From 577c71b930dddcc0ca74dcb4368aa2aea07486da Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Thu, 4 Jan 2024 21:35:25 +0200 Subject: [PATCH 001/787] Fix typos --- libi2pd/Datagram.h | 2 +- libi2pd/NTCP2.cpp | 2 +- libi2pd/RouterInfo.cpp | 2 +- libi2pd/TunnelPool.cpp | 2 +- libi2pd_client/UDPTunnel.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index 8f3d5ceb..e6d1f7b6 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -150,7 +150,7 @@ namespace datagram void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len); void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); - /** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */ + /** find a receiver by port, if none by port is found try default receiver, otherwise returns nullptr */ Receiver FindReceiver(uint16_t port); private: diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 0a23f07e..f1a5e241 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1234,7 +1234,7 @@ namespace transport void NTCP2Session::SendLocalRouterInfo (bool update) { - if (update || !IsOutgoing ()) // we send it in SessionConfirmed for ougoing session + if (update || !IsOutgoing ()) // we send it in SessionConfirmed for outgoing session m_Server.GetService ().post (std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ())); } diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 63cb79ef..60f9a518 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -995,7 +995,7 @@ namespace data bool RouterInfo::IsPublished (bool v4) const { - if (m_Caps & (eUnreachable | eHidden)) return false; // if router sets U or H we assume that all addreses are not published + if (m_Caps & (eUnreachable | eHidden)) return false; // if router sets U or H we assume that all addresses are not published auto addr = GetAddresses (); if (v4) return ((*addr)[eNTCP2V4Idx] && ((*addr)[eNTCP2V4Idx])->published) || diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 23cc53e3..5339c9be 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -301,7 +301,7 @@ namespace tunnel { for (auto it: m_OutboundTunnels) { - // try to create inbound tunnel through the same path as succesive outbound + // try to create inbound tunnel through the same path as successive outbound CreatePairedInboundTunnel (it); num++; if (num >= m_NumInboundTunnels) break; diff --git a/libi2pd_client/UDPTunnel.h b/libi2pd_client/UDPTunnel.h index 862ce216..3233c3f0 100644 --- a/libi2pd_client/UDPTunnel.h +++ b/libi2pd_client/UDPTunnel.h @@ -72,7 +72,7 @@ namespace client boost::asio::ip::udp::endpoint LocalEndpoint; /** client's udp endpoint */ boost::asio::ip::udp::endpoint RemoteEndpoint; - /** how long has this converstation been idle in ms */ + /** how long has this conversation been idle in ms */ uint64_t idle; }; From 8bc58daa5a63a12f88b3fb454ee297e37e1ec48a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 7 Jan 2024 18:42:34 -0500 Subject: [PATCH 002/787] fixed #2004. Check supported crypto --- libi2pd_client/SAM.cpp | 56 +++++++++++++++++++++++++----------------- libi2pd_client/SAM.h | 6 +++-- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index ffdeb5ac..775b9411 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -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 * @@ -550,17 +550,22 @@ namespace client if (!session) session = m_Owner.FindSession(m_ID); if (session) { - m_SocketType = eSAMSocketTypeStream; - m_Stream = session->GetLocalDestination ()->CreateStream (remote); - if (m_Stream) - { - m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send - m_BufferOffset = 0; - I2PReceive (); - SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); + if (session->GetLocalDestination ()->SupportsEncryptionType (remote->GetEncryptionType ())) + { + m_SocketType = eSAMSocketTypeStream; + m_Stream = session->GetLocalDestination ()->CreateStream (remote); + if (m_Stream) + { + m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send + m_BufferOffset = 0; + I2PReceive (); + SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); + } + else + SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); } else - SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); + SendStreamCantReachPeer ("Incompatible crypto"); } else SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); @@ -573,7 +578,7 @@ namespace client else { LogPrint (eLogError, "SAM: Destination to connect not found"); - SendMessageReply (SAM_STREAM_STATUS_CANT_REACH_PEER, strlen(SAM_STREAM_STATUS_CANT_REACH_PEER), true); + SendStreamCantReachPeer ("LeaseSet not found"); } } @@ -857,27 +862,32 @@ namespace client SendSessionI2PError ("Wrong session type"); } + void SAMSocket::SendReplyWithMessage (const char * reply, const std::string & msg) + { +#ifdef _MSC_VER + size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, reply, msg.c_str()); +#else + size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, reply, msg.c_str()); +#endif + SendMessageReply (m_Buffer, len, true); + } + void SAMSocket::SendSessionI2PError(const std::string & msg) { LogPrint (eLogError, "SAM: Session I2P error: ", msg); -#ifdef _MSC_VER - size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_STATUS_I2P_ERROR, msg.c_str()); -#else - size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_STATUS_I2P_ERROR, msg.c_str()); -#endif - SendMessageReply (m_Buffer, len, true); + SendReplyWithMessage (SAM_SESSION_STATUS_I2P_ERROR, msg); } void SAMSocket::SendStreamI2PError(const std::string & msg) { LogPrint (eLogError, "SAM: Stream I2P error: ", msg); -#ifdef _MSC_VER - size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_STREAM_STATUS_I2P_ERROR, msg.c_str()); -#else - size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_STREAM_STATUS_I2P_ERROR, msg.c_str()); -#endif - SendMessageReply (m_Buffer, len, true); + SendReplyWithMessage (SAM_STREAM_STATUS_I2P_ERROR, msg); } + + void SAMSocket::SendStreamCantReachPeer(const std::string & msg) + { + SendReplyWithMessage (SAM_STREAM_STATUS_CANT_REACH_PEER, msg); + } void SAMSocket::HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr leaseSet, std::string name) { diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 34af5a62..3ed8f00c 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -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 * @@ -51,7 +51,7 @@ namespace client const char SAM_STREAM_STATUS_OK[] = "STREAM STATUS RESULT=OK\n"; const char SAM_STREAM_STATUS_INVALID_ID[] = "STREAM STATUS RESULT=INVALID_ID\n"; const char SAM_STREAM_STATUS_INVALID_KEY[] = "STREAM STATUS RESULT=INVALID_KEY\n"; - const char SAM_STREAM_STATUS_CANT_REACH_PEER[] = "STREAM STATUS RESULT=CANT_REACH_PEER\n"; + const char SAM_STREAM_STATUS_CANT_REACH_PEER[] = "STREAM STATUS RESULT=CANT_REACH_PEER MESSAGE=\"%s\"\n"; const char SAM_STREAM_STATUS_I2P_ERROR[] = "STREAM STATUS RESULT=I2P_ERROR MESSAGE=\"%s\"\n"; const char SAM_STREAM_ACCEPT[] = "STREAM ACCEPT"; const char SAM_STREAM_FORWARD[] = "STREAM FORWARD"; @@ -144,8 +144,10 @@ namespace client void ProcessNamingLookup (char * buf, size_t len); void ProcessSessionAdd (char * buf, size_t len); void ProcessSessionRemove (char * buf, size_t len); + void SendReplyWithMessage (const char * reply, const std::string & msg); void SendSessionI2PError(const std::string & msg); void SendStreamI2PError(const std::string & msg); + void SendStreamCantReachPeer(const std::string & msg); size_t ProcessDatagramSend (char * buf, size_t len, const char * data); // from SAM 1.0 void ExtractParams (char * buf, std::map& params); From 1e9bcd6b8b228aeed713f1d1714809409e97633a Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 8 Jan 2024 16:36:14 +0300 Subject: [PATCH 003/787] [gha] MSVC: Switch to direct Boost and OpenSSL installation --- .github/workflows/build-windows-msvc.yml | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-windows-msvc.yml b/.github/workflows/build-windows-msvc.yml index 172e0596..a077d626 100644 --- a/.github/workflows/build-windows-msvc.yml +++ b/.github/workflows/build-windows-msvc.yml @@ -26,15 +26,27 @@ jobs: ./install_zlib.bat del install_zlib.bat + #- name: Install Boost + # uses: crazy-max/ghaction-chocolatey@v2 + # with: + # args: install boost-msvc-14.3 --version=1.81.0 + + #- name: Install OpenSSL + # uses: crazy-max/ghaction-chocolatey@v2 + # with: + # args: install openssl + - name: Install Boost - uses: crazy-max/ghaction-chocolatey@v2 - with: - args: install boost-msvc-14.3 --version=1.81.0 + run: | + powershell -Command "(Invoke-WebRequest -UserAgent "Wget" -Uri https://sourceforge.net/projects/boost/files/boost-binaries/1.84.0/boost_1_84_0-msvc-14.3-64.exe/download -OutFile boost_1_84_0-msvc-14.3-64.exe)" + ./boost_1_84_0-msvc-14.3-64.exe /VERYSILENT + del boost_1_84_0-msvc-14.3-64.exe - name: Install OpenSSL - uses: crazy-max/ghaction-chocolatey@v2 - with: - args: install openssl + run: | + powershell -Command "(Invoke-WebRequest -UserAgent "Wget" -Uri https://slproweb.com/download/Win64OpenSSL-3_2_0.exe -OutFile Win64OpenSSL-3_2_0.exe)" + ./Win64OpenSSL-3_2_0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- + del Win64OpenSSL-3_2_0.exe - name: Configure working-directory: build From dfe8b25e5ec2d0533584bf03cf0d1289bc1ca71d Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 8 Jan 2024 17:05:36 +0300 Subject: [PATCH 004/787] [gha] MSVC: remove deletion of installation files --- .github/workflows/build-windows-msvc.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/build-windows-msvc.yml b/.github/workflows/build-windows-msvc.yml index a077d626..5af526e2 100644 --- a/.github/workflows/build-windows-msvc.yml +++ b/.github/workflows/build-windows-msvc.yml @@ -40,13 +40,11 @@ jobs: run: | powershell -Command "(Invoke-WebRequest -UserAgent "Wget" -Uri https://sourceforge.net/projects/boost/files/boost-binaries/1.84.0/boost_1_84_0-msvc-14.3-64.exe/download -OutFile boost_1_84_0-msvc-14.3-64.exe)" ./boost_1_84_0-msvc-14.3-64.exe /VERYSILENT - del boost_1_84_0-msvc-14.3-64.exe - name: Install OpenSSL run: | powershell -Command "(Invoke-WebRequest -UserAgent "Wget" -Uri https://slproweb.com/download/Win64OpenSSL-3_2_0.exe -OutFile Win64OpenSSL-3_2_0.exe)" ./Win64OpenSSL-3_2_0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- - del Win64OpenSSL-3_2_0.exe - name: Configure working-directory: build From cd087568b55161767c6094f86054d4976e137209 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 9 Jan 2024 21:02:11 -0500 Subject: [PATCH 005/787] reply with CANT_REACH_PEER if connect to outselves --- libi2pd_client/SAM.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 775b9411..1a3afb58 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -523,15 +523,20 @@ namespace client { if (addr->IsIdentHash ()) { - auto leaseSet = session->GetLocalDestination ()->FindLeaseSet(addr->identHash); - if (leaseSet) - Connect(leaseSet, session); - else - { - session->GetLocalDestination ()->RequestDestination(addr->identHash, - std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete, - shared_from_this(), std::placeholders::_1)); + if (session->GetLocalDestination ()->GetIdentHash () != addr->identHash) + { + auto leaseSet = session->GetLocalDestination ()->FindLeaseSet(addr->identHash); + if (leaseSet) + Connect(leaseSet, session); + else + { + session->GetLocalDestination ()->RequestDestination(addr->identHash, + std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete, + shared_from_this(), std::placeholders::_1)); + } } + else + SendStreamCantReachPeer ("Can't connect to myself"); } else // B33 session->GetLocalDestination ()->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey, From 2ad26dd4c9def4cf05e144f65793323187a2b830 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 11 Jan 2024 14:09:08 -0500 Subject: [PATCH 006/787] fixed race condition in ECIESx25519 tags table --- libi2pd/RouterContext.cpp | 22 +++++++++++++++++++++- libi2pd/RouterContext.h | 1 + libi2pd/Tunnel.cpp | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index f21c0592..10d33bf5 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -1199,7 +1199,27 @@ namespace i2p else i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg); } - + + void RouterContext::SubmitECIESx25519Key (const uint8_t * key, uint64_t tag) + { + if (m_Service) + { + struct + { + uint8_t k[32]; + uint64_t t; + } data; + memcpy (data.k, key, 32); + data.t = tag; + m_Service->GetService ().post ([this,data](void) + { + AddECIESx25519Key (data.k, data.t); + }); + } + else + LogPrint (eLogError, "Router: service is NULL"); + } + void RouterContext::CleanupDestination () { if (m_Service) diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index d49b5523..91a553ba 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -136,6 +136,7 @@ namespace garlic void SetNetID (int netID) { m_NetID = netID; }; bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data); bool DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data); + void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag); void UpdatePort (int port); // called from Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU2 or Daemon diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 6234ceb4..b8e17920 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -116,7 +116,7 @@ namespace tunnel if (m_Pool && m_Pool->GetLocalDestination ()) m_Pool->GetLocalDestination ()->SubmitECIESx25519Key (key, tag); else - i2p::context.AddECIESx25519Key (key, tag); + i2p::context.SubmitECIESx25519Key (key, tag); } i2p::transport::transports.SendMessage (GetNextIdentHash (), msg); } From ca9782dd0d4ad8116035352f22524b4f3ee77633 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 11 Jan 2024 15:39:42 -0500 Subject: [PATCH 007/787] handle 'reservedrange' param properly --- daemon/Daemon.cpp | 4 +--- libi2pd/NTCP2.cpp | 4 ++-- libi2pd/Reseed.cpp | 24 +++++++++++------------- libi2pd/RouterInfo.cpp | 5 +++-- libi2pd/SSU2.cpp | 8 ++++---- libi2pd/SSU2Session.cpp | 4 ++-- libi2pd/Transports.cpp | 13 ++++++++++--- libi2pd/Transports.h | 5 +++-- 8 files changed, 36 insertions(+), 31 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index f04236fe..308daa4c 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -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 * @@ -298,12 +298,10 @@ namespace util bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); - bool checkInReserved; i2p::config::GetOption("reservedrange", checkInReserved); LogPrint(eLogInfo, "Daemon: Starting Transports"); if(!ssu2) LogPrint(eLogInfo, "Daemon: SSU2 disabled"); if(!ntcp2) LogPrint(eLogInfo, "Daemon: NTCP2 disabled"); - i2p::transport::transports.SetCheckReserved(checkInReserved); i2p::transport::transports.Start(ntcp2, ssu2); if (i2p::transport::transports.IsBoundSSU2() || i2p::transport::transports.IsBoundNTCP2()) LogPrint(eLogInfo, "Daemon: Transports started"); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f1a5e241..efc317c2 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1490,7 +1490,7 @@ namespace transport if (!ec) { LogPrint (eLogDebug, "NTCP2: Connected from ", ep); - if (!i2p::util::net::IsInReservedRange(ep.address ())) + if (!i2p::transport::transports.IsInReservedRange(ep.address ())) { if (m_PendingIncomingSessions.emplace (ep.address (), conn).second) { @@ -1537,7 +1537,7 @@ namespace transport if (!ec) { LogPrint (eLogDebug, "NTCP2: Connected from ", ep); - if (!i2p::util::net::IsInReservedRange(ep.address ()) || + if (!i2p::transport::transports.IsInReservedRange(ep.address ()) || i2p::util::net::IsYggdrasilAddress (ep.address ())) { if (m_PendingIncomingSessions.emplace (ep.address (), conn).second) diff --git a/libi2pd/Reseed.cpp b/libi2pd/Reseed.cpp index 28e4db24..5fdc2fae 100644 --- a/libi2pd/Reseed.cpp +++ b/libi2pd/Reseed.cpp @@ -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 * @@ -687,18 +687,16 @@ namespace data while (it != end) { boost::asio::ip::tcp::endpoint ep = *it; - if ( - ( - !i2p::util::net::IsInReservedRange(ep.address ()) && ( - (ep.address ().is_v4 () && i2p::context.SupportsV4 ()) || - (ep.address ().is_v6 () && i2p::context.SupportsV6 ()) - ) - ) || - ( - i2p::util::net::IsYggdrasilAddress (ep.address ()) && - i2p::context.SupportsMesh () - ) - ) + bool supported = false; + if (!ep.address ().is_unspecified ()) + { + if (ep.address ().is_v4 ()) + supported = i2p::context.SupportsV4 (); + else if (ep.address ().is_v6 ()) + supported = i2p::util::net::IsYggdrasilAddress (ep.address ()) ? + i2p::context.SupportsMesh () : i2p::context.SupportsV6 (); + } + if (supported) { s.lowest_layer().connect (ep, ecode); if (!ecode) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 60f9a518..7cde7c33 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -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 * @@ -21,6 +21,7 @@ #include "Base.h" #include "Timestamp.h" #include "Log.h" +#include "Transports.h" #include "NetDb.hpp" #include "RouterContext.h" #include "RouterInfo.h" @@ -253,7 +254,7 @@ namespace data address->host = boost::asio::ip::address::from_string (value, ecode); if (!ecode && !address->host.is_unspecified ()) { - if (!i2p::util::net::IsInReservedRange (address->host) || + if (!i2p::transport::transports.IsInReservedRange (address->host) || i2p::util::net::IsYggdrasilAddress (address->host)) isHost = true; else diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 6a8615d5..1503b404 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022-2023, The PurpleI2P Project +* Copyright (c) 2022-2024, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -566,7 +566,7 @@ namespace transport else it1->second->ProcessRetry (buf, len); } - else if (!i2p::util::net::IsInReservedRange(senderEndpoint.address ()) && senderEndpoint.port ()) + else if (!i2p::transport::transports.IsInReservedRange(senderEndpoint.address ()) && senderEndpoint.port ()) { // assume new incoming session auto session = std::make_shared (*this); @@ -666,7 +666,7 @@ namespace transport bool isValidEndpoint = !address->host.is_unspecified () && address->port; if (isValidEndpoint) { - if (i2p::util::net::IsInReservedRange(address->host)) return false; + if (i2p::transport::transports.IsInReservedRange(address->host)) return false; auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (address->host, address->port)); if (s) { @@ -753,7 +753,7 @@ namespace transport if (addr) { bool isValidEndpoint = !addr->host.is_unspecified () && addr->port && - !i2p::util::net::IsInReservedRange(addr->host); + !i2p::transport::transports.IsInReservedRange(addr->host); if (isValidEndpoint) { auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (addr->host, addr->port)); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index e5261622..8cb39102 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1471,7 +1471,7 @@ namespace transport ResendHandshakePacket (); // assume we receive return; } - if (from != m_RemoteEndpoint && !i2p::util::net::IsInReservedRange (from.address ())) + if (from != m_RemoteEndpoint && !i2p::transport::transports.IsInReservedRange (from.address ())) { LogPrint (eLogInfo, "SSU2: Remote endpoint update ", m_RemoteEndpoint, "->", from); m_RemoteEndpoint = from; @@ -1753,7 +1753,7 @@ namespace transport if (ExtractEndpoint (buf, len, ep)) { LogPrint (eLogInfo, "SSU2: Our external address is ", ep); - if (!i2p::util::net::IsInReservedRange (ep.address ())) + if (!i2p::transport::transports.IsInReservedRange (ep.address ())) { i2p::context.UpdateAddress (ep.address ()); // check our port diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index b6e2e261..318d410f 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -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 * @@ -505,7 +505,7 @@ namespace transport if (!m_NTCP2Server) continue; std::shared_ptr address = (tr == i2p::data::RouterInfo::eNTCP2V6) ? peer.router->GetPublishedNTCP2V6Address () : peer.router->GetPublishedNTCP2V4Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) + if (address && IsInReservedRange(address->host)) address = nullptr; if (address) { @@ -524,7 +524,7 @@ namespace transport if (!m_SSU2Server) continue; std::shared_ptr address = (tr == i2p::data::RouterInfo::eSSU2V6) ? peer.router->GetSSU2V6Address () : peer.router->GetSSU2V4Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) + if (address && IsInReservedRange(address->host)) address = nullptr; if (address && address->IsReachableSSU ()) { @@ -1084,6 +1084,11 @@ namespace transport } } + bool Transports::IsInReservedRange (const boost::asio::ip::address& host) const + { + return IsCheckReserved () && i2p::util::net::IsInReservedRange (host); + } + void InitAddressFromIface () { bool ipv6; i2p::config::GetOption("ipv6", ipv6); @@ -1196,6 +1201,8 @@ namespace transport i2p::context.PublishSSU2Address (ssu2port, false, ipv4, ipv6); // unpublish } + bool checkReserved; i2p::config::GetOption("reservedrange", checkReserved); + transports.SetCheckReserved (checkReserved); } } } diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index cb63ca91..7ef7f9b2 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -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 * @@ -167,7 +167,8 @@ namespace transport void PeerTest (bool ipv4 = true, bool ipv6 = true); void SetCheckReserved (bool check) { m_CheckReserved = check; }; - bool IsCheckReserved () { return m_CheckReserved; }; + bool IsCheckReserved () const { return m_CheckReserved; }; + bool IsInReservedRange (const boost::asio::ip::address& host) const; private: From 34d75b08ddac5a3655dab2f89793528562af30d2 Mon Sep 17 00:00:00 2001 From: Vort Date: Fri, 12 Jan 2024 17:13:07 +0200 Subject: [PATCH 008/787] handle 'reservedrange' param properly --- daemon/Daemon.cpp | 4 ++++ libi2pd/Transports.cpp | 3 --- libi2pd/api.cpp | 5 ++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 308daa4c..17d17f72 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -160,6 +160,10 @@ namespace util int netID; i2p::config::GetOption("netid", netID); i2p::context.SetNetID (netID); + + bool checkReserved; i2p::config::GetOption("reservedrange", checkReserved); + i2p::transport::transports.SetCheckReserved(checkReserved); + i2p::context.Init (); i2p::transport::InitTransports (); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 318d410f..0bd17104 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -1200,9 +1200,6 @@ namespace transport else i2p::context.PublishSSU2Address (ssu2port, false, ipv4, ipv6); // unpublish } - - bool checkReserved; i2p::config::GetOption("reservedrange", checkReserved); - transports.SetCheckReserved (checkReserved); } } } diff --git a/libi2pd/api.cpp b/libi2pd/api.cpp index ad24519f..05f962f3 100644 --- a/libi2pd/api.cpp +++ b/libi2pd/api.cpp @@ -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 * @@ -44,6 +44,9 @@ namespace api int netID; i2p::config::GetOption("netid", netID); i2p::context.SetNetID (netID); + bool checkReserved; i2p::config::GetOption("reservedrange", checkReserved); + i2p::transport::transports.SetCheckReserved(checkReserved); + i2p::context.Init (); } From d8f6c4a93dc1722463754eb5c1670a4bab2f2304 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 14 Jan 2024 17:16:31 -0500 Subject: [PATCH 009/787] correct encryption and path for follow on lookup request --- libi2pd/NetDb.cpp | 42 +++-------------- libi2pd/NetDbRequests.cpp | 94 +++++++++++++++++++++++++-------------- libi2pd/NetDbRequests.h | 24 ++++++---- 3 files changed, 83 insertions(+), 77 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 6e023c45..8eb5d653 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -721,7 +721,7 @@ namespace data void NetDb::RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete, bool direct) { - auto dest = m_Requests.CreateRequest (destination, false, requestComplete); // non-exploratory + auto dest = m_Requests.CreateRequest (destination, false, direct, requestComplete); // non-exploratory if (!dest) { LogPrint (eLogWarning, "NetDb: Destination ", destination.ToBase64(), " is requested already"); @@ -761,10 +761,10 @@ namespace data } } - void NetDb::RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete) + void NetDb::RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploratory, RequestedDestination::RequestComplete requestComplete) { - auto dest = m_Requests.CreateRequest (destination, exploritory, requestComplete); // non-exploratory + auto dest = m_Requests.CreateRequest (destination, exploratory, true, requestComplete); // non-exploratory if (!dest) { LogPrint (eLogWarning, "NetDb: Destination ", destination.ToBase64(), " is requested already"); @@ -919,39 +919,9 @@ namespace data auto dest = m_Requests.FindRequest (ident); if (dest) { - bool deleteDest = true; if (num > 0) - { - auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); - auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr; - auto inbound = pool ? pool->GetNextInboundTunnel () : nullptr; - if (!dest->IsExploratory ()) - { - // reply to our destination. Try other floodfills - if (outbound && inbound) - { - auto count = dest->GetExcludedPeers ().size (); - if (count < 7) - { - auto nextFloodfill = GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ()); - if (nextFloodfill) - { - // request destination - LogPrint (eLogDebug, "NetDb: Try ", key, " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ()); - outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0, - dest->CreateRequestMessage (nextFloodfill, inbound)); - deleteDest = false; - } - } - else - LogPrint (eLogWarning, "NetDb: ", key, " was not found on ", count, " floodfills"); - } - } - - if (deleteDest) - // no more requests for the destinationation. delete it - m_Requests.RequestComplete (ident, nullptr); - } + // try to send next requests + m_Requests.SendNextRequest (dest); else // no more requests for destination possible. delete it m_Requests.RequestComplete (ident, nullptr); @@ -1156,7 +1126,7 @@ namespace data for (int i = 0; i < numDestinations; i++) { RAND_bytes (randomHash, 32); - auto dest = m_Requests.CreateRequest (randomHash, true); // exploratory + auto dest = m_Requests.CreateRequest (randomHash, true, !throughTunnels); // exploratory if (!dest) { LogPrint (eLogWarning, "NetDb: Exploratory destination is requested already"); diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index 4011b8aa..2cb578e2 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -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 * @@ -11,6 +11,7 @@ #include "Transports.h" #include "NetDb.hpp" #include "NetDbRequests.h" +#include "ECIESX25519AEADRatchetSession.h" namespace i2p { @@ -74,14 +75,15 @@ namespace data } - std::shared_ptr NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete) + std::shared_ptr NetDbRequests::CreateRequest (const IdentHash& destination, + bool isExploratory, bool direct, RequestedDestination::RequestComplete requestComplete) { // request RouterInfo directly - auto dest = std::make_shared (destination, isExploratory); + auto dest = std::make_shared (destination, isExploratory, direct); dest->SetRequestComplete (requestComplete); { - std::unique_lock l(m_RequestedDestinationsMutex); - if (!m_RequestedDestinations.insert (std::make_pair (destination, dest)).second) // not inserted + std::unique_lock l(m_RequestedDestinationsMutex); + if (!m_RequestedDestinations.emplace (destination, dest).second) // not inserted return nullptr; } return dest; @@ -125,35 +127,10 @@ namespace data { auto& dest = it->second; bool done = false; - if (ts < dest->GetCreationTime () + 60) // request is worthless after 1 minute + if (ts < dest->GetCreationTime () + MAX_REQUEST_TIME) // request becomes worthless { - if (ts > dest->GetCreationTime () + 5) // no response for 5 seconds - { - auto count = dest->GetExcludedPeers ().size (); - if (!dest->IsExploratory () && count < 7) - { - auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); - auto outbound = pool->GetNextOutboundTunnel (); - auto inbound = pool->GetNextInboundTunnel (); - auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ()); - if (nextFloodfill && outbound && inbound) - outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0, - dest->CreateRequestMessage (nextFloodfill, inbound)); - else - { - done = true; - if (!inbound) LogPrint (eLogWarning, "NetDbReq: No inbound tunnels"); - if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels"); - if (!nextFloodfill) LogPrint (eLogWarning, "NetDbReq: No more floodfills"); - } - } - else - { - if (!dest->IsExploratory ()) - LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts"); - done = true; - } - } + if (ts > dest->GetCreationTime () + MIN_REQUEST_TIME) // retry in no response after min interval + done = !SendNextRequest (dest); } else // delete obsolete request done = true; @@ -164,5 +141,56 @@ namespace data ++it; } } + + bool NetDbRequests::SendNextRequest (std::shared_ptr dest) + { + if (!dest) return false; + bool ret = true; + auto count = dest->GetExcludedPeers ().size (); + if (!dest->IsExploratory () && count < MAX_NUM_REQUEST_ATTEMPTS) + { + auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ()); + if (nextFloodfill) + { + bool direct = dest->IsDirect (); + if (direct && !nextFloodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) && + !i2p::transport::transports.IsConnected (nextFloodfill->GetIdentHash ())) + direct = false; // floodfill can't be reached directly + if (direct) + i2p::transport::transports.SendMessage (nextFloodfill->GetIdentHash (), dest->CreateRequestMessage (nextFloodfill->GetIdentHash ())); + else + { + auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); + auto outbound = pool->GetNextOutboundTunnel (); + auto inbound = pool->GetNextInboundTunnel (); + if (nextFloodfill && outbound && inbound) + { + LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ()); + auto msg = dest->CreateRequestMessage (nextFloodfill, inbound); + outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0, + i2p::garlic::WrapECIESX25519MessageForRouter (msg, nextFloodfill->GetIdentity ()->GetEncryptionPublicKey ())); + } + else + { + ret = false; + if (!inbound) LogPrint (eLogWarning, "NetDbReq: No inbound tunnels"); + if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels"); + } + } + } + else + { + ret = false; + if (!nextFloodfill) LogPrint (eLogWarning, "NetDbReq: No more floodfills"); + } + } + else + { + if (!dest->IsExploratory ()) + LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts"); + ret = false; + } + return ret; + } } } diff --git a/libi2pd/NetDbRequests.h b/libi2pd/NetDbRequests.h index cf2f0915..a4d1cf21 100644 --- a/libi2pd/NetDbRequests.h +++ b/libi2pd/NetDbRequests.h @@ -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 * @@ -9,9 +9,10 @@ #ifndef NETDB_REQUESTS_H__ #define NETDB_REQUESTS_H__ +#include #include #include -#include +#include #include "Identity.h" #include "RouterInfo.h" @@ -19,14 +20,18 @@ namespace i2p { namespace data { + const size_t MAX_NUM_REQUEST_ATTEMPTS = 7; + const uint64_t MIN_REQUEST_TIME = 5; // in seconds + const uint64_t MAX_REQUEST_TIME = 60; // in seconds + class RequestedDestination { public: typedef std::function)> RequestComplete; - RequestedDestination (const IdentHash& destination, bool isExploratory = false): - m_Destination (destination), m_IsExploratory (isExploratory), m_CreationTime (0) {}; + RequestedDestination (const IdentHash& destination, bool isExploratory = false, bool direct = true): + m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), m_CreationTime (0) {}; ~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); }; const IdentHash& GetDestination () const { return m_Destination; }; @@ -34,6 +39,7 @@ namespace data const std::set& GetExcludedPeers () { return m_ExcludedPeers; }; void ClearExcludedPeers (); bool IsExploratory () const { return m_IsExploratory; }; + bool IsDirect () const { return m_IsDirect; }; bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); }; uint64_t GetCreationTime () const { return m_CreationTime; }; std::shared_ptr CreateRequestMessage (std::shared_ptr, std::shared_ptr replyTunnel); @@ -47,7 +53,7 @@ namespace data private: IdentHash m_Destination; - bool m_IsExploratory; + bool m_IsExploratory, m_IsDirect; std::set m_ExcludedPeers; uint64_t m_CreationTime; RequestComplete m_RequestComplete; @@ -60,15 +66,17 @@ namespace data void Start (); void Stop (); - std::shared_ptr CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete = nullptr); + std::shared_ptr CreateRequest (const IdentHash& destination, bool isExploratory, + bool direct = false, RequestedDestination::RequestComplete requestComplete = nullptr); void RequestComplete (const IdentHash& ident, std::shared_ptr r); std::shared_ptr FindRequest (const IdentHash& ident) const; void ManageRequests (); - + bool SendNextRequest (std::shared_ptr dest); + private: mutable std::mutex m_RequestedDestinationsMutex; - std::map > m_RequestedDestinations; + std::unordered_map > m_RequestedDestinations; }; } } From 4afdca090d33ba2d2bb390e46637ba42aa42fc5d Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 14 Jan 2024 18:54:21 -0500 Subject: [PATCH 010/787] support multiple RouterInfo request callbacks --- libi2pd/NetDbRequests.cpp | 20 +++++++++++++++++++- libi2pd/NetDbRequests.h | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index 2cb578e2..167095d7 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -83,8 +83,26 @@ namespace data dest->SetRequestComplete (requestComplete); { std::unique_lock l(m_RequestedDestinationsMutex); - if (!m_RequestedDestinations.emplace (destination, dest).second) // not inserted + auto ret = m_RequestedDestinations.emplace (destination, dest); + if (!ret.second) // not inserted + { + dest->SetRequestComplete (nullptr); // don't call requestComplete in destructor + if (requestComplete) + { + auto prev = ret.first->second->GetRequestComplete (); + if (prev) // if already set + ret.first->second->SetRequestComplete ( + [requestComplete, prev](std::shared_ptr r) + { + prev (r); // call previous + requestComplete (r); // then new + }); + else + ret.first->second->SetRequestComplete (requestComplete); + } + return nullptr; + } } return dest; } diff --git a/libi2pd/NetDbRequests.h b/libi2pd/NetDbRequests.h index a4d1cf21..001b0f07 100644 --- a/libi2pd/NetDbRequests.h +++ b/libi2pd/NetDbRequests.h @@ -46,6 +46,7 @@ namespace data std::shared_ptr CreateRequestMessage (const IdentHash& floodfill); void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; }; + RequestComplete GetRequestComplete () const { return m_RequestComplete; }; bool IsRequestComplete () const { return m_RequestComplete != nullptr; }; void Success (std::shared_ptr r); void Fail (); From 49f4dc53adf1c3d464f4d9baaae3c49dfe6ae8af Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 15 Jan 2024 19:32:17 -0500 Subject: [PATCH 011/787] try next floodfill for router request on demand --- libi2pd/NetDbRequests.cpp | 21 +++++++++++++++++---- libi2pd/NetDbRequests.h | 8 ++++---- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index 167095d7..92e5a7b8 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -17,6 +17,17 @@ namespace i2p { namespace data { + RequestedDestination::RequestedDestination (const IdentHash& destination, bool isExploratory, bool direct): + m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), + m_CreationTime (i2p::util::GetSecondsSinceEpoch ()), m_LastRequestTime (0) + { + } + + RequestedDestination::~RequestedDestination () + { + if (m_RequestComplete) m_RequestComplete (nullptr); + } + std::shared_ptr RequestedDestination::CreateRequestMessage (std::shared_ptr router, std::shared_ptr replyTunnel) { @@ -29,7 +40,7 @@ namespace data msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers); if(router) m_ExcludedPeers.insert (router->GetIdentHash ()); - m_CreationTime = i2p::util::GetSecondsSinceEpoch (); + m_LastRequestTime = i2p::util::GetSecondsSinceEpoch (); return msg; } @@ -38,7 +49,7 @@ namespace data auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers); m_ExcludedPeers.insert (floodfill); - m_CreationTime = i2p::util::GetSecondsSinceEpoch (); + m_LastRequestTime = i2p::util::GetSecondsSinceEpoch (); return msg; } @@ -100,7 +111,9 @@ namespace data else ret.first->second->SetRequestComplete (requestComplete); } - + if (i2p::util::GetSecondsSinceEpoch () > ret.first->second->GetLastRequestTime () + MIN_REQUEST_TIME) + if (!SendNextRequest (ret.first->second)) // try next floodfill + m_RequestedDestinations.erase (ret.first); // delete request if failed return nullptr; } } @@ -147,7 +160,7 @@ namespace data bool done = false; if (ts < dest->GetCreationTime () + MAX_REQUEST_TIME) // request becomes worthless { - if (ts > dest->GetCreationTime () + MIN_REQUEST_TIME) // retry in no response after min interval + if (ts > dest->GetLastRequestTime () + MIN_REQUEST_TIME) // try next floodfill if no response after min interval done = !SendNextRequest (dest); } else // delete obsolete request diff --git a/libi2pd/NetDbRequests.h b/libi2pd/NetDbRequests.h index 001b0f07..47a5d481 100644 --- a/libi2pd/NetDbRequests.h +++ b/libi2pd/NetDbRequests.h @@ -30,9 +30,8 @@ namespace data typedef std::function)> RequestComplete; - RequestedDestination (const IdentHash& destination, bool isExploratory = false, bool direct = true): - m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), m_CreationTime (0) {}; - ~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); }; + RequestedDestination (const IdentHash& destination, bool isExploratory = false, bool direct = true); + ~RequestedDestination (); const IdentHash& GetDestination () const { return m_Destination; }; int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); }; @@ -42,6 +41,7 @@ namespace data bool IsDirect () const { return m_IsDirect; }; bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); }; uint64_t GetCreationTime () const { return m_CreationTime; }; + uint64_t GetLastRequestTime () const { return m_LastRequestTime; }; std::shared_ptr CreateRequestMessage (std::shared_ptr, std::shared_ptr replyTunnel); std::shared_ptr CreateRequestMessage (const IdentHash& floodfill); @@ -56,7 +56,7 @@ namespace data IdentHash m_Destination; bool m_IsExploratory, m_IsDirect; std::set m_ExcludedPeers; - uint64_t m_CreationTime; + uint64_t m_CreationTime, m_LastRequestTime; // in seconds RequestComplete m_RequestComplete; }; From 7cfcb12c7b0f3e9c3f6408c404b22e0a3e3e53bf Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 16 Jan 2024 14:33:36 -0500 Subject: [PATCH 012/787] don't create peer for unreachable router --- libi2pd/Transports.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 0bd17104..eb836354 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -436,6 +436,10 @@ namespace transport auto it = m_Peers.find (ident); if (it == m_Peers.end ()) { + // check if not known as unreachable + auto profile = i2p::data::GetRouterProfile (ident); + if (profile && profile->IsUnreachable ()) return; // don't create peer to unreachable router + // try to connect bool connected = false; try { From 39e378a03dda77cb380182c1c0c192478caa44e9 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 17 Jan 2024 18:15:49 -0500 Subject: [PATCH 013/787] check received data size --- libi2pd/NTCP2.cpp | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index efc317c2..c52c5cc2 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -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 * @@ -809,10 +809,15 @@ namespace transport void NTCP2Session::HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - if (ecode) + if (ecode || bytes_transferred != 2) { if (ecode != boost::asio::error::operation_aborted) - LogPrint (eLogWarning, "NTCP2: Receive length read error: ", ecode.message ()); + { + if (ecode) + LogPrint (eLogWarning, "NTCP2: Receive length read error: ", ecode.message ()); + else if (bytes_transferred != 2) + LogPrint (eLogError, "NTCP2: Receive length of ", bytes_transferred, " bytes"); + } Terminate (); } else @@ -833,14 +838,19 @@ namespace transport CreateNextReceivedBuffer (m_NextReceivedLen); boost::system::error_code ec; size_t moreBytes = m_Socket.available(ec); - if (!ec && moreBytes >= m_NextReceivedLen) - { - // read and process message immediately if available - moreBytes = boost::asio::read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), ec); - HandleReceived (ec, moreBytes); - } + if (!ec) + { + if (moreBytes >= m_NextReceivedLen) + { + // read and process message immediately if available + moreBytes = boost::asio::read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), ec); + HandleReceived (ec, moreBytes); + } + else + Receive (); + } else - Receive (); + LogPrint (eLogWarning, "NTCP2: Socket error: ", ec.message ()); } else { @@ -864,10 +874,15 @@ namespace transport void NTCP2Session::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - if (ecode) + if (ecode || bytes_transferred != m_NextReceivedLen) { - if (ecode != boost::asio::error::operation_aborted) - LogPrint (eLogWarning, "NTCP2: Receive read error: ", ecode.message ()); + if (ecode != boost::asio::error::operation_aborted) + { + if (ecode) + LogPrint (eLogWarning, "NTCP2: Receive read error: ", ecode.message ()); + else if (bytes_transferred != m_NextReceivedLen) + LogPrint (eLogError, "NTCP2: Received ", bytes_transferred, " bytes. Instead ", m_NextReceivedLen); + } Terminate (); } else From 1e5604ed4373dcea18a8353df188451d592bd864 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 18 Jan 2024 19:18:51 -0500 Subject: [PATCH 014/787] check if peer is connected before trying to connect --- libi2pd/Transports.cpp | 15 ++++++++------- libi2pd/Transports.h | 2 ++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index eb836354..5d3027a9 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -458,7 +458,7 @@ namespace transport } if (!connected) return; } - if (!it->second.sessions.empty ()) + if (it->second.IsConnected ()) it->second.sessions.front ()->SendI2NPMessages (msgs); else { @@ -616,7 +616,8 @@ namespace transport { LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect"); it->second.SetRouter (r); - ConnectToPeer (ident, it->second); + if (!it->second.IsConnected ()) + ConnectToPeer (ident, it->second); } else { @@ -810,13 +811,13 @@ namespace transport auto it = m_Peers.find (ident); if (it != m_Peers.end ()) { - auto before = it->second.sessions.size (); + bool wasConnected = it->second.IsConnected (); it->second.sessions.remove (session); - if (it->second.sessions.empty ()) + if (!it->second.IsConnected ()) { if (it->second.delayedMessages.size () > 0) { - if (before > 0) // we had an active session before + if (wasConnected) // we had an active session before it->second.numAttempts = 0; // start over ConnectToPeer (ident, it->second); } @@ -849,7 +850,7 @@ namespace transport { return !session || !session->IsEstablished (); }); - if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT) + if (!it->second.IsConnected () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT) { LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds"); /* if (!it->second.router) @@ -991,7 +992,7 @@ namespace transport [isHighBandwidth](const Peer& peer)->bool { // connected, not overloaded and not slow - return !peer.router && !peer.sessions.empty () && peer.isReachable && + return !peer.router && peer.IsConnected () && peer.isReachable && peer.sessions.front ()->GetSendQueueSize () <= PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE && !peer.sessions.front ()->IsSlow () && !peer.sessions.front ()->IsBandwidthExceeded (peer.isHighBandwidth) && (!isHighBandwidth || peer.isHighBandwidth); diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 7ef7f9b2..0e5518b1 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -101,6 +101,8 @@ namespace transport isReachable = (bool)router->GetCompatibleTransports (true); } } + + bool IsConnected () const { return !sessions.empty (); } }; const uint64_t SESSION_CREATION_TIMEOUT = 15; // in seconds From b4484c8e8f7615b6beeab872515c3f9ff1dc3bc9 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 19 Jan 2024 21:54:10 +0300 Subject: [PATCH 015/787] [gha] msvc: switch back to boost 1.81.0 --- .github/workflows/build-windows-msvc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-windows-msvc.yml b/.github/workflows/build-windows-msvc.yml index 5af526e2..dea64644 100644 --- a/.github/workflows/build-windows-msvc.yml +++ b/.github/workflows/build-windows-msvc.yml @@ -38,7 +38,7 @@ jobs: - name: Install Boost run: | - powershell -Command "(Invoke-WebRequest -UserAgent "Wget" -Uri https://sourceforge.net/projects/boost/files/boost-binaries/1.84.0/boost_1_84_0-msvc-14.3-64.exe/download -OutFile boost_1_84_0-msvc-14.3-64.exe)" + powershell -Command "(Invoke-WebRequest -UserAgent "Wget" -Uri https://sourceforge.net/projects/boost/files/boost-binaries/1.81.0/boost_1_81_0-msvc-14.3-64.exe/download -OutFile boost_1_84_0-msvc-14.3-64.exe)" ./boost_1_84_0-msvc-14.3-64.exe /VERYSILENT - name: Install OpenSSL From 140146e433a83eb9137d668baedc13282a5a03c0 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 19 Jan 2024 14:09:48 -0500 Subject: [PATCH 016/787] limit mininal received packet size to 40 bytes --- libi2pd/SSU2.cpp | 9 ++++++++- libi2pd/SSU2.h | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 1503b404..1fb10927 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -283,8 +283,15 @@ namespace transport // but better to find out which host were sent it and mark that router as unreachable { i2p::transport::transports.UpdateReceivedBytes (bytes_transferred); + if (bytes_transferred < SSU2_MIN_RECEIVED_PACKET_SIZE) + { + // drop too short packets + m_PacketsPool.ReleaseMt (packet); + Receive (socket); + return; + } packet->len = bytes_transferred; - + boost::system::error_code ec; size_t moreBytes = socket.available (ec); if (!ec && moreBytes) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 03e22245..6d07f7fa 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022-2023, The PurpleI2P Project +* Copyright (c) 2022-2024, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -27,6 +27,7 @@ namespace transport const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K 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 int SSU2_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds From 0b47f65b069e47187efed3707c90866d0b036f39 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 19 Jan 2024 18:29:17 -0500 Subject: [PATCH 017/787] don't remove another NTCP2 session with same address --- libi2pd/NTCP2.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index c52c5cc2..a58ab0a2 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1415,7 +1415,11 @@ namespace transport void NTCP2Server::RemoveNTCP2Session (std::shared_ptr session) { if (session && session->GetRemoteIdentity ()) - m_NTCP2Sessions.erase (session->GetRemoteIdentity ()->GetIdentHash ()); + { + auto it = m_NTCP2Sessions.find (session->GetRemoteIdentity ()->GetIdentHash ()); + if (it != m_NTCP2Sessions.end () && it->second == session) + m_NTCP2Sessions.erase (it); + } } std::shared_ptr NTCP2Server::FindNTCP2Session (const i2p::data::IdentHash& ident) From 5e19e361e7ececd3008615a623e48f7f2f351e8b Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 20 Jan 2024 17:33:28 -0500 Subject: [PATCH 018/787] check max frame sizebefore sending --- libi2pd/NTCP2.cpp | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index a58ab0a2..45968f7d 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -809,15 +809,10 @@ namespace transport void NTCP2Session::HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - if (ecode || bytes_transferred != 2) + if (ecode) { if (ecode != boost::asio::error::operation_aborted) - { - if (ecode) - LogPrint (eLogWarning, "NTCP2: Receive length read error: ", ecode.message ()); - else if (bytes_transferred != 2) - LogPrint (eLogError, "NTCP2: Receive length of ", bytes_transferred, " bytes"); - } + LogPrint (eLogWarning, "NTCP2: Receive length read error: ", ecode.message ()); Terminate (); } else @@ -874,15 +869,10 @@ namespace transport void NTCP2Session::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - if (ecode || bytes_transferred != m_NextReceivedLen) + if (ecode) { if (ecode != boost::asio::error::operation_aborted) - { - if (ecode) - LogPrint (eLogWarning, "NTCP2: Receive read error: ", ecode.message ()); - else if (bytes_transferred != m_NextReceivedLen) - LogPrint (eLogError, "NTCP2: Received ", bytes_transferred, " bytes. Instead ", m_NextReceivedLen); - } + LogPrint (eLogWarning, "NTCP2: Receive read error: ", ecode.message ()); Terminate (); } else @@ -1061,6 +1051,11 @@ namespace transport macBuf = m_NextSendBuffer + paddingLen; totalLen += paddingLen; } + if (totalLen > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) + { + LogPrint (eLogError, "NTCP2: Frame to send is too long ", totalLen); + return; + } uint8_t nonce[12]; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; i2p::crypto::AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers @@ -1085,6 +1080,12 @@ namespace transport delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; return; } + if (payloadLen > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) + { + LogPrint (eLogError, "NTCP2: Buffer to send is too long ", payloadLen); + delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; + return; + } // encrypt uint8_t nonce[12]; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; @@ -1160,7 +1161,12 @@ namespace transport len -= 3; if (msgLen < 256) msgLen = 256; // for short message padding should not be always zero size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100; - if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) paddingSize = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3; + if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) + { + ssize_t l = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3; + if (l <= 0) return 0; + paddingSize = l; + } if (paddingSize > len) paddingSize = len; if (paddingSize) { @@ -1169,7 +1175,7 @@ namespace transport RAND_bytes ((uint8_t *)m_PaddingSizes, sizeof (m_PaddingSizes)); m_NextPaddingSize = 0; } - paddingSize = m_PaddingSizes[m_NextPaddingSize++] % paddingSize; + paddingSize = m_PaddingSizes[m_NextPaddingSize++] % (paddingSize + 1); } buf[0] = eNTCP2BlkPadding; // blk htobe16buf (buf + 1, paddingSize); // size From 9f217f8a117089e7a4e3d9eeb732f7a741f11edf Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 21 Jan 2024 18:59:04 -0500 Subject: [PATCH 019/787] don't send expired I2NP messages --- libi2pd/I2NPProtocol.cpp | 10 +++++++--- libi2pd/I2NPProtocol.h | 3 ++- libi2pd/NTCP2.cpp | 7 +++++++ libi2pd/SSU2Session.cpp | 3 ++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index b8147555..ebd5f8d6 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -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 * @@ -72,11 +72,15 @@ namespace i2p SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT); } - bool I2NPMessage::IsExpired () const + bool I2NPMessage::IsExpired (uint64_t ts) const { - auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto exp = GetExpiration (); return (ts > exp + I2NP_MESSAGE_CLOCK_SKEW) || (ts < exp - 3*I2NP_MESSAGE_CLOCK_SKEW); // check if expired or too far in future + } + + bool I2NPMessage::IsExpired () const + { + return IsExpired (i2p::util::GetMillisecondsSinceEpoch ()); } std::shared_ptr CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 6c64f2ab..e86f4f32 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -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 * @@ -252,6 +252,7 @@ namespace tunnel void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0, bool checksum = true); void RenewI2NPMessageHeader (); bool IsExpired () const; + bool IsExpired (uint64_t ts) const; // in milliseconds }; template diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 45968f7d..925c89dd 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1132,10 +1132,17 @@ namespace transport if (!m_SendQueue.empty ()) { std::vector > msgs; + auto ts = i2p::util::GetMillisecondsSinceEpoch (); size_t s = 0; while (!m_SendQueue.empty ()) { auto msg = m_SendQueue.front (); + if (!msg || msg->IsExpired (ts)) + { + // drop null or expired message + m_SendQueue.pop_front (); + continue; + } size_t len = msg->GetNTCP2Length (); if (s + len + 3 <= NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) // 3 bytes block header { diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 8cb39102..3ea07629 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -379,8 +379,9 @@ namespace transport while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) { auto msg = m_SendQueue.front (); - if (!msg) + if (!msg || msg->IsExpired (ts)) { + // drop null or expired message m_SendQueue.pop_front (); continue; } From a2249f0a82ca29215b039e15e7755be9f6012735 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 24 Jan 2024 13:52:13 -0500 Subject: [PATCH 020/787] identify server tunnel session but from ant to ports --- libi2pd_client/UDPTunnel.cpp | 57 +++++++++++++++++++++++++----------- libi2pd_client/UDPTunnel.h | 7 +++-- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/libi2pd_client/UDPTunnel.cpp b/libi2pd_client/UDPTunnel.cpp index 1e4b3d7c..3fcf8b35 100644 --- a/libi2pd_client/UDPTunnel.cpp +++ b/libi2pd_client/UDPTunnel.cpp @@ -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 * @@ -27,8 +27,17 @@ namespace client m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch(); } - void I2PUDPServerTunnel::HandleRecvFromI2PRaw (uint16_t, uint16_t, const uint8_t * buf, size_t len) + void I2PUDPServerTunnel::HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) { + if (m_LastSession && (fromPort != m_LastSession->RemotePort || toPort != m_LastSession->LocalPort)) + { + std::lock_guard lock(m_SessionsMutex); + auto it = m_Sessions.find (GetSessionIndex (fromPort, toPort)); + if (it != m_Sessions.end ()) + m_LastSession = it->second; + else + m_LastSession = nullptr; + } if (m_LastSession) { m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint); @@ -41,11 +50,12 @@ namespace client std::lock_guard lock(m_SessionsMutex); uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); auto itr = m_Sessions.begin(); - while(itr != m_Sessions.end()) { - if(now - (*itr)->LastActivity >= delta ) + while(itr != m_Sessions.end()) + { + if(now - itr->second->LastActivity >= delta ) itr = m_Sessions.erase(itr); else - ++itr; + itr++; } } @@ -66,15 +76,25 @@ namespace client UDPSessionPtr I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort) { auto ih = from.GetIdentHash(); - for (auto & s : m_Sessions ) + auto idx = GetSessionIndex (remotePort, localPort); { - if (s->Identity.GetLL()[0] == ih.GetLL()[0] && remotePort == s->RemotePort) + std::lock_guard lock(m_SessionsMutex); + auto it = m_Sessions.find (idx); + if (it != m_Sessions.end ()) { - /** found existing session */ - LogPrint(eLogDebug, "UDPServer: Found session ", s->IPSocket.local_endpoint(), " ", ih.ToBase32()); - return s; - } - } + if (it->second->Identity.GetLL()[0] == ih.GetLL()[0]) + { + LogPrint(eLogDebug, "UDPServer: Found session ", it->second->IPSocket.local_endpoint(), " ", ih.ToBase32()); + return it->second; + } + else + { + LogPrint(eLogWarning, "UDPServer: Session with from ", remotePort, " and to ", localPort, " ports already exists. But from differend address. Removed"); + m_Sessions.erase (it); + } + } + } + boost::asio::ip::address addr; /** create new udp session */ if(m_IsUniqueLocal && m_LocalAddress.is_loopback()) @@ -84,10 +104,12 @@ namespace client } else addr = m_LocalAddress; - boost::asio::ip::udp::endpoint ep(addr, 0); - m_Sessions.push_back(std::make_shared(ep, m_LocalDest, m_RemoteEndpoint, ih, localPort, remotePort)); - auto & back = m_Sessions.back(); - return back; + + auto s = std::make_shared(boost::asio::ip::udp::endpoint(addr, 0), + m_LocalDest, m_RemoteEndpoint, ih, localPort, remotePort); + std::lock_guard lock(m_SessionsMutex); + m_Sessions.emplace (idx, s); + return s; } UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint, @@ -175,8 +197,9 @@ namespace client std::vector > sessions; std::lock_guard lock (m_SessionsMutex); - for (UDPSessionPtr s: m_Sessions) + for (auto it: m_Sessions) { + auto s = it.second; if (!s->m_Destination) continue; auto info = s->m_Destination->GetInfoForRemote (s->Identity); if (!info) continue; diff --git a/libi2pd_client/UDPTunnel.h b/libi2pd_client/UDPTunnel.h index 3233c3f0..6dff41ea 100644 --- a/libi2pd_client/UDPTunnel.h +++ b/libi2pd_client/UDPTunnel.h @@ -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 * @@ -104,7 +104,8 @@ namespace client void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); UDPSessionPtr ObtainUDPSession (const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort); - + uint32_t GetSessionIndex (uint16_t fromPort, uint16_t toPort) const { return ((uint32_t)fromPort << 16) + toPort; } + private: bool m_IsUniqueLocal; @@ -112,7 +113,7 @@ namespace client boost::asio::ip::address m_LocalAddress; boost::asio::ip::udp::endpoint m_RemoteEndpoint; std::mutex m_SessionsMutex; - std::vector m_Sessions; + std::unordered_map m_Sessions; // (from port, to port)->session std::shared_ptr m_LocalDest; UDPSessionPtr m_LastSession; bool m_Gzip; From c5a18065281e45469518d6db032264971252199b Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 24 Jan 2024 13:58:42 -0500 Subject: [PATCH 021/787] fixed possible deadlock --- libi2pd_client/UDPTunnel.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libi2pd_client/UDPTunnel.cpp b/libi2pd_client/UDPTunnel.cpp index 3fcf8b35..0bf3202f 100644 --- a/libi2pd_client/UDPTunnel.cpp +++ b/libi2pd_client/UDPTunnel.cpp @@ -19,10 +19,7 @@ namespace client void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) { if (!m_LastSession || m_LastSession->Identity.GetLL()[0] != from.GetIdentHash ().GetLL()[0] || fromPort != m_LastSession->RemotePort) - { - std::lock_guard lock(m_SessionsMutex); m_LastSession = ObtainUDPSession(from, toPort, fromPort); - } m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint); m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch(); } From 70639f11396ad514d3bf358b8dccdd9aee7aff80 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 24 Jan 2024 19:05:38 -0500 Subject: [PATCH 022/787] don't adjust clock if offsets came from same router --- libi2pd/SSU2.cpp | 29 +++++++++++++++++++++-------- libi2pd/SSU2.h | 3 ++- libi2pd/SSU2Session.cpp | 6 +++--- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 1fb10927..0ebeab6d 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -210,27 +210,40 @@ namespace transport return ep.port (); } - void SSU2Server::AdjustTimeOffset (int64_t offset) + void SSU2Server::AdjustTimeOffset (int64_t offset, std::shared_ptr from) { if (offset) { if (m_PendingTimeOffset) // one more { - if (std::abs (m_PendingTimeOffset - offset) < SSU2_CLOCK_SKEW) + if (m_PendingTimeOffsetFrom && from && + m_PendingTimeOffsetFrom->GetIdentHash ().GetLL()[0] != from->GetIdentHash ().GetLL()[0]) // from different routers { - offset = (m_PendingTimeOffset + offset)/2; // average - LogPrint (eLogWarning, "SSU2: Clock adjusted by ", offset, " seconds"); - i2p::util::AdjustTimeOffset (offset); - } + if (std::abs (m_PendingTimeOffset - offset) < SSU2_CLOCK_SKEW) + { + offset = (m_PendingTimeOffset + offset)/2; // average + LogPrint (eLogWarning, "SSU2: Clock adjusted by ", offset, " seconds"); + i2p::util::AdjustTimeOffset (offset); + } + else + LogPrint (eLogWarning, "SSU2: Time offsets are too different. Clock not adjusted"); + m_PendingTimeOffset = 0; + m_PendingTimeOffsetFrom = nullptr; + } else - LogPrint (eLogWarning, "SSU2: Time offsets are too different. Clock not adjusted"); - m_PendingTimeOffset = 0; + LogPrint (eLogWarning, "SSU2: Time offsets from same router. Clock not adjusted"); } else + { m_PendingTimeOffset = offset; // first + m_PendingTimeOffsetFrom = from; + } } else + { m_PendingTimeOffset = 0; // reset + m_PendingTimeOffsetFrom = nullptr; + } } boost::asio::ip::udp::socket& SSU2Server::OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 6d07f7fa..da682746 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -67,7 +67,7 @@ namespace transport bool IsSupported (const boost::asio::ip::address& addr) const; uint16_t GetPort (bool v4) const; bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; - void AdjustTimeOffset (int64_t offset); + void AdjustTimeOffset (int64_t offset, std::shared_ptr from); void AddSession (std::shared_ptr session); void RemoveSession (uint64_t connID); @@ -164,6 +164,7 @@ namespace transport bool m_IsPublished; // if we maintain introducers bool m_IsSyncClockFromPeers; int64_t m_PendingTimeOffset; // during peer test + std::shared_ptr m_PendingTimeOffsetFrom; // proxy bool m_IsThroughProxy; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 3ea07629..5c951391 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1671,10 +1671,10 @@ namespace transport if (std::abs (offset) > SSU2_CLOCK_THRESHOLD) { LogPrint (eLogWarning, "SSU2: Time offset ", offset, " from ", m_RemoteEndpoint); - m_Server.AdjustTimeOffset (-offset); + m_Server.AdjustTimeOffset (-offset, GetRemoteIdentity ()); } else - m_Server.AdjustTimeOffset (0); + m_Server.AdjustTimeOffset (0, nullptr); } else if (std::abs (offset) > SSU2_CLOCK_SKEW) { @@ -2485,7 +2485,7 @@ namespace transport i2p::context.SetTestingV6 (testing); } if (!testing) - m_Server.AdjustTimeOffset (0); // reset time offset when testing is over + m_Server.AdjustTimeOffset (0, nullptr); // reset time offset when testing is over } size_t SSU2Session::CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep) From 5b93558bd0d7b46bf004a198f15282d217e5c7d8 Mon Sep 17 00:00:00 2001 From: weko Date: Thu, 25 Jan 2024 01:05:58 +0000 Subject: [PATCH 023/787] Add support for multiple udp server tunnels on one destionation --- libi2pd/Datagram.cpp | 68 ++++++++++++++++++++++++++++++-- libi2pd/Datagram.h | 28 +++++++------ libi2pd_client/ClientContext.cpp | 2 +- libi2pd_client/SAM.cpp | 53 ++++++++++++++----------- libi2pd_client/UDPTunnel.cpp | 46 ++++++++++++++------- libi2pd_client/UDPTunnel.h | 3 +- 6 files changed, 143 insertions(+), 57 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 64738ebe..c99db584 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -19,7 +19,7 @@ namespace i2p namespace datagram { DatagramDestination::DatagramDestination (std::shared_ptr owner, bool gzip): - m_Owner (owner), m_Receiver (nullptr), m_RawReceiver (nullptr), m_Gzip (gzip) + m_Owner (owner), m_DefaultReceiver (nullptr), m_DefaultRawReceiver (nullptr), m_Gzip (gzip) { if (m_Gzip) m_Deflator.reset (new i2p::data::GzipDeflator); @@ -119,19 +119,79 @@ namespace datagram void DatagramDestination::HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) { - if (m_RawReceiver) - m_RawReceiver (fromPort, toPort, buf, len); + auto r = FindRawReceiver(toPort); + + if (r) + r (fromPort, toPort, buf, len); else LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram"); } + void DatagramDestination::SetReceiver (const Receiver& receiver, uint16_t port) + { + std::lock_guard lock(m_ReceiversMutex); + m_ReceiversByPorts[port] = receiver; + if (!m_DefaultReceiver) { + m_DefaultReceiver = receiver; + m_DefaultReceiverPort = port; + } + } + + void DatagramDestination::ResetReceiver (uint16_t port) + { + std::lock_guard lock(m_ReceiversMutex); + m_ReceiversByPorts.erase (port); + if (m_DefaultReceiverPort == port) { + m_DefaultReceiver = nullptr; + m_DefaultReceiverPort = 0; + } + } + + + void DatagramDestination::SetRawReceiver (const RawReceiver& receiver, uint16_t port) + { + std::lock_guard lock(m_RawReceiversMutex); + m_RawReceiversByPorts[port] = receiver; + if (!m_DefaultRawReceiver) { + m_DefaultRawReceiver = receiver; + m_DefaultRawReceiverPort = port; + } + }; + + void DatagramDestination::ResetRawReceiver (uint16_t port) + { + std::lock_guard lock(m_RawReceiversMutex); + m_RawReceiversByPorts.erase (port); + if (m_DefaultRawReceiverPort == port) { + m_DefaultRawReceiver = nullptr; + m_DefaultRawReceiverPort = 0; + } + } + + DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port) { std::lock_guard lock(m_ReceiversMutex); - Receiver r = m_Receiver; + Receiver r = nullptr; auto itr = m_ReceiversByPorts.find(port); if (itr != m_ReceiversByPorts.end()) r = itr->second; + else { + r = m_DefaultReceiver; + } + return r; + } + + DatagramDestination::RawReceiver DatagramDestination::FindRawReceiver(uint16_t port) + { + std::lock_guard lock(m_RawReceiversMutex); + RawReceiver r = nullptr; + auto itr = m_RawReceiversByPorts.find(port); + if (itr != m_RawReceiversByPorts.end()) + r = itr->second; + else { + r = m_DefaultRawReceiver; + } return r; } diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index e6d1f7b6..fd6af909 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -126,14 +126,12 @@ namespace datagram void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false); - void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; }; - void ResetReceiver () { m_Receiver = nullptr; }; - void SetReceiver (const Receiver& receiver, uint16_t port) { std::lock_guard lock(m_ReceiversMutex); m_ReceiversByPorts[port] = receiver; }; - void ResetReceiver (uint16_t port) { std::lock_guard lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); }; + void SetReceiver (const Receiver& receiver, uint16_t port); + void ResetReceiver (uint16_t port); - void SetRawReceiver (const RawReceiver& receiver) { m_RawReceiver = receiver; }; - void ResetRawReceiver () { m_RawReceiver = nullptr; }; + void SetRawReceiver (const RawReceiver& receiver, uint16_t port); + void ResetRawReceiver (uint16_t port); std::shared_ptr GetInfoForRemote(const i2p::data::IdentHash & remote); @@ -150,20 +148,26 @@ namespace datagram void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len); void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); - /** find a receiver by port, if none by port is found try default receiver, otherwise returns nullptr */ Receiver FindReceiver(uint16_t port); + RawReceiver FindRawReceiver(uint16_t port); private: std::shared_ptr m_Owner; - Receiver m_Receiver; // default - RawReceiver m_RawReceiver; // default - bool m_Gzip; // gzip compression of data messages + std::mutex m_SessionsMutex; std::map m_Sessions; - std::mutex m_ReceiversMutex; - std::map m_ReceiversByPorts; + Receiver m_DefaultReceiver; + RawReceiver m_DefaultRawReceiver; + uint16_t m_DefaultReceiverPort; + uint16_t m_DefaultRawReceiverPort; + std::mutex m_ReceiversMutex; + std::mutex m_RawReceiversMutex; + std::unordered_map m_ReceiversByPorts; + std::unordered_map m_RawReceiversByPorts; + + bool m_Gzip; // gzip compression of data messages i2p::data::GzipInflator m_Inflator; std::unique_ptr m_Deflator; std::vector m_From, m_Signature; diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index d8c0bd2d..4efe252d 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -775,7 +775,7 @@ namespace client address = "127.0.0.1"; } auto localAddress = boost::asio::ip::address::from_string(address); - auto serverTunnel = std::make_shared(name, localDestination, localAddress, endpoint, port, gzip); + auto serverTunnel = std::make_shared(name, localDestination, localAddress, endpoint, inPort, gzip); if(!isUniqueLocal) { LogPrint(eLogInfo, "Clients: Disabling loopback address mapping"); diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 1a3afb58..e4cbae8a 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -415,12 +415,17 @@ namespace client { session->UDPEndpoint = forward; auto dest = session->GetLocalDestination ()->CreateDatagramDestination (); + auto port = std::stoi(params[SAM_PARAM_PORT]); if (type == eSAMSessionTypeDatagram) dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (), - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), + port + ); else // raw dest->SetRawReceiver (std::bind (&SAMSocket::HandleI2PRawDatagramReceive, shared_from_this (), - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), + port + ); } if (session->GetLocalDestination ()->IsReady ()) @@ -524,7 +529,7 @@ namespace client if (addr->IsIdentHash ()) { if (session->GetLocalDestination ()->GetIdentHash () != addr->identHash) - { + { auto leaseSet = session->GetLocalDestination ()->FindLeaseSet(addr->identHash); if (leaseSet) Connect(leaseSet, session); @@ -556,7 +561,7 @@ namespace client if (session) { if (session->GetLocalDestination ()->SupportsEncryptionType (remote->GetEncryptionType ())) - { + { m_SocketType = eSAMSocketTypeStream; m_Stream = session->GetLocalDestination ()->CreateStream (remote); if (m_Stream) @@ -570,7 +575,7 @@ namespace client SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); } else - SendStreamCantReachPeer ("Incompatible crypto"); + SendStreamCantReachPeer ("Incompatible crypto"); } else SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); @@ -583,7 +588,7 @@ namespace client else { LogPrint (eLogError, "SAM: Destination to connect not found"); - SendStreamCantReachPeer ("LeaseSet not found"); + SendStreamCantReachPeer ("LeaseSet not found"); } } @@ -612,27 +617,27 @@ namespace client session->GetLocalDestination ()->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1)); } else - { + { auto ts = i2p::util::GetSecondsSinceEpoch (); while (!session->acceptQueue.empty () && session->acceptQueue.front ().second + SAM_SESSION_MAX_ACCEPT_INTERVAL > ts) - { + { auto socket = session->acceptQueue.front ().first; session->acceptQueue.pop_front (); if (socket) m_Owner.GetService ().post (std::bind(&SAMSocket::TerminateClose, socket)); - } + } if (session->acceptQueue.size () < SAM_SESSION_MAX_ACCEPT_QUEUE_SIZE) { // already accepting, queue up SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); session->acceptQueue.push_back (std::make_pair(shared_from_this(), ts)); - } - else - { + } + else + { LogPrint (eLogInfo, "SAM: Session ", m_ID, " accept queue is full ", session->acceptQueue.size ()); SendStreamI2PError ("Already accepting"); - } - } + } + } } else SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); @@ -875,8 +880,8 @@ namespace client size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, reply, msg.c_str()); #endif SendMessageReply (m_Buffer, len, true); - } - + } + void SAMSocket::SendSessionI2PError(const std::string & msg) { LogPrint (eLogError, "SAM: Session I2P error: ", msg); @@ -886,14 +891,14 @@ namespace client void SAMSocket::SendStreamI2PError(const std::string & msg) { LogPrint (eLogError, "SAM: Stream I2P error: ", msg); - SendReplyWithMessage (SAM_STREAM_STATUS_I2P_ERROR, msg); + SendReplyWithMessage (SAM_STREAM_STATUS_I2P_ERROR, msg); } void SAMSocket::SendStreamCantReachPeer(const std::string & msg) { - SendReplyWithMessage (SAM_STREAM_STATUS_CANT_REACH_PEER, msg); - } - + SendReplyWithMessage (SAM_STREAM_STATUS_CANT_REACH_PEER, msg); + } + void SAMSocket::HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr leaseSet, std::string name) { if (leaseSet) @@ -1093,14 +1098,14 @@ namespace client // pending acceptors auto ts = i2p::util::GetSecondsSinceEpoch (); while (!session->acceptQueue.empty () && session->acceptQueue.front ().second + SAM_SESSION_MAX_ACCEPT_INTERVAL > ts) - { + { auto socket = session->acceptQueue.front ().first; session->acceptQueue.pop_front (); if (socket) m_Owner.GetService ().post (std::bind(&SAMSocket::TerminateClose, socket)); - } + } if (!session->acceptQueue.empty ()) - { + { auto socket = session->acceptQueue.front ().first; session->acceptQueue.pop_front (); if (socket && socket->GetSocketType () == eSAMSocketTypeAcceptor) @@ -1108,7 +1113,7 @@ namespace client socket->m_IsAccepting = true; session->GetLocalDestination ()->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, socket, std::placeholders::_1)); } - } + } } if (!m_IsSilent) { diff --git a/libi2pd_client/UDPTunnel.cpp b/libi2pd_client/UDPTunnel.cpp index 0bf3202f..cd17bbf0 100644 --- a/libi2pd_client/UDPTunnel.cpp +++ b/libi2pd_client/UDPTunnel.cpp @@ -32,7 +32,7 @@ namespace client auto it = m_Sessions.find (GetSessionIndex (fromPort, toPort)); if (it != m_Sessions.end ()) m_LastSession = it->second; - else + else m_LastSession = nullptr; } if (m_LastSession) @@ -47,7 +47,7 @@ namespace client std::lock_guard lock(m_SessionsMutex); uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); auto itr = m_Sessions.begin(); - while(itr != m_Sessions.end()) + while(itr != m_Sessions.end()) { if(now - itr->second->LastActivity >= delta ) itr = m_Sessions.erase(itr); @@ -88,10 +88,10 @@ namespace client { LogPrint(eLogWarning, "UDPServer: Session with from ", remotePort, " and to ", localPort, " ports already exists. But from differend address. Removed"); m_Sessions.erase (it); - } - } - } - + } + } + } + boost::asio::ip::address addr; /** create new udp session */ if(m_IsUniqueLocal && m_LocalAddress.is_loopback()) @@ -102,7 +102,7 @@ namespace client else addr = m_LocalAddress; - auto s = std::make_shared(boost::asio::ip::udp::endpoint(addr, 0), + auto s = std::make_shared(boost::asio::ip::udp::endpoint(addr, 0), m_LocalDest, m_RemoteEndpoint, ih, localPort, remotePort); std::lock_guard lock(m_SessionsMutex); m_Sessions.emplace (idx, s); @@ -163,9 +163,9 @@ namespace client } I2PUDPServerTunnel::I2PUDPServerTunnel (const std::string & name, std::shared_ptr localDestination, - const boost::asio::ip::address& localAddress, const boost::asio::ip::udp::endpoint& forwardTo, uint16_t port, bool gzip) : + const boost::asio::ip::address& localAddress, const boost::asio::ip::udp::endpoint& forwardTo, uint16_t inPort, bool gzip) : m_IsUniqueLocal (true), m_Name (name), m_LocalAddress (localAddress), - m_RemoteEndpoint (forwardTo), m_LocalDest (localDestination), m_Gzip (gzip) + m_RemoteEndpoint (forwardTo), m_LocalDest (localDestination), m_inPort(inPort), m_Gzip (gzip) { } @@ -179,14 +179,23 @@ namespace client m_LocalDest->Start (); auto dgram = m_LocalDest->CreateDatagramDestination (m_Gzip); - dgram->SetReceiver (std::bind (&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); - dgram->SetRawReceiver (std::bind (&I2PUDPServerTunnel::HandleRecvFromI2PRaw, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + dgram->SetReceiver ( + std::bind (&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), + m_inPort + ); + dgram->SetRawReceiver ( + std::bind (&I2PUDPServerTunnel::HandleRecvFromI2PRaw, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), + m_inPort + ); } void I2PUDPServerTunnel::Stop () { auto dgram = m_LocalDest->GetDatagramDestination (); - if (dgram) dgram->ResetReceiver (); + if (dgram) { + dgram->ResetReceiver (m_inPort); + dgram->ResetRawReceiver (m_inPort); + } } std::vector > I2PUDPServerTunnel::GetSessions () @@ -240,9 +249,13 @@ namespace client dgram->SetReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, - std::placeholders::_5)); + std::placeholders::_5), + RemotePort + ); dgram->SetRawReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2PRaw, this, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), + RemotePort + ); m_LocalDest->Start (); if (m_ResolveThread == nullptr) @@ -253,7 +266,10 @@ namespace client void I2PUDPClientTunnel::Stop () { auto dgram = m_LocalDest->GetDatagramDestination (); - if (dgram) dgram->ResetReceiver (); + if (dgram) { + dgram->ResetReceiver (RemotePort); + dgram->ResetRawReceiver (RemotePort); + } m_cancel_resolve = true; m_Sessions.clear(); diff --git a/libi2pd_client/UDPTunnel.h b/libi2pd_client/UDPTunnel.h index 6dff41ea..5650124c 100644 --- a/libi2pd_client/UDPTunnel.h +++ b/libi2pd_client/UDPTunnel.h @@ -105,7 +105,7 @@ namespace client void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); UDPSessionPtr ObtainUDPSession (const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort); uint32_t GetSessionIndex (uint16_t fromPort, uint16_t toPort) const { return ((uint32_t)fromPort << 16) + toPort; } - + private: bool m_IsUniqueLocal; @@ -116,6 +116,7 @@ namespace client std::unordered_map m_Sessions; // (from port, to port)->session std::shared_ptr m_LocalDest; UDPSessionPtr m_LastSession; + uint16_t m_inPort; bool m_Gzip; public: From 4b167fdbafe577bca8b745e64ed0b15140c90b34 Mon Sep 17 00:00:00 2001 From: weko Date: Thu, 25 Jan 2024 01:57:24 +0000 Subject: [PATCH 024/787] Update copyright year --- libi2pd/Datagram.cpp | 2 +- libi2pd/Datagram.h | 2 +- libi2pd_client/ClientContext.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index c99db584..717e3312 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -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 * diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index fd6af909..45edecab 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -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 * diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 4efe252d..c27ce625 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -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 * From 67c4d4bcaafbe67ee5dd7bbd4fda44eb1d91a6e4 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 25 Jan 2024 09:09:44 -0500 Subject: [PATCH 025/787] fixed VS build error --- libi2pd/NTCP2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 925c89dd..fff2fdc7 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1170,7 +1170,7 @@ namespace transport size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100; if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) { - ssize_t l = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3; + int l = (int)NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3; if (l <= 0) return 0; paddingSize = l; } From 75c2cb751f493c4bf96249e1b1e800868806943c Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 25 Jan 2024 18:51:46 -0500 Subject: [PATCH 026/787] lock mutex before deleting RouterInfo's buffer --- libi2pd/NetDb.cpp | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 8eb5d653..f1be7520 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -240,7 +240,7 @@ namespace data { bool wasFloodfill = r->IsFloodfill (); { - std::unique_lock l(m_RouterInfosMutex); + std::lock_guard l(m_RouterInfosMutex); if (!r->Update (buf, len)) { updated = false; @@ -254,7 +254,7 @@ namespace data m_RouterInfos.erase (ident); if (wasFloodfill) { - std::unique_lock l(m_FloodfillsMutex); + std::lock_guard l(m_FloodfillsMutex); m_Floodfills.Remove (r->GetIdentHash ()); } m_Requests.RequestComplete (ident, nullptr); @@ -265,7 +265,7 @@ namespace data if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated { LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64()); - std::unique_lock l(m_FloodfillsMutex); + std::lock_guard l(m_FloodfillsMutex); if (wasFloodfill) m_Floodfills.Remove (r->GetIdentHash ()); else if (r->IsEligibleFloodfill ()) @@ -291,7 +291,7 @@ namespace data { bool inserted = false; { - std::unique_lock l(m_RouterInfosMutex); + std::lock_guard l(m_RouterInfosMutex); inserted = m_RouterInfos.insert ({r->GetIdentHash (), r}).second; } if (inserted) @@ -302,7 +302,7 @@ namespace data if (m_Floodfills.GetSize () < NETDB_NUM_FLOODFILLS_THRESHOLD || r->GetProfile ()->IsReal ()) // don't insert floodfill until it's known real if we have enough { - std::unique_lock l(m_FloodfillsMutex); + std::lock_guard l(m_FloodfillsMutex); m_Floodfills.Insert (r); } else @@ -325,7 +325,7 @@ namespace data bool NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len) { - std::unique_lock lock(m_LeaseSetsMutex); + std::lock_guard lock(m_LeaseSetsMutex); bool updated = false; auto it = m_LeaseSets.find(ident); if (it != m_LeaseSets.end () && it->second->GetStoreType () == i2p::data::NETDB_STORE_TYPE_LEASESET) @@ -366,7 +366,7 @@ namespace data auto leaseSet = std::make_shared (storeType, buf, len, false); // we don't need leases in netdb if (leaseSet->IsValid ()) { - std::unique_lock lock(m_LeaseSetsMutex); + std::lock_guard lock(m_LeaseSetsMutex); auto it = m_LeaseSets.find(ident); if (it == m_LeaseSets.end () || it->second->GetStoreType () != storeType || leaseSet->GetPublishedTimestamp () > it->second->GetPublishedTimestamp ()) @@ -393,7 +393,7 @@ namespace data std::shared_ptr NetDb::FindRouter (const IdentHash& ident) const { - std::unique_lock l(m_RouterInfosMutex); + std::lock_guard l(m_RouterInfosMutex); auto it = m_RouterInfos.find (ident); if (it != m_RouterInfos.end ()) return it->second; @@ -403,7 +403,7 @@ namespace data std::shared_ptr NetDb::FindLeaseSet (const IdentHash& destination) const { - std::unique_lock lock(m_LeaseSetsMutex); + std::lock_guard lock(m_LeaseSetsMutex); auto it = m_LeaseSets.find (destination); if (it != m_LeaseSets.end ()) return it->second; @@ -437,7 +437,7 @@ namespace data auto r = FindRouter (ident); if (r) { - std::unique_lock l(m_RouterInfosMutex); + std::lock_guard l(m_RouterInfosMutex); r->ExcludeReachableTransports (transports); } } @@ -527,7 +527,7 @@ namespace data void NetDb::VisitLeaseSets(LeaseSetVisitor v) { - std::unique_lock lock(m_LeaseSetsMutex); + std::lock_guard lock(m_LeaseSetsMutex); for ( auto & entry : m_LeaseSets) v(entry.first, entry.second); } @@ -543,7 +543,7 @@ namespace data void NetDb::VisitRouterInfos(RouterInfoVisitor v) { - std::unique_lock lock(m_RouterInfosMutex); + std::lock_guard lock(m_RouterInfosMutex); for ( const auto & item : m_RouterInfos ) v(item.second); } @@ -555,7 +555,7 @@ namespace data size_t iters = max_iters_per_cyle; while(n > 0) { - std::unique_lock lock(m_RouterInfosMutex); + std::lock_guard lock(m_RouterInfosMutex); uint32_t idx = rand () % m_RouterInfos.size (); uint32_t i = 0; for (const auto & it : m_RouterInfos) { @@ -638,6 +638,7 @@ namespace data // we have something to save it.second->SaveToFile (m_Storage.Path(ident)); it.second->SetUnreachable (false); + std::lock_guard l(m_RouterInfosMutex); // possible collision between DeleteBuffer and Update it.second->DeleteBuffer (); } it.second->SetUpdated (false); @@ -696,7 +697,7 @@ namespace data LogPrint (eLogInfo, "NetDb: Deleting ", deletedCount, " unreachable routers"); // clean up RouterInfos table { - std::unique_lock l(m_RouterInfosMutex); + std::lock_guard l(m_RouterInfosMutex); for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();) { if (!it->second || it->second->IsUnreachable ()) @@ -710,7 +711,7 @@ namespace data } // clean up expired floodfills or not floodfills anymore { - std::unique_lock l(m_FloodfillsMutex); + std::lock_guard l(m_FloodfillsMutex); m_Floodfills.Cleanup ([](const std::shared_ptr& r)->bool { return r && r->IsFloodfill () && !r->IsUnreachable (); @@ -1249,7 +1250,7 @@ namespace data return 0; uint16_t inds[3]; RAND_bytes ((uint8_t *)inds, sizeof (inds)); - std::unique_lock l(m_RouterInfosMutex); + std::lock_guard l(m_RouterInfosMutex); auto count = m_RouterInfos.size (); if(count == 0) return nullptr; inds[0] %= count; @@ -1311,7 +1312,7 @@ namespace data const std::set& excluded) const { IdentHash destKey = CreateRoutingKey (destination); - std::unique_lock l(m_FloodfillsMutex); + std::lock_guard l(m_FloodfillsMutex); return m_Floodfills.FindClosest (destKey, [&excluded](const std::shared_ptr& r)->bool { return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () && @@ -1326,7 +1327,7 @@ namespace data IdentHash destKey = CreateRoutingKey (destination); std::vector > v; { - std::unique_lock l(m_FloodfillsMutex); + std::lock_guard l(m_FloodfillsMutex); v = m_Floodfills.FindClosest (destKey, num, [&excluded](const std::shared_ptr& r)->bool { return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () && @@ -1381,7 +1382,7 @@ namespace data { auto ts = i2p::util::GetSecondsSinceEpoch (); { - std::unique_lock l(m_RouterInfosMutex); + std::lock_guard l(m_RouterInfosMutex); for (auto& it: m_RouterInfos) it.second->UpdateIntroducers (ts); } From 530c353b00f73dcc497cf13206d50051b0748615 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 27 Jan 2024 12:17:59 -0500 Subject: [PATCH 027/787] don't send Ack with NACK immediately but after 2 milliseconds --- libi2pd/Streaming.cpp | 37 ++++++++++++++++--------------------- libi2pd/Streaming.h | 3 ++- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 629039ab..c43f99ad 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -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 * @@ -179,13 +179,9 @@ namespace stream { if (!m_IsAckSendScheduled) { - m_IsAckSendScheduled = true; auto ackTimeout = m_RTT/10; if (ackTimeout > m_AckDelay) ackTimeout = m_AckDelay; - else if (ackTimeout < MIN_SEND_ACK_TIMEOUT) ackTimeout = MIN_SEND_ACK_TIMEOUT; - m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(ackTimeout)); - m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer, - shared_from_this (), std::placeholders::_1)); + ScheduleAck (ackTimeout); } } else if (packet->IsSYN ()) @@ -207,23 +203,11 @@ namespace stream // save message and wait for missing message again SavePacket (packet); if (m_LastReceivedSequenceNumber >= 0) - { - // send NACKs for missing messages ASAP - if (m_IsAckSendScheduled) - { - m_IsAckSendScheduled = false; - m_AckSendTimer.cancel (); - } - SendQuickAck (); - } + // send NACKs for missing messages with minimal timeout + ScheduleAck (MIN_SEND_ACK_TIMEOUT); else - { // wait for SYN - m_IsAckSendScheduled = true; - m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(SYN_TIMEOUT)); - m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer, - shared_from_this (), std::placeholders::_1)); - } + ScheduleAck (SYN_TIMEOUT); } } } @@ -1029,6 +1013,17 @@ namespace stream } } + void Stream::ScheduleAck (int timeout) + { + if (m_IsAckSendScheduled) + m_AckSendTimer.cancel (); + m_IsAckSendScheduled = true; + if (timeout < MIN_SEND_ACK_TIMEOUT) timeout = MIN_SEND_ACK_TIMEOUT; + m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(timeout)); + m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer, + shared_from_this (), std::placeholders::_1)); + } + void Stream::HandleAckSendTimer (const boost::system::error_code& ecode) { if (m_IsAckSendScheduled) diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 1db59118..ed79edc9 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -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 * @@ -227,6 +227,7 @@ namespace stream void ScheduleResend (); void HandleResendTimer (const boost::system::error_code& ecode); + void ScheduleAck (int timeout); void HandleAckSendTimer (const boost::system::error_code& ecode); private: From a3246cd9dc92f91219801e6ef8c6fa22f0056616 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 27 Jan 2024 17:57:50 -0500 Subject: [PATCH 028/787] doen't send Ack packet too often if missing packets --- libi2pd/Streaming.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index c43f99ad..a4604892 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -203,8 +203,11 @@ namespace stream // save message and wait for missing message again SavePacket (packet); if (m_LastReceivedSequenceNumber >= 0) - // send NACKs for missing messages with minimal timeout - ScheduleAck (MIN_SEND_ACK_TIMEOUT); + { + if (!m_IsAckSendScheduled) + // send NACKs for missing messages + ScheduleAck (MIN_SEND_ACK_TIMEOUT*m_SavedPackets.size ()); + } else // wait for SYN ScheduleAck (SYN_TIMEOUT); From 81015a52285651e0c6fe2a8bf33d7dd0b2c96b83 Mon Sep 17 00:00:00 2001 From: Vort Date: Sun, 28 Jan 2024 15:37:14 +0200 Subject: [PATCH 029/787] log changes of network status --- libi2pd/RouterContext.cpp | 4 ++++ libi2pd/RouterContext.h | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 10d33bf5..b3c51ca6 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -303,6 +303,8 @@ namespace i2p SetTesting (false); if (status != m_Status) { + LogPrint(eLogInfo, "Router: network status v4 changed ", + ROUTER_STATUS_NAMES[m_Status], " -> ", ROUTER_STATUS_NAMES[status]); m_Status = status; switch (m_Status) { @@ -323,6 +325,8 @@ namespace i2p SetTestingV6 (false); if (status != m_StatusV6) { + LogPrint(eLogInfo, "Router: network status v6 changed ", + ROUTER_STATUS_NAMES[m_StatusV6], " -> ", ROUTER_STATUS_NAMES[status]); m_StatusV6 = status; switch (m_StatusV6) { diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 91a553ba..ddfc65de 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -48,6 +48,15 @@ namespace garlic eRouterStatusMesh = 4 }; + const char* const ROUTER_STATUS_NAMES[] = + { + "OK", // 0 + "Firewalled", // 1 + "Unknown", // 2 + "Proxy", // 3 + "Mesh" // 4 + }; + enum RouterError { eRouterErrorNone = 0, From 822cb35efe35b95c269329275b1d00f3b7f3b7c8 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 28 Jan 2024 18:12:40 -0500 Subject: [PATCH 030/787] limit send Ack timeout by Ack delay interval --- libi2pd/Streaming.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index a4604892..74fb3d97 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -205,8 +205,12 @@ namespace stream if (m_LastReceivedSequenceNumber >= 0) { if (!m_IsAckSendScheduled) + { // send NACKs for missing messages - ScheduleAck (MIN_SEND_ACK_TIMEOUT*m_SavedPackets.size ()); + int ackTimeout = MIN_SEND_ACK_TIMEOUT*m_SavedPackets.size (); + if (ackTimeout > m_AckDelay) ackTimeout = m_AckDelay; + ScheduleAck (ackTimeout); + } } else // wait for SYN From d926a310645d9778848f8fadb710a70dc66ebd34 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 29 Jan 2024 18:01:41 -0500 Subject: [PATCH 031/787] fixed warning --- libi2pd/Datagram.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 717e3312..f87f9653 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -156,7 +156,7 @@ namespace datagram m_DefaultRawReceiver = receiver; m_DefaultRawReceiverPort = port; } - }; + } void DatagramDestination::ResetRawReceiver (uint16_t port) { From f0084785059b8e78acef3301e1fd818ec6b0c73b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 29 Jan 2024 19:54:43 -0500 Subject: [PATCH 032/787] handle I2NP messages drops --- libi2pd/I2NPProtocol.h | 7 +++++-- libi2pd/NTCP2.cpp | 1 + libi2pd/NetDb.cpp | 6 +++++- libi2pd/NetDbRequests.cpp | 6 +++++- libi2pd/SSU2Session.cpp | 1 + libi2pd/Transports.h | 7 +++++++ 6 files changed, 24 insertions(+), 4 deletions(-) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index e86f4f32..a2877a08 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "Crypto.h" #include "I2PEndian.h" #include "Identity.h" @@ -149,7 +150,8 @@ namespace tunnel uint8_t * buf; size_t len, offset, maxLen; std::shared_ptr from; - + std::function onDrop; + I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2), offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header @@ -241,7 +243,6 @@ namespace tunnel SetSize (len - offset - I2NP_HEADER_SIZE); SetChks (0); } - void ToNTCP2 () { uint8_t * ntcp2 = GetNTCP2Header (); @@ -253,6 +254,8 @@ namespace tunnel void RenewI2NPMessageHeader (); bool IsExpired () const; bool IsExpired (uint64_t ts) const; // in milliseconds + + void Drop () { if (onDrop) { onDrop (); onDrop = nullptr; }; } }; template diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index fff2fdc7..ad8ef51d 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1140,6 +1140,7 @@ namespace transport if (!msg || msg->IsExpired (ts)) { // drop null or expired message + if (msg) msg->Drop (); m_SendQueue.pop_front (); continue; } diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index f1be7520..0bf7af9d 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -736,7 +736,11 @@ namespace data !i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) direct = false; // floodfill can't be reached directly if (direct) - transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); + { + auto msg = dest->CreateRequestMessage (floodfill->GetIdentHash ()); + msg->onDrop = [this, dest]() { this->m_Requests.SendNextRequest (dest); }; + transports.SendMessage (floodfill->GetIdentHash (), msg); + } else { auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index 92e5a7b8..4099f921 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -188,7 +188,11 @@ namespace data !i2p::transport::transports.IsConnected (nextFloodfill->GetIdentHash ())) direct = false; // floodfill can't be reached directly if (direct) - i2p::transport::transports.SendMessage (nextFloodfill->GetIdentHash (), dest->CreateRequestMessage (nextFloodfill->GetIdentHash ())); + { + auto msg = dest->CreateRequestMessage (nextFloodfill->GetIdentHash ()); + msg->onDrop = [this, dest]() { this->SendNextRequest (dest); }; + i2p::transport::transports.SendMessage (nextFloodfill->GetIdentHash (), msg); + } else { auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 5c951391..fa6d9eca 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -382,6 +382,7 @@ namespace transport if (!msg || msg->IsExpired (ts)) { // drop null or expired message + if (msg) msg->Drop (); m_SendQueue.pop_front (); continue; } diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 0e5518b1..c78a8bd0 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -86,6 +86,13 @@ namespace transport } } + ~Peer () + { + // drop not sent delayed messages + for (auto& it: delayedMessages) + it->Drop (); + } + void Done () { for (auto& it: sessions) From 85f5f5b91e669d626adb1daaa98a35fbc0321245 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 30 Jan 2024 10:04:19 -0500 Subject: [PATCH 033/787] fixed potential deadlock --- libi2pd/Transports.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index c78a8bd0..540bafb4 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -85,18 +85,14 @@ namespace transport isReachable = (bool)router->GetCompatibleTransports (true); } } - - ~Peer () - { - // drop not sent delayed messages - for (auto& it: delayedMessages) - it->Drop (); - } void Done () { for (auto& it: sessions) it->Done (); + // drop not sent delayed messages + for (auto& it: delayedMessages) + it->Drop (); } void SetRouter (std::shared_ptr r) From e40b656ecf8ea4bdbb92c2c5f5c996ffae7aa2d2 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 30 Jan 2024 15:41:57 -0500 Subject: [PATCH 034/787] Drop for tunnel and encrypted messages --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 10 ++++++++-- libi2pd/ECIESX25519AEADRatchetSession.h | 4 ++-- libi2pd/NetDb.cpp | 1 + libi2pd/NetDbRequests.cpp | 1 + libi2pd/TunnelGateway.cpp | 11 +++++++++-- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 3b3ed485..6f56f2e5 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -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 * @@ -1171,7 +1171,7 @@ namespace garlic return m; } - std::shared_ptr WrapECIESX25519MessageForRouter (std::shared_ptr msg, const uint8_t * routerPublicKey) + std::shared_ptr WrapECIESX25519MessageForRouter (std::shared_ptr msg, const uint8_t * routerPublicKey) { // Noise_N, we are Alice, routerPublicKey is Bob's i2p::crypto::NoiseSymmetricState noiseState; @@ -1205,6 +1205,12 @@ namespace garlic htobe32buf (m->GetPayload (), offset); m->len += offset + 4; m->FillI2NPMessageHeader (eI2NPGarlic); + if (msg->onDrop) + { + // move onDrop to the wrapping I2NP messages + m->onDrop = msg->onDrop; + msg->onDrop = nullptr; + } return m; } } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 301f597a..517833e8 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -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 * @@ -246,7 +246,7 @@ namespace garlic }; std::shared_ptr WrapECIESX25519Message (std::shared_ptr msg, const uint8_t * key, uint64_t tag); - std::shared_ptr WrapECIESX25519MessageForRouter (std::shared_ptr msg, const uint8_t * routerPublicKey); + std::shared_ptr WrapECIESX25519MessageForRouter (std::shared_ptr msg, const uint8_t * routerPublicKey); } } diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 0bf7af9d..bedb19f6 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -749,6 +749,7 @@ namespace data if (outbound && inbound) { auto msg = dest->CreateRequestMessage (floodfill, inbound); + msg->onDrop = [this, dest]() { this->m_Requests.SendNextRequest (dest); }; outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0, i2p::garlic::WrapECIESX25519MessageForRouter (msg, floodfill->GetIdentity ()->GetEncryptionPublicKey ())); } diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index 4099f921..3b5f41b6 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -202,6 +202,7 @@ namespace data { LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ()); auto msg = dest->CreateRequestMessage (nextFloodfill, inbound); + msg->onDrop = [this, dest]() { this->SendNextRequest (dest); }; outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0, i2p::garlic::WrapECIESX25519MessageForRouter (msg, nextFloodfill->GetIdentity ()->GetEncryptionPublicKey ())); } diff --git a/libi2pd/TunnelGateway.cpp b/libi2pd/TunnelGateway.cpp index 12e7652f..85ff224e 100644 --- a/libi2pd/TunnelGateway.cpp +++ b/libi2pd/TunnelGateway.cpp @@ -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 * @@ -35,6 +35,13 @@ namespace tunnel if (!m_CurrentTunnelDataMsg) { CreateCurrentTunnelDataMessage (); + if (block.data && block.data->onDrop) + { + // onDrop is called for the first fragment in tunnel message + // that's usually true for short TBMs or lookups + m_CurrentTunnelDataMsg->onDrop = block.data->onDrop; + block.data->onDrop = nullptr; + } messageCreated = true; } @@ -155,7 +162,6 @@ namespace tunnel void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage () { - m_CurrentTunnelDataMsg = nullptr; m_CurrentTunnelDataMsg = NewI2NPTunnelMessage (true); // tunnel endpoint is at least of two tunnel messages size // we reserve space for padding m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE; @@ -223,6 +229,7 @@ namespace tunnel 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; } From 0ca782ed717bc8ad631efd4bf252c1b78894b72b Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 30 Jan 2024 18:02:14 -0500 Subject: [PATCH 035/787] drop unsent messages if session disconnects --- libi2pd/NTCP2.cpp | 2 ++ libi2pd/SSU2Session.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index ad8ef51d..6fe88509 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -373,6 +373,8 @@ namespace transport m_Socket.close (); transports.PeerDisconnected (shared_from_this ()); m_Server.RemoveNTCP2Session (shared_from_this ()); + for (auto& it: m_SendQueue) + it->Drop (); m_SendQueue.clear (); SetSendQueueSize (0); auto remoteIdentity = GetRemoteIdentity (); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index fa6d9eca..9180ccc8 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -262,6 +262,8 @@ namespace transport m_SentHandshakePacket.reset (nullptr); m_SessionConfirmedFragment.reset (nullptr); m_PathChallenge.reset (nullptr); + for (auto& it: m_SendQueue) + it->Drop (); m_SendQueue.clear (); SetSendQueueSize (0); m_SentPackets.clear (); From 2e9f2d4a3b1513797a73f94b1b661d4f9b76bb9b Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 30 Jan 2024 21:52:18 -0500 Subject: [PATCH 036/787] Drop for LeaseSet request --- libi2pd/Destination.cpp | 67 ++++++++++++++++++++++++----------------- libi2pd/Destination.h | 3 +- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index b9555abe..9b173f24 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -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 * @@ -502,38 +502,43 @@ namespace client if (it != m_LeaseSetRequests.end ()) { auto request = it->second; - bool found = false; - if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST) + for (int i = 0; i < num; i++) { - for (int i = 0; i < num; i++) + i2p::data::IdentHash peerHash (buf + 33 + i*32); + if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash)) { - i2p::data::IdentHash peerHash (buf + 33 + i*32); - if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash)) - { - LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); - i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory - } - } - - auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded); - if (floodfill) - { - LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", floodfill->GetIdentHash ().ToBase64 ()); - if (SendLeaseSetRequest (key, floodfill, request)) - found = true; + LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); + i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory } } - if (!found) - { - LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills"); - request->Complete (nullptr); - m_LeaseSetRequests.erase (key); - } + SendNextLeaseSetRequest (key, request); } else LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found"); } + void LeaseSetDestination::SendNextLeaseSetRequest (const i2p::data::IdentHash& key, + std::shared_ptr request) + { + bool found = false; + if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST) + { + auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded); + if (floodfill) + { + LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", floodfill->GetIdentHash ().ToBase64 ()); + if (SendLeaseSetRequest (key, floodfill, request)) + found = true; + } + } + if (!found) + { + LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills"); + request->Complete (nullptr); + m_LeaseSetRequests.erase (key); + } + } + void LeaseSetDestination::HandleDeliveryStatusMessage (uint32_t msgID) { if (msgID == m_PublishReplyToken) @@ -822,14 +827,22 @@ namespace client AddECIESx25519Key (replyKey, replyTag); else AddSessionKey (replyKey, replyTag); - auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest, - request->excluded, request->replyTunnel, replyKey, replyTag, isECIES)); + auto msg = CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, request->replyTunnel, replyKey, replyTag, isECIES); + auto s = shared_from_this (); + msg->onDrop = [s, dest, request]() + { + s->GetService ().post([s, dest, request]() + { + s->SendNextLeaseSetRequest (dest, request); + }); + }; + auto encryptedMsg = WrapMessageForRouter (nextFloodfill, msg); request->outboundTunnel->SendTunnelDataMsgs ( { i2p::tunnel::TunnelMessageBlock { i2p::tunnel::eDeliveryTypeRouter, - nextFloodfill->GetIdentHash (), 0, msg + nextFloodfill->GetIdentHash (), 0, encryptedMsg } }); request->requestTimeoutTimer.expires_from_now (boost::posix_time::seconds(LEASESET_REQUEST_TIMEOUT)); diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 3b395f4d..a066c64c 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -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 * @@ -176,6 +176,7 @@ namespace client void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr requestedBlindedKey = nullptr); bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr nextFloodfill, std::shared_ptr request); + void SendNextLeaseSetRequest (const i2p::data::IdentHash& key, std::shared_ptr request); void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest); void HandleCleanupTimer (const boost::system::error_code& ecode); void CleanupRemoteLeaseSets (); From ffdd5935e90e65300da10164ca72a0de64a52b4a Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 31 Jan 2024 11:46:01 -0500 Subject: [PATCH 037/787] Handle drop of own RouterInfo publishing message --- libi2pd/RouterContext.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index b3c51ca6..40949891 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -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 * @@ -1378,10 +1378,19 @@ namespace i2p uint32_t replyToken; RAND_bytes ((uint8_t *)&replyToken, 4); LogPrint (eLogInfo, "Router: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken); + auto onDrop = [this]() + { + if (m_Service) + m_Service->GetService ().post ([this]() { HandlePublishResendTimer (boost::system::error_code ()); }); + }; if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect? i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ? + { // send directly - i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken)); + auto msg = CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken); + msg->onDrop = onDrop; + i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), msg); + } else { // otherwise through exploratory @@ -1392,6 +1401,7 @@ namespace i2p { // encrypt for floodfill auto msg = CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound); + msg->onDrop = onDrop; outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0, i2p::garlic::WrapECIESX25519MessageForRouter (msg, floodfill->GetIdentity ()->GetEncryptionPublicKey ())); } From 83cb3a1820802a5ddf01fb3de1f0654f9f56e237 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 31 Jan 2024 15:41:21 -0500 Subject: [PATCH 038/787] reduce router unreachable interval --- libi2pd/Profiling.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/Profiling.h b/libi2pd/Profiling.h index 6531e060..ed23fb12 100644 --- a/libi2pd/Profiling.h +++ b/libi2pd/Profiling.h @@ -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 * @@ -35,7 +35,7 @@ namespace data const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3600; // in seconds (1 hour) const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 150; // in seconds (2.5 minutes) const int PEER_PROFILE_PERSIST_INTERVAL = 3300; // in seconds (55 minutes) - const int PEER_PROFILE_UNREACHABLE_INTERVAL = 2*3600; // on seconds (2 hours) + const int PEER_PROFILE_UNREACHABLE_INTERVAL = 480; // in seconds (8 minutes) const int PEER_PROFILE_USEFUL_THRESHOLD = 3; class RouterProfile From 96cf6ca531289328aeda9c8ea7f6eae06b338c57 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 1 Feb 2024 18:14:45 -0500 Subject: [PATCH 039/787] drop earlier if outgoing queue is semi-full --- libi2pd/NTCP2.cpp | 7 ++++++- libi2pd/SSU2Session.cpp | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 6fe88509..76f3a940 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1250,8 +1250,13 @@ namespace transport void NTCP2Session::PostI2NPMessages (std::vector > msgs) { if (m_IsTerminated) return; + bool isSemiFull = m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE/2; for (auto it: msgs) - m_SendQueue.push_back (std::move (it)); + if (isSemiFull && it->onDrop) + it->Drop (); // drop earlier because we can handle it + else + m_SendQueue.push_back (std::move (it)); + if (!m_IsSending) SendQueue (); else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 9180ccc8..12671f4f 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -351,8 +351,12 @@ namespace transport void SSU2Session::PostI2NPMessages (std::vector > msgs) { if (m_State == eSSU2SessionStateTerminated) return; + bool isSemiFull = m_SendQueue.size () > SSU2_MAX_OUTGOING_QUEUE_SIZE/2; for (auto it: msgs) - m_SendQueue.push_back (std::move (it)); + if (isSemiFull && it->onDrop) + it->Drop (); // drop earlier because we can handle it + else + m_SendQueue.push_back (std::move (it)); SendQueue (); if (m_SendQueue.size () > 0) // windows is full From 8f28cee32fa76c87d8b2930a6197732a21f84852 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 1 Feb 2024 18:55:10 -0500 Subject: [PATCH 040/787] drop earlier if delayed queue is semi-full --- libi2pd/Transports.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 5d3027a9..a70e77b4 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -477,7 +477,10 @@ namespace transport } } for (auto& it1: msgs) - it->second.delayedMessages.push_back (it1); + if (sz > MAX_NUM_DELAYED_MESSAGES/2 && it1->onDrop) + it1->Drop (); // drop earlier because we can handle it + else + it->second.delayedMessages.push_back (it1); } else { From 47578b69c621a6d8b6a812530b8a6da31bbd9a9a Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 1 Feb 2024 19:38:12 -0500 Subject: [PATCH 041/787] handle drop of tunnel test message --- libi2pd/TunnelPool.cpp | 74 +++++++++++++++++++++++++++--------------- libi2pd/TunnelPool.h | 4 +-- 2 files changed, 50 insertions(+), 28 deletions(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 5339c9be..93df99be 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -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 * @@ -360,36 +360,58 @@ namespace tunnel } // new tests - std::unique_lock l1(m_OutboundTunnelsMutex); - auto it1 = m_OutboundTunnels.begin (); - std::unique_lock l2(m_InboundTunnelsMutex); - auto it2 = m_InboundTunnels.begin (); - while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ()) + std::vector, std::shared_ptr > > newTests; { - bool failed = false; - if ((*it1)->IsFailed ()) + std::unique_lock l1(m_OutboundTunnelsMutex); + auto it1 = m_OutboundTunnels.begin (); + std::unique_lock l2(m_InboundTunnelsMutex); + auto it2 = m_InboundTunnels.begin (); + while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ()) { - failed = true; - ++it1; - } - if ((*it2)->IsFailed ()) - { - failed = true; - ++it2; - } - if (!failed) - { - uint32_t msgID; - RAND_bytes ((uint8_t *)&msgID, 4); + bool failed = false; + if ((*it1)->IsFailed ()) { - std::unique_lock l(m_TestsMutex); - m_Tests[msgID] = std::make_pair (*it1, *it2); + failed = true; + ++it1; + } + if ((*it2)->IsFailed ()) + { + failed = true; + ++it2; + } + if (!failed) + { + newTests.push_back(std::make_pair (*it1, *it2)); + ++it1; ++it2; } - (*it1)->SendTunnelDataMsgTo ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (), - CreateDeliveryStatusMsg (msgID)); - ++it1; ++it2; } - } + } + for (auto& it: newTests) + { + uint32_t msgID; + RAND_bytes ((uint8_t *)&msgID, 4); + { + std::unique_lock l(m_TestsMutex); + m_Tests[msgID] = it; + } + auto msg = CreateDeliveryStatusMsg (msgID); + auto outbound = it.first; + auto s = shared_from_this (); + msg->onDrop = [msgID, outbound, s]() + { + // if test msg dropped locally it's outbound tunnel to blame + outbound->SetState (eTunnelStateFailed); + { + std::unique_lock l(s->m_TestsMutex); + s->m_Tests.erase (msgID); + } + { + std::unique_lock l(s->m_OutboundTunnelsMutex); + s->m_OutboundTunnels.erase (outbound); + } + }; + outbound->SendTunnelDataMsgTo (it.second->GetNextIdentHash (), it.second->GetNextTunnelID (), msg); + } } void TunnelPool::ManageTunnels (uint64_t ts) diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index c1fd19cd..7cb1f5c9 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -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 * @@ -30,7 +30,7 @@ namespace tunnel const int TUNNEL_POOL_MANAGE_INTERVAL = 10; // in seconds const int TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY = 16; const int TUNNEL_POOL_MAX_OUTBOUND_TUNNELS_QUANTITY = 16; - const int TUNNEL_POOL_MAX_NUM_BUILD_REQUESTS = 2; + const int TUNNEL_POOL_MAX_NUM_BUILD_REQUESTS = 3; class Tunnel; class InboundTunnel; From 7b776666a3dcec3e7237a064c2ce97139e7a86ea Mon Sep 17 00:00:00 2001 From: StormyCloudInc <64628149+WaxySteelWorm@users.noreply.github.com> Date: Sat, 3 Feb 2024 10:21:19 -0600 Subject: [PATCH 042/787] Add files via upload --- .../reseed/admin_at_stormycloud.org.crt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 contrib/certificates/reseed/admin_at_stormycloud.org.crt diff --git a/contrib/certificates/reseed/admin_at_stormycloud.org.crt b/contrib/certificates/reseed/admin_at_stormycloud.org.crt new file mode 100644 index 00000000..ae44521b --- /dev/null +++ b/contrib/certificates/reseed/admin_at_stormycloud.org.crt @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF1zCCA7+gAwIBAgIRAMDqFR09Xuj8ZUu+oetSvAEwDQYJKoZIhvcNAQELBQAw +dTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE +ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxHjAcBgNVBAMM +FWFkbWluQHN0b3JteWNsb3VkLm9yZzAeFw0yNDAxMjUxNDE1MzBaFw0zNDAxMjUx +NDE1MzBaMHUxCzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgx +HjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMR4w +HAYDVQQDDBVhZG1pbkBzdG9ybXljbG91ZC5vcmcwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDbGX+GikPzQXr9zvkrhfO9g0l49KHLNQhUKYqd6T+PfnGo +Fm0d3ZZVVQZ045vWgroOXDGGZZWxUIlb2inRaR2DF1TxN3pPYt59RgY9ZQ9+TL7o +isY91krCRygY8EcAmHIjlfZQ9dBVcL7CfyT0MYZA5Efee9+NDHSewTfQP9T2faIE +83Fcyd93a2mIHYjKUbJnojng/wgsy8srbsEuuTok4MIQmDj+B5nz+za2FgI0/ydh +srlMt4aGJF4/DIem9z9d0zBCOkwrmtFIzjNF1mOSA8ES4m5YnKA/y9rZlRidLPGu +prbXhPVnqHeOnHMz2QCw1wbVo504kl0bMqyEz2tVWsO9ep7iZoQs2xkFAEaegYNT +QLUpwVGlyuq3wXXwopFRffOSimGSazICwWI6j+K0pOtgefNJaWrqKYvtkj1SbK2L +LBNUIENz6VnB7KPRckuX6zxC8PpOiBK9BcftfO+xAz/wC6qq3riBPw30KKSym0nC +Zp5KciDn4Phtw9PGq8Bkl8SyWl0jtFnfTB1tzJkisf2qKcNHaFTEe2JW763YLbh/ +AU+8X8evFu40qLgvOgKoyy5DLy6i8zetX+3t9K0Fxt9+Vzzq6lm5V/RS8iIPPn+M +q1/3Z5kD0KQBG9h/Gl8BH+lB71ZxPAOZ3SMu8DJZcxBLVmDWqQPCr5CKnoz0swID +AQABo2IwYDAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG +AQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wHgYDVR0OBBcEFWFkbWluQHN0b3JteWNs +b3VkLm9yZzANBgkqhkiG9w0BAQsFAAOCAgEARWOJ69vTHMneSXYscha+4Ytjg0RM +faewJNEGj8qy/Qvh9si2bWYNPRK6BlbHFS7pRYBLAnhaeLBGVv1CCR6GUMMe74zQ +UuMeAoWU6qMDmB3GfYoZJh8sIxpwHqyJeTdeccRbZ4sX4F6u3IHPXYiU/AgbYqH7 +pYXQg2lCjXZYaDFAlEf5SlYUDOhhXe5kR8Edhlrsu32/JzA1DQK0JjxKCBp+DQmA +ltdOpQtAg03fHP4ssdj7VvjIDl28iIlATwBvHrdNm7T0tYWn6TWhvxbRqvfTxfaH +MvxnPdIJwNP4/9TyQkwjwHb1h+ucho3CnxI/AxspdOvT1ElMhP6Ce6rcS9pk11Rl +x0ChsqpWwDg7KYpg0qZFSKCTBp4zBq9xoMJ6BQcgMfyl736WbsCzFTEyfifp8beg +NxUa/Qk7w7cuSPGyMIKNOmOR7FLlFbtocy8sXVsUQdqnp/edelufdNe39U9uNtY6 +yoXI9//Tc6NgOwy2Oyia0slZ5qHRkB7e4USXMRzJ3p4q9eCVKjAJs81Utp7O2U+9 +vhbhwWP8CAnNTT1E5WS6EKtfrdqF7wjkV+noPGLDGmrXi01J1fSMAjMfVO+7/LOL +UN+G4ybKWnEhhOO27yidN8Xx6UrCS23DBlPPQAeA74dTsTExiOxf1o1EXzcQiMyO +LAj3/Ojbi1xkWhI= +-----END CERTIFICATE----- From de2b0f6e0986c16d394e1d9b34dcd10266d96e2f Mon Sep 17 00:00:00 2001 From: StormyCloudInc <64628149+WaxySteelWorm@users.noreply.github.com> Date: Sat, 3 Feb 2024 10:24:11 -0600 Subject: [PATCH 043/787] Update Config.cpp --- libi2pd/Config.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 4deb59ac..18cc69ee 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -223,7 +223,8 @@ namespace config { "https://i2p.ghativega.in/," "https://i2p.novg.net/," "https://reseed.is.prestium.org/," - "https://reseed.us.prestium.org/" + "https://reseed.us.prestium.org/", + "https://reseed.stormycloud.org/" ), "Reseed URLs, separated by comma") ("reseed.yggurls", value()->default_value( "http://[324:71e:281a:9ed3::ace]:7070/," From ce356378667fac05b192ec5e9ae1e4c7fbf7bc31 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 4 Feb 2024 15:45:22 -0500 Subject: [PATCH 044/787] handle drop of tunnel build message --- libi2pd/Tunnel.cpp | 14 ++++++++++---- libi2pd/Tunnel.h | 14 +++++++++++--- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index b8e17920..b578217f 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -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 * @@ -90,7 +90,13 @@ namespace tunnel hop = hop->prev; } msg->FillI2NPMessageHeader (m_Config->IsShort () ? eI2NPShortTunnelBuild : eI2NPVariableTunnelBuild); - + auto s = shared_from_this (); + msg->onDrop = [s]() + { + LogPrint (eLogInfo, "I2NP: Tunnel ", s->GetTunnelID (), " request was not sent"); + s->SetState (i2p::tunnel::eTunnelStateBuildFailed); + }; + // send message if (outboundTunnel) { @@ -246,7 +252,7 @@ namespace tunnel { if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive EncryptTunnelMsg (msg, msg); - msg->from = shared_from_this (); + msg->from = GetSharedFromThis (); m_Endpoint.HandleDecryptedTunnelDataMsg (msg); } @@ -261,7 +267,7 @@ namespace tunnel if (msg) { m_NumReceivedBytes += msg->GetLength (); - msg->from = shared_from_this (); + msg->from = GetSharedFromThis (); HandleI2NPMessage (msg); } } diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index e6e3c3a5..47ff0465 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -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 * @@ -65,7 +65,8 @@ namespace tunnel class OutboundTunnel; class InboundTunnel; - class Tunnel: public TunnelBase + class Tunnel: public TunnelBase, + public std::enable_shared_from_this { struct TunnelHop { @@ -155,7 +156,7 @@ namespace tunnel i2p::data::IdentHash m_EndpointIdentHash; }; - class InboundTunnel: public Tunnel, public std::enable_shared_from_this + class InboundTunnel: public Tunnel { public: @@ -167,6 +168,13 @@ namespace tunnel // override TunnelBase void Cleanup () override { m_Endpoint.Cleanup (); }; + protected: + + std::shared_ptr GetSharedFromThis () + { + return std::static_pointer_cast(shared_from_this ()); + } + private: TunnelEndpoint m_Endpoint; From be815804e66c878c81cb802193b589204d66005b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 5 Feb 2024 15:44:17 -0500 Subject: [PATCH 045/787] expire transit tunnel is not sent further --- libi2pd/I2NPProtocol.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index ebd5f8d6..70cefbdc 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -584,13 +584,14 @@ namespace i2p memcpy (ivKey, noiseState.m_CK , 32); // check if we accept this tunnel + std::shared_ptr transitTunnel; uint8_t retCode = 0; if (!i2p::context.AcceptsTunnels () || i2p::context.IsHighCongestion ()) retCode = 30; if (!retCode) { // create new transit tunnel - auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( + 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), @@ -624,11 +625,22 @@ namespace i2p 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? { @@ -652,9 +664,12 @@ namespace i2p } } else - transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, - CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len, - bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + { + 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; @@ -714,7 +729,11 @@ namespace i2p return msg; } else - return CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ()); + { + auto newMsg = CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ()); + if (msg->onDrop) newMsg->onDrop = msg->onDrop; + return newMsg; + } } std::shared_ptr CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType, From f64b136f5a8426c304e38946c5cf8cfa62de5281 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 6 Feb 2024 13:37:08 -0500 Subject: [PATCH 046/787] remove prestium reseeds --- .../reseed/null_at_i2pmail.org.crt | 33 ------------------ .../reheatedburger_at_protonmail.com.crt | 34 ------------------- libi2pd/Config.cpp | 4 +-- 3 files changed, 1 insertion(+), 70 deletions(-) delete mode 100644 contrib/certificates/reseed/null_at_i2pmail.org.crt delete mode 100644 contrib/certificates/reseed/reheatedburger_at_protonmail.com.crt diff --git a/contrib/certificates/reseed/null_at_i2pmail.org.crt b/contrib/certificates/reseed/null_at_i2pmail.org.crt deleted file mode 100644 index d736a95e..00000000 --- a/contrib/certificates/reseed/null_at_i2pmail.org.crt +++ /dev/null @@ -1,33 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFyDCCA7CgAwIBAgIRAO8lBnTo+hlvglQwug2jHZkwDQYJKoZIhvcNAQELBQAw -cDELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE -ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGTAXBgNVBAMM -EG51bGxAaTJwbWFpbC5vcmcwHhcNMjMwOTIxMjIzMTM2WhcNMzMwOTIxMjIzMTM2 -WjBwMQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYD -VQQKExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEZMBcGA1UE -AwwQbnVsbEBpMnBtYWlsLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC -ggIBAMMpAvaHwzuZZ6qelRU4jcgpuAIZFH++F1Te4b1t02pRfnQ0Eeh04VC1JxO0 -XjUr1/iszEyvrI4+AdxaobDyRFPylkOLtfec4d2ciDc1cupj6y2vyYhMVN31rrvE -ve7sKoTHJ5Dx+UPGOVZZsSsmK9TXIU23W2bo7k2VnjVBXdWZyNE4twfTYCosDnYA -1HIEaIUFVv+COqw2pktxkMmfUAlnDLeVSfsAzEr37K+x0Xk5hO8m6GWQx0NRjjYp -gyEcFhWAJjAYaF3gUVR9rVVky1OeFhZgxE/KzVrW7uc84ZCMKITEPwT0qqIpsTJp -486YXzuPSc+ef78cKSQf5992l7imySJ24I/5H73HkovGAFGZdwvl6V6Ta5YqO7RR -gVDOL1EIVUnMCqFBCE6RmyZqXBVrv4Cacdc6lZ4fj42SRtWZfe6rNCpJzTRtbOyW -DBmYpK6q/jddfqI1sX0PXIn9U+Rod5Z4uz82PAjhamqyr5fpAnoQxKppBvQ3tNfn -KQhmP73Hdpvl24pRyQLBIRUL86i7TPBBn7n3XZlQfXP7lp8+KJYLkL2/zCVDrwLX -kC9hRIxCU9bZbXlkRE2R/PrK53LZecjk2KcgINA4ZlguNgze/Qj8BXelUF4izbpV -bTSvniTM46AECvjDcICAOky9Ku4RnmUJxQVf3ahDEuso7/N7AgMBAAGjXTBbMA4G -A1UdDwEB/wQEAwIChDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDwYD -VR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQbnVsbEBpMnBtYWlsLm9yZzANBgkqhkiG -9w0BAQsFAAOCAgEAEUfYJTdDH7uCojnpF0Gs2tXxPJ22UhdqEsXfqR7KhhmmApss -q5kiiPIYoy5T/4IM7NVyeeJAMYwQsdJjwZ4QyxLBb9EqMS2krREcPZNRfFzBr2Wj -EBhJEYTnbIn4docwJWyXsJVG0CqFXPF1qGd0Sc2u87yj2xZNTnloWKAEQAO7DE39 -gWfDH6slM/3h3WD3Mjuk7JoYSYmBfvvm2hkBbC6lzD7XY7rdSmIUwJ050e9UrJaV -La51dd5r4q8d1cHrVUwLiACAaXJ15AEqUDLHQcvKvyfhkabwRy+v0wsodSMgSMEH -xA+kGhkIW7yV7o2exYOYypHCca3IA+pimMpEseNNrHSwbHOMfauiN7jiZLEPg6D6 -a8XwK7qmMYUq7j6QWuIqI81o29WZRf4LZ0GFoVce+e5VxkVKSItKcJoedIAp1ML8 -NhFwd9s/nqWidu/StscEEbGzz6ZuDXwshERXC0QR8HjHEPi4U8220juf4cxUahxK -heEU91l7VksSZYRUN98h28vovGcukLcnVoLj5H/+Z4r/BgxMrOUJKetxf8fU7FjO -j1U6XV36tGi+IOwYQb9D5fTVafC3hHkuUIjlOdUGYadse98ILhn9kaNtqkBtk/EU -vK+McnrEv7tcKrbvYEop/KaUayhjFiL+wGWnpxt7gLhIiavnIeUyD7acltw= ------END CERTIFICATE----- diff --git a/contrib/certificates/reseed/reheatedburger_at_protonmail.com.crt b/contrib/certificates/reseed/reheatedburger_at_protonmail.com.crt deleted file mode 100644 index d14c5fe1..00000000 --- a/contrib/certificates/reseed/reheatedburger_at_protonmail.com.crt +++ /dev/null @@ -1,34 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIF7zCCA9egAwIBAgIRANVB/+wEuXS0Ttoh5teJt90wDQYJKoZIhvcNAQELBQAw -fTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE -ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxJjAkBgNVBAMM -HXJlaGVhdGVkYnVyZ2VyQHByb3Rvbm1haWwuY29tMB4XDTIzMDkyMTE4MDAyOVoX -DTMzMDkyMTE4MDAyOVowfTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYD -VQQJEwJYWDEeMBwGA1UEChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQL -EwNJMlAxJjAkBgNVBAMMHXJlaGVhdGVkYnVyZ2VyQHByb3Rvbm1haWwuY29tMIIC -IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuNwmiIY3MLSBS5sL5PXRDVK6 -MoSNw4qx0o8nDHvVBxNtzgc0/qjYvsuUggY0tZbPpxhML6GHd4qo7Z3Ip1x0MxhI -Ao5MJaflaEdm4+HeMy0IE3aU73KRUwp+nF3cUHZdlps+9mtYs4oncVEWkFQwGsgt -4yrLtXf6PmPWfFH28ffeaev90e+hdhQpTvr54Ewx6NTaMQr8mkhXL2utvPpjnPM5 -UAhOeJCMgfhLzgS4rahG0O8CQMtH5gKZ+6zjoSRatnjj0j1mBO7+e1TL5O7dVS9k -P83tmkIDDl4tXBzXr9aXQMJstbM2CEvinVcCsR74GjPcg4iB0Ift71Dx7oGKI06t -3bSvll0GZm2mFhIba/4q6f4oAJ2aeq6ejt1Kcm8g5cxtwrRZnXv5JXHZqba3y8J5 -zWaRHzhc9tyEqRBRkc6c7xMdZQ31iJ6TlxUT8vAJ1N7OnX87oHrCjwyikpyOen4r -Uvv1Ge054XPTeoHz+Jyt34t71ty1W13uPHpuvtPVR9MfgGrxd4Z9+LWvAjmMbFsZ -lC3Ll+94nUk+O0puU6KisuCGP4hCtdEtebkIqT8zo8LicLAYUMjX7KwnS7681Cu1 -sY2mB2oZAytN9Zy42oOoNeY5x39kxfwuut/2E1kxKX75O0bwfIXr611abCKc3bbz -euMrIsaB/2VFp9nAah8CAwEAAaNqMGgwDgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQW -MBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCYGA1UdDgQf -BB1yZWhlYXRlZGJ1cmdlckBwcm90b25tYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOC -AgEATuHi2Yz52OK7e+sKVdHu2KrSLCGm98BG1UIMHFi3WRBTOFyp+lZ519bJ1rFj -tmP9E1a+k/vlbc7FbV4PcV6HJYfGEv/ImtJsEnrzbhrQphC1zMFv7q6JCTUbAzl6 -ySlJ++mVxQ6AzPNH3TQgL1wPKuLh76/Y4053fg+NI3PmzzhkTUheVDkg0/a9ENSf -xMnCa3fIm869735qHk67QlikFvAfWwc4zT1Ncwodh8G4+oX0GFzIl+OZaM1GTMuD -UCcFKoqwtjyLCr22xNk8CfyiExPJXQG1HzEvDcxyoxQtnh9occR9PgqXySz26/NM -XDyM+l4utLMGBcVY4x9fksRiaWEfxiygYOxY9zDl6clh6S10b3CLut4UMiS1RTtE -Mjx2BZN3p0nxpT2leJdGxtBPGrvxuiCOEmTbOMLc3DQtppXO97B3dVMtJ5Ee8Y6p -Tq/8eiHI6eQXat6dgFT5X16vzF7w7XO7fAxuqk4Kx1D1aTVyikdo+Fcdg44dWOjq -NZu8VcCzZij/Dfjlce6t6h8D+wvDD8AkiivaDljpvbNDx/QQlQXFgH98TZA8Rnvr -QcyNNATfz+1yQUiyO6Lrjaw64OJwXYX/llgnDC+qQpP6kqZabi2TsG0EVPukVvr9 -0HyAUu4lnXtTIDq2yPNenegCloqDL1ZQdaYd2XIItnfZdTY= ------END CERTIFICATE----- diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 18cc69ee..b2ad7a17 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -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 * @@ -222,8 +222,6 @@ namespace config { "https://www2.mk16.de/," "https://i2p.ghativega.in/," "https://i2p.novg.net/," - "https://reseed.is.prestium.org/," - "https://reseed.us.prestium.org/", "https://reseed.stormycloud.org/" ), "Reseed URLs, separated by comma") ("reseed.yggurls", value()->default_value( From c01fd3299ffb23f0497957ac6f10d8564a4fd7e4 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 6 Feb 2024 18:51:59 -0500 Subject: [PATCH 047/787] handle drop of destination publish msg --- libi2pd/Destination.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 9b173f24..ef0d5db3 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -626,6 +626,15 @@ namespace client LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ()); RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4); auto msg = WrapMessageForRouter (floodfill, i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound)); + auto s = shared_from_this (); + msg->onDrop = [s]() + { + s->GetService ().post([s]() + { + s->m_PublishConfirmationTimer.cancel (); + s->HandlePublishConfirmationTimer (boost::system::error_code()); + }); + }; m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer, shared_from_this (), std::placeholders::_1)); @@ -642,7 +651,7 @@ namespace client m_PublishReplyToken = 0; if (GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) { - LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again"); + LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds or failed. will try again"); Publish (); } else @@ -827,7 +836,9 @@ namespace client AddECIESx25519Key (replyKey, replyTag); else AddSessionKey (replyKey, replyTag); - auto msg = CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, request->replyTunnel, replyKey, replyTag, isECIES); + + auto msg = WrapMessageForRouter (nextFloodfill, + CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, request->replyTunnel, replyKey, replyTag, isECIES)); auto s = shared_from_this (); msg->onDrop = [s, dest, request]() { @@ -836,13 +847,12 @@ namespace client s->SendNextLeaseSetRequest (dest, request); }); }; - auto encryptedMsg = WrapMessageForRouter (nextFloodfill, msg); request->outboundTunnel->SendTunnelDataMsgs ( { i2p::tunnel::TunnelMessageBlock { i2p::tunnel::eDeliveryTypeRouter, - nextFloodfill->GetIdentHash (), 0, encryptedMsg + nextFloodfill->GetIdentHash (), 0, msg } }); request->requestTimeoutTimer.expires_from_now (boost::posix_time::seconds(LEASESET_REQUEST_TIMEOUT)); From c158bbe90a7c502b9a5fc23d6a8218bf7372b3d3 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 7 Feb 2024 19:43:29 -0500 Subject: [PATCH 048/787] send frame when it exceeds 16K --- libi2pd/NTCP2.cpp | 3 +++ libi2pd/NTCP2.h | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 76f3a940..0dbccbca 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1152,10 +1152,13 @@ namespace transport msgs.push_back (msg); s += (len + 3); m_SendQueue.pop_front (); + if (s >= NTCP2_SEND_AFTER_FRAME_SIZE) + break; // send frame right a way } else if (len + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) { LogPrint (eLogError, "NTCP2: I2NP message of size ", len, " can't be sent. Dropped"); + msg->Drop (); m_SendQueue.pop_front (); } else diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index ba1380c3..1eac23f0 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -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 * @@ -28,6 +28,7 @@ namespace transport { const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519; + const size_t NTCP2_SEND_AFTER_FRAME_SIZE = 16386; // send frame when exceeds this size const size_t NTCP2_SESSION_REQUEST_MAX_SIZE = 287; const size_t NTCP2_SESSION_CREATED_MAX_SIZE = 287; const int NTCP2_MAX_PADDING_RATIO = 6; // in % From 586695673b6b6e8fc9e6d3a17d963da196e98b71 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 8 Feb 2024 18:48:10 -0500 Subject: [PATCH 049/787] correct log message for next netdb request --- libi2pd/NetDbRequests.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index 3b5f41b6..4893fa1b 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -189,6 +189,7 @@ namespace data direct = false; // floodfill can't be reached directly if (direct) { + LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " directly"); auto msg = dest->CreateRequestMessage (nextFloodfill->GetIdentHash ()); msg->onDrop = [this, dest]() { this->SendNextRequest (dest); }; i2p::transport::transports.SendMessage (nextFloodfill->GetIdentHash (), msg); @@ -200,7 +201,7 @@ namespace data auto inbound = pool->GetNextInboundTunnel (); if (nextFloodfill && outbound && inbound) { - LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ()); + LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " through tunnels"); auto msg = dest->CreateRequestMessage (nextFloodfill, inbound); msg->onDrop = [this, dest]() { this->SendNextRequest (dest); }; outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0, From f98027755281c4d168bd4843b1850ce7ceb2cfc6 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 8 Feb 2024 19:55:54 -0500 Subject: [PATCH 050/787] don't flood failed router --- libi2pd/NetDb.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index bedb19f6..f2166bf0 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -226,7 +226,8 @@ namespace data bool NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len) { bool updated; - AddRouterInfo (ident, buf, len, updated); + if (!AddRouterInfo (ident, buf, len, updated)) + updated = false; return updated; } @@ -874,7 +875,7 @@ namespace data } else // RouterInfo { - LogPrint (eLogDebug, "NetDb: Store request: RouterInfo"); + LogPrint (eLogDebug, "NetDb: Store request: RouterInfo ", ident.ToBase64()); size_t size = bufbe16toh (buf + offset); offset += 2; if (size > MAX_RI_BUFFER_SIZE || size > len - offset) From 1b23aa2d7b7e4696713f7ce0a4d90e1a92baee85 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 8 Feb 2024 21:44:12 -0500 Subject: [PATCH 051/787] increase request timeout --- libi2pd/NetDb.cpp | 2 +- libi2pd/NetDbRequests.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index f2166bf0..f3822997 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -149,7 +149,7 @@ namespace data if (!i2p::transport::transports.IsOnline ()) continue; // don't manage netdb when offline uint64_t ts = i2p::util::GetSecondsSinceEpoch (); - if (ts - lastManageRequest >= 15 || ts + 15 < lastManageRequest) // manage requests every 15 seconds + if (ts - lastManageRequest >= MANAGE_REQUESTS_INTERVAL || ts + MANAGE_REQUESTS_INTERVAL < lastManageRequest) // manage requests every 15 seconds { m_Requests.ManageRequests (); lastManageRequest = ts; diff --git a/libi2pd/NetDbRequests.h b/libi2pd/NetDbRequests.h index 47a5d481..25c102de 100644 --- a/libi2pd/NetDbRequests.h +++ b/libi2pd/NetDbRequests.h @@ -21,8 +21,9 @@ namespace i2p namespace data { const size_t MAX_NUM_REQUEST_ATTEMPTS = 7; + const uint64_t MANAGE_REQUESTS_INTERVAL = 15; // in seconds const uint64_t MIN_REQUEST_TIME = 5; // in seconds - const uint64_t MAX_REQUEST_TIME = 60; // in seconds + const uint64_t MAX_REQUEST_TIME = MAX_NUM_REQUEST_ATTEMPTS*MANAGE_REQUESTS_INTERVAL; class RequestedDestination { From 7dd9a7a0afc0acfad81421ba681fc889ea08a8ce Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 8 Feb 2024 21:45:57 -0500 Subject: [PATCH 052/787] added CheckLogLevel --- libi2pd/Log.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/libi2pd/Log.h b/libi2pd/Log.h index 1ec0c5fe..0164ea4f 100644 --- a/libi2pd/Log.h +++ b/libi2pd/Log.h @@ -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 * @@ -87,8 +87,8 @@ namespace log { Log (); ~Log (); - LogType GetLogType () { return m_Destination; }; - LogLevel GetLogLevel () { return m_MinLevel; }; + LogType GetLogType () const { return m_Destination; }; + LogLevel GetLogLevel () const { return m_MinLevel; }; void Start (); void Stop (); @@ -160,6 +160,11 @@ namespace log { } // log } // i2p +inline bool CheckLogLevel (LogLevel level) noexcept +{ + return level <= i2p::log::Logger().GetLogLevel (); +} + /** internal usage only -- folding args array to single string */ template void LogPrint (std::stringstream& s, TValue&& arg) noexcept @@ -185,9 +190,7 @@ void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept template void LogPrint (LogLevel level, TArgs&&... args) noexcept { - i2p::log::Log &log = i2p::log::Logger(); - if (level > log.GetLogLevel ()) - return; + if (!CheckLogLevel (level)) return; // fold message to single string std::stringstream ss; @@ -200,7 +203,7 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept auto msg = std::make_shared(level, std::time(nullptr), std::move(ss).str()); msg->tid = std::this_thread::get_id(); - log.Append(msg); + i2p::log::Logger().Append(msg); } /** From 592d6ae4f47c7f1647e3b61862d28674fac882ad Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 8 Feb 2024 21:56:25 -0500 Subject: [PATCH 053/787] check log level before calculating base32 or base64 of ident --- libi2pd/NetDb.cpp | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index f3822997..026ae53e 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -262,10 +262,12 @@ namespace data return nullptr; } } - LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64()); + if (CheckLogLevel (eLogInfo)) + LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64()); if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated { - LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64()); + if (CheckLogLevel (eLogDebug)) + LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64()); std::lock_guard l(m_FloodfillsMutex); if (wasFloodfill) m_Floodfills.Remove (r->GetIdentHash ()); @@ -280,7 +282,8 @@ namespace data } else { - LogPrint (eLogDebug, "NetDb: RouterInfo is older: ", ident.ToBase64()); + if (CheckLogLevel (eLogDebug)) + LogPrint (eLogDebug, "NetDb: RouterInfo is older: ", ident.ToBase64()); updated = false; } } @@ -297,7 +300,8 @@ namespace data } if (inserted) { - LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64()); + if (CheckLogLevel (eLogInfo)) + LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64()); if (r->IsFloodfill () && r->IsEligibleFloodfill ()) { if (m_Floodfills.GetSize () < NETDB_NUM_FLOODFILLS_THRESHOLD || @@ -338,10 +342,11 @@ namespace data if(it->second->GetExpirationTime() < expires) { it->second->Update (buf, len, false); // signature is verified already - LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase32()); + if (CheckLogLevel (eLogInfo)) + LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase32()); updated = true; } - else + else if (CheckLogLevel (eLogDebug)) LogPrint(eLogDebug, "NetDb: LeaseSet is older: ", ident.ToBase32()); } else @@ -352,7 +357,8 @@ namespace data auto leaseSet = std::make_shared (buf, len, false); // we don't need leases in netdb if (leaseSet->IsValid ()) { - LogPrint (eLogInfo, "NetDb: LeaseSet added: ", ident.ToBase32()); + if (CheckLogLevel (eLogInfo)) + LogPrint (eLogInfo, "NetDb: LeaseSet added: ", ident.ToBase32()); m_LeaseSets[ident] = leaseSet; updated = true; } @@ -376,7 +382,8 @@ namespace data i2p::util::GetSecondsSinceEpoch () + NETDB_EXPIRATION_TIMEOUT_THRESHOLD > leaseSet->GetPublishedTimestamp ()) { // TODO: implement actual update - LogPrint (eLogInfo, "NetDb: LeaseSet2 updated: ", ident.ToBase32()); + if (CheckLogLevel (eLogInfo)) + LogPrint (eLogInfo, "NetDb: LeaseSet2 updated: ", ident.ToBase32()); m_LeaseSets[ident] = leaseSet; return true; } @@ -863,19 +870,22 @@ namespace data { if (storeType == NETDB_STORE_TYPE_LEASESET) // 1 { - LogPrint (eLogDebug, "NetDb: Store request: LeaseSet for ", ident.ToBase32()); + if (CheckLogLevel (eLogDebug)) + LogPrint (eLogDebug, "NetDb: Store request: LeaseSet for ", ident.ToBase32()); updated = AddLeaseSet (ident, buf + offset, len - offset); } else // all others are considered as LeaseSet2 { - LogPrint (eLogDebug, "NetDb: Store request: LeaseSet2 of type ", int(storeType), " for ", ident.ToBase32()); + if (CheckLogLevel (eLogDebug)) + LogPrint (eLogDebug, "NetDb: Store request: LeaseSet2 of type ", int(storeType), " for ", ident.ToBase32()); updated = AddLeaseSet2 (ident, buf + offset, len - offset, storeType); } } } else // RouterInfo { - LogPrint (eLogDebug, "NetDb: Store request: RouterInfo ", ident.ToBase64()); + if (CheckLogLevel (eLogDebug)) + LogPrint (eLogDebug, "NetDb: Store request: RouterInfo ", ident.ToBase64()); size_t size = bufbe16toh (buf + offset); offset += 2; if (size > MAX_RI_BUFFER_SIZE || size > len - offset) From d96803a2909a966bad9cc0599a46191c982dce84 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 9 Feb 2024 15:24:48 -0500 Subject: [PATCH 054/787] always request through tunnels in case of restricted routes --- libi2pd/NetDb.cpp | 1 + libi2pd/Transports.cpp | 25 ++++++++++++++++--------- libi2pd/Transports.h | 2 +- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 026ae53e..e8c92658 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -730,6 +730,7 @@ namespace data void NetDb::RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete, bool direct) { + if (direct && i2p::transport::transports.RoutesRestricted ()) direct = false; // always use tunnels for restricted routes auto dest = m_Requests.CreateRequest (destination, false, direct, requestComplete); // non-exploratory if (!dest) { diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index a70e77b4..0afe47a1 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -1015,18 +1015,25 @@ namespace transport } } - void Transports::RestrictRoutesToRouters(std::set routers) + void Transports::RestrictRoutesToRouters(const std::set& routers) { - std::unique_lock lock(m_TrustedRoutersMutex); + std::lock_guard lock(m_TrustedRoutersMutex); m_TrustedRouters.clear(); for (const auto & ri : routers ) m_TrustedRouters.push_back(ri); } - bool Transports::RoutesRestricted() const { - std::unique_lock famlock(m_FamilyMutex); - std::unique_lock routerslock(m_TrustedRoutersMutex); - return m_TrustedFamilies.size() > 0 || m_TrustedRouters.size() > 0; + bool Transports::RoutesRestricted() const + { + { + std::lock_guard routerslock(m_TrustedRoutersMutex); + if (!m_TrustedRouters.empty ()) return true; + } + { + std::lock_guard famlock(m_FamilyMutex); + if (!m_TrustedFamilies.empty ()) return true; + } + return false; } /** XXX: if routes are not restricted this dies */ @@ -1050,7 +1057,7 @@ namespace transport return i2p::data::netdb.GetRandomRouterInFamily(fam); } { - std::unique_lock l(m_TrustedRoutersMutex); + std::lock_guard l(m_TrustedRoutersMutex); auto sz = m_TrustedRouters.size(); if (sz) { @@ -1067,12 +1074,12 @@ namespace transport bool Transports::IsRestrictedPeer(const i2p::data::IdentHash & ih) const { { - std::unique_lock l(m_TrustedRoutersMutex); + std::lock_guard l(m_TrustedRoutersMutex); for (const auto & r : m_TrustedRouters ) if ( r == ih ) return true; } { - std::unique_lock l(m_FamilyMutex); + std::lock_guard l(m_FamilyMutex); auto ri = i2p::data::netdb.FindRouter(ih); for (const auto & fam : m_TrustedFamilies) if(ri->IsFamily(fam)) return true; diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 540bafb4..206b0256 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -165,7 +165,7 @@ namespace transport /** restrict routes to use only these router families for first hops */ void RestrictRoutesToFamilies(const std::set& families); /** restrict routes to use only these routers for first hops */ - void RestrictRoutesToRouters(std::set routers); + void RestrictRoutesToRouters(const std::set& routers); bool IsRestrictedPeer(const i2p::data::IdentHash & ident) const; From 36dbc15bca1a41f7f764a15e2c272394aa06154d Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 9 Feb 2024 18:08:51 -0500 Subject: [PATCH 055/787] keep SSU2 socket open even if failed to bind --- libi2pd/SSU2.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 0ebeab6d..3e0583ea 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -258,13 +258,22 @@ namespace transport socket.set_option (boost::asio::ip::v6_only (true)); socket.set_option (boost::asio::socket_base::receive_buffer_size (SSU2_SOCKET_RECEIVE_BUFFER_SIZE)); socket.set_option (boost::asio::socket_base::send_buffer_size (SSU2_SOCKET_SEND_BUFFER_SIZE)); + } + catch (std::exception& ex ) + { + LogPrint (eLogCritical, "SSU2: Failed to open socket on ", localEndpoint.address (), ": ", ex.what()); + ThrowFatal ("Unable to start SSU2 transport on ", localEndpoint.address (), ": ", ex.what ()); + return socket; + } + try + { socket.bind (localEndpoint); LogPrint (eLogInfo, "SSU2: Start listening on ", localEndpoint); } catch (std::exception& ex ) { - LogPrint (eLogCritical, "SSU2: Failed to bind to ", localEndpoint, ": ", ex.what()); - ThrowFatal ("Unable to start SSU2 transport on ", localEndpoint, ": ", ex.what ()); + LogPrint (eLogWarning, "SSU2: Failed to bind to ", localEndpoint, ": ", ex.what(), ". Actual endpoint is ", socket.local_endpoint ()); + // we can continue without binding being firewalled } return socket; } From adba3987f84f67f6ab8b2be8762f51ff29154a71 Mon Sep 17 00:00:00 2001 From: Vort Date: Sat, 10 Feb 2024 17:10:21 +0200 Subject: [PATCH 056/787] logging fixes --- libi2pd/NTCP2.cpp | 2 +- libi2pd/RouterInfo.cpp | 2 +- libi2pd/SSU2Session.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 0dbccbca..19609b0b 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -381,7 +381,7 @@ namespace transport if (remoteIdentity) { LogPrint (eLogDebug, "NTCP2: Session with ", GetRemoteEndpoint (), - " (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") terminated"); + " (", i2p::data::GetIdentHashAbbreviation (remoteIdentity->GetIdentHash ()), ") terminated"); } else { diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 7cde7c33..a034691a 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -131,7 +131,7 @@ namespace data m_BufferLen = s.tellg (); if (m_BufferLen < 40 || m_BufferLen > MAX_RI_BUFFER_SIZE) { - LogPrint(eLogError, "RouterInfo: File", fullPath, " is malformed"); + LogPrint(eLogError, "RouterInfo: File ", fullPath, " is malformed"); return false; } s.seekg(0, std::ios::beg); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 12671f4f..4015dcac 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -277,7 +277,7 @@ namespace transport if (remoteIdentity) { LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), - " (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") terminated"); + " (", i2p::data::GetIdentHashAbbreviation (remoteIdentity->GetIdentHash ()), ") terminated"); } else { From 158160f5c0256bd91bb68c5550d5fe97150dcda2 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 10 Feb 2024 20:03:36 -0500 Subject: [PATCH 057/787] common code for SOCKS5 proxy connectivity --- libi2pd/NTCP2.cpp | 119 ++++------------------------ libi2pd/NTCP2.h | 3 +- libi2pd/SSU2.h | 1 + libi2pd/Socks5.h | 154 +++++++++++++++++++++++++++++++++++++ libi2pd/TransportSession.h | 11 +-- 5 files changed, 170 insertions(+), 118 deletions(-) create mode 100644 libi2pd/Socks5.h diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 19609b0b..58a1c539 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -19,9 +19,10 @@ #include "RouterContext.h" #include "Transports.h" #include "NetDb.hpp" -#include "NTCP2.h" #include "HTTP.h" #include "util.h" +#include "Socks5.h" +#include "NTCP2.h" #if defined(__linux__) && !defined(_NETINET_IN_H) #include @@ -1728,47 +1729,18 @@ namespace transport case eSocksProxy: { // TODO: support username/password auth etc - static const uint8_t buff[3] = {SOCKS5_VER, 0x01, 0x00}; - boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(), - [] (const boost::system::error_code & ec, std::size_t transferred) - { - (void) transferred; - if(ec) - { - LogPrint(eLogWarning, "NTCP2: SOCKS5 write error ", ec.message()); - } - }); - auto readbuff = std::make_shared >(2); - boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 2), - [this, readbuff, timer, conn](const boost::system::error_code & ec, std::size_t transferred) - { - if(ec) - { - LogPrint(eLogError, "NTCP2: SOCKS5 read error ", ec.message()); - timer->cancel(); - conn->Terminate(); - return; - } - else if(transferred == 2) - { - if((*readbuff)[1] == 0x00) - { - AfterSocksHandshake(conn, timer); - return; - } - else if ((*readbuff)[1] == 0xff) - { - LogPrint(eLogError, "NTCP2: SOCKS5 proxy rejected authentication"); - timer->cancel(); - conn->Terminate(); - return; - } - LogPrint(eLogError, "NTCP2:", (int)(*readbuff)[1]); - } - LogPrint(eLogError, "NTCP2: SOCKS5 server gave invalid response"); + Socks5Handshake (conn->GetSocket(), conn->GetRemoteEndpoint (), + [conn, timer](const boost::system::error_code& ec) + { timer->cancel(); - conn->Terminate(); - }); + if (!ec) + conn->ClientLogin(); + else + { + LogPrint(eLogError, "NTCP2: SOCKS proxy handshake error ", ec.message()); + conn->Terminate(); + } + }); break; } case eHTTPProxy: @@ -1836,71 +1808,6 @@ namespace transport } } - void NTCP2Server::AfterSocksHandshake(std::shared_ptr conn, std::shared_ptr timer) - { - // build request - size_t sz = 6; // header + port - auto buff = std::make_shared >(256); - auto readbuff = std::make_shared >(256); - (*buff)[0] = SOCKS5_VER; - (*buff)[1] = SOCKS5_CMD_CONNECT; - (*buff)[2] = 0x00; - - auto& ep = conn->GetRemoteEndpoint (); - if(ep.address ().is_v4 ()) - { - (*buff)[3] = SOCKS5_ATYP_IPV4; - auto addrbytes = ep.address ().to_v4().to_bytes(); - sz += 4; - memcpy(buff->data () + 4, addrbytes.data(), 4); - } - else if (ep.address ().is_v6 ()) - { - (*buff)[3] = SOCKS5_ATYP_IPV6; - auto addrbytes = ep.address ().to_v6().to_bytes(); - sz += 16; - memcpy(buff->data () + 4, addrbytes.data(), 16); - } - else - { - // We mustn't really fall here because all connections are made to IP addresses - LogPrint(eLogError, "NTCP2: Tried to connect to unexpected address via proxy"); - return; - } - htobe16buf(buff->data () + sz - 2, ep.port ()); - boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff->data (), sz), boost::asio::transfer_all(), - [buff](const boost::system::error_code & ec, std::size_t written) - { - if(ec) - { - LogPrint(eLogError, "NTCP2: Failed to write handshake to socks proxy ", ec.message()); - return; - } - }); - - boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE), // read min reply size - boost::asio::transfer_all(), - [timer, conn, readbuff](const boost::system::error_code & e, std::size_t transferred) - { - if (e) - LogPrint(eLogError, "NTCP2: SOCKS proxy read error ", e.message()); - else if (!(*readbuff)[1]) // succeeded - { - boost::system::error_code ec; - size_t moreBytes = conn->GetSocket ().available(ec); - if (moreBytes) // read remaining portion of reply if ipv6 received - boost::asio::read (conn->GetSocket (), boost::asio::buffer(readbuff->data (), moreBytes), boost::asio::transfer_all (), ec); - timer->cancel(); - conn->ClientLogin(); - return; - } - else - LogPrint(eLogError, "NTCP2: Proxy reply error ", (int)(*readbuff)[1]); - timer->cancel(); - conn->Terminate(); - }); - } - void NTCP2Server::SetLocalAddress (const boost::asio::ip::address& localAddress) { auto addr = std::make_shared(boost::asio::ip::tcp::endpoint(localAddress, 0)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 1eac23f0..a566b38d 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -267,8 +267,7 @@ namespace transport void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer); void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer); - void AfterSocksHandshake(std::shared_ptr conn, std::shared_ptr timer); - + // timer void ScheduleTermination (); void HandleTerminationTimer (const boost::system::error_code& ecode); diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index da682746..da5ca317 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -13,6 +13,7 @@ #include #include "util.h" #include "SSU2Session.h" +#include "Socks5.h" namespace i2p { diff --git a/libi2pd/Socks5.h b/libi2pd/Socks5.h new file mode 100644 index 00000000..84a23997 --- /dev/null +++ b/libi2pd/Socks5.h @@ -0,0 +1,154 @@ +/* +* Copyright (c) 2024, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +* +*/ + +#ifndef SOCKS5_H__ +#define SOCKS5_H__ + +#include +#include +#include +#include "I2PEndian.h" + +namespace i2p +{ +namespace transport +{ + // SOCKS5 constants + const uint8_t SOCKS5_VER = 0x05; + const uint8_t SOCKS5_CMD_CONNECT = 0x01; + const uint8_t SOCKS5_CMD_UDP_ASSOCIATE = 0x03; + const uint8_t SOCKS5_ATYP_IPV4 = 0x01; + const uint8_t SOCKS5_ATYP_IPV6 = 0x04; + const uint8_t SOCKS5_ATYP_NAME = 0x03; + const size_t SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE = 10; + const size_t SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE = 22; + + // SOCKS5 handshake + template + void Socks5Connect (Socket& s, Handler handler, std::shared_ptr > buff, uint16_t port) + { + if (buff && buff->size () >= 6) + { + (*buff)[0] = SOCKS5_VER; + (*buff)[1] = SOCKS5_CMD_CONNECT; + (*buff)[2] = 0x00; + htobe16buf(buff->data () + buff->size () - 2, port); + boost::asio::async_write(s, boost::asio::buffer(*buff), boost::asio::transfer_all(), + [buff, &s, handler](const boost::system::error_code& ec, std::size_t transferred) + { + (void) transferred; + if (!ec) + { + auto readbuff = std::make_shared >(262); // max possible + boost::asio::async_read(s, boost::asio::buffer(readbuff->data (), 7), boost::asio::transfer_all(), // read min reply size + [readbuff, &s, handler](const boost::system::error_code& ec, std::size_t transferred) + { + if (!ec) + { + if (!(*readbuff)[1]) // succeeded + { + boost::system::error_code ec; + size_t moreBytes = s.available(ec); + if (!ec && moreBytes) // read remaining portion of reply + boost::asio::read (s, boost::asio::buffer(readbuff->data (), moreBytes), boost::asio::transfer_all (), ec); + if (!ec) + handler (boost::system::error_code ()); + else + handler (boost::asio::error::make_error_code (boost::asio::error::connection_aborted)); + } + else + handler (boost::asio::error::make_error_code (boost::asio::error::connection_refused)); + } + else + handler (ec); + }); + } + else + handler (ec); + }); + } + else + handler (boost::asio::error::make_error_code (boost::asio::error::no_buffer_space)); + } + + template + void Socks5Connect (Socket& s, const boost::asio::ip::tcp::endpoint& ep, Handler handler) + { + std::shared_ptr > buff; + if(ep.address ().is_v4 ()) + { + buff = std::make_shared >(10); + (*buff)[3] = SOCKS5_ATYP_IPV4; + auto addrbytes = ep.address ().to_v4().to_bytes(); + memcpy(buff->data () + 4, addrbytes.data(), 4); + } + else if (ep.address ().is_v6 ()) + { + buff = std::make_shared >(22); + (*buff)[3] = SOCKS5_ATYP_IPV6; + auto addrbytes = ep.address ().to_v6().to_bytes(); + memcpy(buff->data () + 4, addrbytes.data(), 16); + } + if (buff) + Socks5Connect (s, handler, buff, ep.port ()); + else + handler (boost::asio::error::make_error_code (boost::asio::error::fault)); + } + + template + void Socks5Connect (Socket& s, const std::pair& ep, Handler handler) + { + auto& addr = ep.first; + if (addr.length () <= 255) + { + auto buff = std::make_shared >(addr.length () + 7); + (*buff)[3] = SOCKS5_ATYP_NAME; + (*buff)[4] = addr.length (); + memcpy (buff->data () + 5, addr.c_str (), addr.length ()); + Socks5Connect (s, handler, buff, ep.second); + } + else + handler (boost::asio::error::make_error_code (boost::asio::error::name_too_long)); + } + + + template + void Socks5Handshake (Socket& s, Endpoint ep, Handler handler) + { + static const uint8_t methodSelection[3] = { SOCKS5_VER, 0x01, 0x00 }; // 1 method, no auth + boost::asio::async_write(s, boost::asio::buffer(methodSelection, 3), boost::asio::transfer_all(), + [&s, ep, handler] (const boost::system::error_code& ec, std::size_t transferred) + { + (void) transferred; + if (!ec) + { + auto readbuff = std::make_shared >(2); + boost::asio::async_read(s, boost::asio::buffer(*readbuff), boost::asio::transfer_all(), + [&s, ep, handler, readbuff] (const boost::system::error_code& ec, std::size_t transferred) + { + if (!ec) + { + if (transferred == 2 && (*readbuff)[1] == 0x00) // no auth + Socks5Connect (s, ep, handler); + else + handler (boost::asio::error::make_error_code (boost::asio::error::invalid_argument)); + } + else + handler (ec); + }); + } + else + handler (ec); + }); + } + +} +} + +#endif diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index f4668116..c6bf0de3 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -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 * @@ -187,15 +187,6 @@ namespace transport uint64_t m_LastActivityTimestamp, m_LastBandwidthUpdateTimestamp; uint32_t m_InBandwidth, m_OutBandwidth; }; - - // SOCKS5 proxy - const uint8_t SOCKS5_VER = 0x05; - const uint8_t SOCKS5_CMD_CONNECT = 0x01; - const uint8_t SOCKS5_CMD_UDP_ASSOCIATE = 0x03; - const uint8_t SOCKS5_ATYP_IPV4 = 0x01; - const uint8_t SOCKS5_ATYP_IPV6 = 0x04; - const size_t SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE = 10; - const size_t SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE = 22; } } From 0ae7931a6f4d0299f64f95bea8249b8d6fd7b17d Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 11 Feb 2024 11:23:37 -0500 Subject: [PATCH 058/787] replaced SOCKS4 outproxy by SOCKS5 --- libi2pd_client/HTTPProxy.cpp | 71 ++++++++++-------------------------- 1 file changed, 19 insertions(+), 52 deletions(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index a0fc8f07..5f9ee1de 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -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 * @@ -29,6 +29,7 @@ #include "Config.h" #include "HTTP.h" #include "I18N.h" +#include "Socks5.h" namespace i2p { namespace proxy { @@ -93,9 +94,6 @@ namespace proxy { void HTTPConnect(const std::string & host, uint16_t port); void HandleHTTPConnectStreamRequestComplete(std::shared_ptr stream); - void HandleSocksProxySendHandshake(const boost::system::error_code & ec, std::size_t bytes_transfered); - void HandleSocksProxyReply(const boost::system::error_code & ec, std::size_t bytes_transfered); - typedef std::function ProxyResolvedHandler; void HandleUpstreamProxyResolved(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr, ProxyResolvedHandler handler); @@ -612,43 +610,30 @@ namespace proxy { void HTTPReqHandler::HandleUpstreamSocksProxyConnect(const boost::system::error_code & ec) { - if(!ec) { - if(m_RequestURL.host.size() > 255) { + if(!ec) + { + if(m_RequestURL.host.size() > 255) + { GenericProxyError(tr("Hostname is too long"), m_RequestURL.host); return; } uint16_t port = m_RequestURL.port; if(!port) port = 80; LogPrint(eLogDebug, "HTTPProxy: Connected to SOCKS upstream"); - std::string host = m_RequestURL.host; - std::size_t reqsize = 0; - m_socks_buf[0] = '\x04'; - m_socks_buf[1] = 1; - htobe16buf(m_socks_buf+2, port); - m_socks_buf[4] = 0; - m_socks_buf[5] = 0; - m_socks_buf[6] = 0; - m_socks_buf[7] = 1; - // user id - m_socks_buf[8] = 'i'; - m_socks_buf[9] = '2'; - m_socks_buf[10] = 'p'; - m_socks_buf[11] = 'd'; - m_socks_buf[12] = 0; - reqsize += 13; - memcpy(m_socks_buf+ reqsize, host.c_str(), host.size()); - reqsize += host.size(); - m_socks_buf[++reqsize] = 0; - boost::asio::async_write(*m_proxysock, boost::asio::buffer(m_socks_buf, reqsize), boost::asio::transfer_all(), std::bind(&HTTPReqHandler::HandleSocksProxySendHandshake, this, std::placeholders::_1, std::placeholders::_2)); - } else GenericProxyError(tr("Cannot connect to upstream SOCKS proxy"), ec.message()); - } - - void HTTPReqHandler::HandleSocksProxySendHandshake(const boost::system::error_code & ec, std::size_t bytes_transferred) - { - LogPrint(eLogDebug, "HTTPProxy: Upstream SOCKS handshake sent"); - if(ec) GenericProxyError(tr("Cannot negotiate with SOCKS proxy"), ec.message()); - else m_proxysock->async_read_some(boost::asio::buffer(m_socks_buf, 8), std::bind(&HTTPReqHandler::HandleSocksProxyReply, this, std::placeholders::_1, std::placeholders::_2)); + auto s = shared_from_this (); + i2p::transport::Socks5Handshake (*m_proxysock, std::make_pair(host, port), + [s](const boost::system::error_code& ec) + { + if (!ec) + s->SocksProxySuccess(); + else + s->GenericProxyError(tr("SOCKS proxy error"), ec.message ()); + }); + + } + else + GenericProxyError(tr("Cannot connect to upstream SOCKS proxy"), ec.message()); } void HTTPReqHandler::HandoverToUpstreamProxy() @@ -714,24 +699,6 @@ namespace proxy { } } - void HTTPReqHandler::HandleSocksProxyReply(const boost::system::error_code & ec, std::size_t bytes_transferred) - { - if(!ec) - { - if(m_socks_buf[1] == 90) { - // success - SocksProxySuccess(); - } else { - std::stringstream ss; - ss << "error code: "; - ss << (int) m_socks_buf[1]; - std::string msg = ss.str(); - GenericProxyError(tr("SOCKS proxy error"), msg); - } - } - else GenericProxyError(tr("No reply from SOCKS proxy"), ec.message()); - } - void HTTPReqHandler::HandleUpstreamHTTPProxyConnect(const boost::system::error_code & ec) { if(!ec) { From b07530a8a17f49745fbee0b6df6ddd6644779796 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 11 Feb 2024 11:44:15 -0500 Subject: [PATCH 059/787] don't print error message if operation cancelled --- libi2pd_client/I2PService.cpp | 88 ++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/libi2pd_client/I2PService.cpp b/libi2pd_client/I2PService.cpp index c30b7c9f..9b0b8028 100644 --- a/libi2pd_client/I2PService.cpp +++ b/libi2pd_client/I2PService.cpp @@ -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 * @@ -240,54 +240,68 @@ namespace client void TCPIPPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) { - LogPrint(eLogDebug, "TCPIPPipe: Downstream: ", (int) bytes_transfered, " bytes received"); - if (ecode) - { - LogPrint(eLogError, "TCPIPPipe: Downstream read error:" , ecode.message()); - if (ecode != boost::asio::error::operation_aborted) + if (ecode != boost::asio::error::operation_aborted) + { + LogPrint(eLogDebug, "TCPIPPipe: Downstream: ", (int) bytes_transfered, " bytes received"); + if (ecode) + { + LogPrint(eLogWarning, "TCPIPPipe: Downstream read error:" , ecode.message()); Terminate(); - } else { - if (bytes_transfered > 0 ) - memcpy(m_upstream_buf, m_downstream_to_up_buf, bytes_transfered); - UpstreamWrite(bytes_transfered); - } + } + else + { + if (bytes_transfered > 0 ) + memcpy(m_upstream_buf, m_downstream_to_up_buf, bytes_transfered); + UpstreamWrite(bytes_transfered); + } + } } - void TCPIPPipe::HandleDownstreamWrite(const boost::system::error_code & ecode) { - if (ecode) - { - LogPrint(eLogError, "TCPIPPipe: Downstream write error:" , ecode.message()); - if (ecode != boost::asio::error::operation_aborted) + void TCPIPPipe::HandleDownstreamWrite(const boost::system::error_code & ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + if (ecode) + { + LogPrint(eLogWarning, "TCPIPPipe: Downstream write error:" , ecode.message()); Terminate(); - } - else - AsyncReceiveUpstream(); + } + else + AsyncReceiveUpstream(); + } } - void TCPIPPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) { - if (ecode) - { - LogPrint(eLogError, "TCPIPPipe: Upstream write error:" , ecode.message()); - if (ecode != boost::asio::error::operation_aborted) + void TCPIPPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + if (ecode) + { + LogPrint(eLogWarning, "TCPIPPipe: Upstream write error:" , ecode.message()); Terminate(); - } - else - AsyncReceiveDownstream(); + } + else + AsyncReceiveDownstream(); + } } void TCPIPPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) { - LogPrint(eLogDebug, "TCPIPPipe: Upstream ", (int)bytes_transfered, " bytes received"); - if (ecode) - { - LogPrint(eLogError, "TCPIPPipe: Upstream read error:" , ecode.message()); - if (ecode != boost::asio::error::operation_aborted) + if (ecode != boost::asio::error::operation_aborted) + { + LogPrint(eLogDebug, "TCPIPPipe: Upstream ", (int)bytes_transfered, " bytes received"); + if (ecode) + { + LogPrint(eLogWarning, "TCPIPPipe: Upstream read error:" , ecode.message()); Terminate(); - } else { - if (bytes_transfered > 0 ) - memcpy(m_downstream_buf, m_upstream_to_down_buf, bytes_transfered); - DownstreamWrite(bytes_transfered); - } + } + else + { + if (bytes_transfered > 0 ) + memcpy(m_downstream_buf, m_upstream_to_down_buf, bytes_transfered); + DownstreamWrite(bytes_transfered); + } + } } void TCPIPAcceptor::Start () From 075f80aea23eab9b81c925c352291b73c4b34946 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 11 Feb 2024 15:33:37 -0500 Subject: [PATCH 060/787] use SOCK5 proxy for upstream --- libi2pd_client/SOCKS.cpp | 121 ++++++--------------------------------- 1 file changed, 18 insertions(+), 103 deletions(-) diff --git a/libi2pd_client/SOCKS.cpp b/libi2pd_client/SOCKS.cpp index 547a2da2..49a04b81 100644 --- a/libi2pd_client/SOCKS.cpp +++ b/libi2pd_client/SOCKS.cpp @@ -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 * @@ -19,6 +19,7 @@ #include "I2PTunnel.h" #include "I2PService.h" #include "util.h" +#include "Socks5.h" namespace i2p { @@ -27,10 +28,6 @@ namespace proxy static const size_t socks_buffer_size = 8192; static const size_t max_socks_hostname_size = 255; // Limit for socks5 and bad idea to traverse - //static const size_t SOCKS_FORWARDER_BUFFER_SIZE = 8192; - - static const size_t SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE = 8; - struct SOCKSDnsAddress { uint8_t size; @@ -132,7 +129,6 @@ namespace proxy boost::asio::const_buffers_1 GenerateSOCKS5SelectAuth(authMethods method); boost::asio::const_buffers_1 GenerateSOCKS4Response(errTypes error, uint32_t ip, uint16_t port); boost::asio::const_buffers_1 GenerateSOCKS5Response(errTypes error, addrTypes type, const address &addr, uint16_t port); - boost::asio::const_buffers_1 GenerateUpstreamRequest(); bool Socks5ChooseAuth(); void Socks5UserPasswdResponse (); void SocksRequestFailed(errTypes error); @@ -146,9 +142,6 @@ namespace proxy void SocksUpstreamSuccess(); void AsyncUpstreamSockRead(); void SendUpstreamRequest(); - void HandleUpstreamData(uint8_t * buff, std::size_t len); - void HandleUpstreamSockSend(const boost::system::error_code & ecode, std::size_t bytes_transfered); - void HandleUpstreamSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered); void HandleUpstreamConnected(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr); void HandleUpstreamResolved(const boost::system::error_code & ecode, @@ -161,9 +154,6 @@ namespace proxy uint8_t *m_remaining_data; //Data left to be sent uint8_t *m_remaining_upstream_data; //upstream data left to be forwarded uint8_t m_response[7+max_socks_hostname_size]; - uint8_t m_upstream_response[SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE]; - uint8_t m_upstream_request[14+max_socks_hostname_size]; - std::size_t m_upstream_response_len; address m_address; //Address std::size_t m_remaining_data_len; //Size of the data left to be sent uint32_t m_4aip; //Used in 4a requests @@ -280,37 +270,6 @@ namespace proxy return boost::asio::const_buffers_1(m_response, size); } - boost::asio::const_buffers_1 SOCKSHandler::GenerateUpstreamRequest() - { - size_t upstreamRequestSize = 0; - // TODO: negotiate with upstream - // SOCKS 4a - m_upstream_request[0] = '\x04'; //version - m_upstream_request[1] = m_cmd; - htobe16buf(m_upstream_request + 2, m_port); - m_upstream_request[4] = 0; - m_upstream_request[5] = 0; - m_upstream_request[6] = 0; - m_upstream_request[7] = 1; - // user id - m_upstream_request[8] = 'i'; - m_upstream_request[9] = '2'; - m_upstream_request[10] = 'p'; - m_upstream_request[11] = 'd'; - m_upstream_request[12] = 0; - upstreamRequestSize += 13; - if (m_address.dns.size <= max_socks_hostname_size - ( upstreamRequestSize + 1) ) { - // bounds check okay - memcpy(m_upstream_request + upstreamRequestSize, m_address.dns.value, m_address.dns.size); - upstreamRequestSize += m_address.dns.size; - // null terminate - m_upstream_request[++upstreamRequestSize] = 0; - } else { - LogPrint(eLogError, "SOCKS: BUG!!! m_addr.dns.sizs > max_socks_hostname - ( upstreamRequestSize + 1 ) )"); - } - return boost::asio::const_buffers_1(m_upstream_request, upstreamRequestSize); - } - bool SOCKSHandler::Socks5ChooseAuth() { m_response[0] = '\x05'; // Version @@ -724,32 +683,6 @@ namespace proxy std::placeholders::_1, std::placeholders::_2)); } - void SOCKSHandler::AsyncUpstreamSockRead() - { - LogPrint(eLogDebug, "SOCKS: Async upstream sock read"); - if (m_upstreamSock) { - m_upstreamSock->async_read_some(boost::asio::buffer(m_upstream_response, SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE), - std::bind(&SOCKSHandler::HandleUpstreamSockRecv, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); - } else { - LogPrint(eLogError, "SOCKS: No upstream socket for read"); - SocksRequestFailed(SOCKS5_GEN_FAIL); - } - } - - void SOCKSHandler::HandleUpstreamSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered) - { - if (ecode) { - if (m_state == UPSTREAM_HANDSHAKE ) { - // we are trying to handshake but it failed - SocksRequestFailed(SOCKS5_NET_UNREACH); - } else { - LogPrint(eLogError, "SOCKS: Bad state when reading from upstream: ", (int) m_state); - } - return; - } - HandleUpstreamData(m_upstream_response, bytes_transfered); - } - void SOCKSHandler::SocksUpstreamSuccess() { LogPrint(eLogInfo, "SOCKS: Upstream success"); @@ -776,46 +709,28 @@ namespace proxy } - void SOCKSHandler::HandleUpstreamData(uint8_t * dataptr, std::size_t len) - { - if (m_state == UPSTREAM_HANDSHAKE) { - m_upstream_response_len += len; - // handle handshake data - if (m_upstream_response_len < SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE) { - // too small, continue reading - AsyncUpstreamSockRead(); - } else if (len == SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE) { - // just right - uint8_t resp = m_upstream_response[1]; - if (resp == SOCKS4_OK) { - // we have connected ! - SocksUpstreamSuccess(); - } else { - // upstream failure - LogPrint(eLogError, "SOCKS: Upstream proxy failure: ", (int) resp); - // TODO: runtime error? - SocksRequestFailed(SOCKS5_GEN_FAIL); - } - } else { - // too big - SocksRequestFailed(SOCKS5_GEN_FAIL); - } - } else { - // invalid state - LogPrint(eLogError, "SOCKS: Invalid state reading from upstream: ", (int) m_state); - } - } void SOCKSHandler::SendUpstreamRequest() { LogPrint(eLogInfo, "SOCKS: Negotiating with upstream proxy"); EnterState(UPSTREAM_HANDSHAKE); - if (m_upstreamSock) { - boost::asio::write(*m_upstreamSock, GenerateUpstreamRequest()); - AsyncUpstreamSockRead(); - } else { + if (m_upstreamSock) + { + auto s = shared_from_this (); + i2p::transport::Socks5Handshake (*m_upstreamSock, std::make_pair(m_address.dns.ToString (), m_port), + [s](const boost::system::error_code& ec) + { + if (!ec) + s->SocksUpstreamSuccess(); + else + { + s->SocksRequestFailed(SOCKS5_NET_UNREACH); + LogPrint(eLogError, "SOCKS: Upstream proxy failure: ", ec.message ()); + } + }); + } + else LogPrint(eLogError, "SOCKS: No upstream socket to send handshake to"); - } } void SOCKSHandler::HandleUpstreamConnected(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr) From d9b6262a6e903507697f323926ba9c5f321a234a Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 12 Feb 2024 12:10:29 -0500 Subject: [PATCH 061/787] removed unused field --- libi2pd_client/HTTPProxy.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 5f9ee1de..8f9f8ada 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -111,7 +111,6 @@ namespace proxy { bool m_Addresshelper; i2p::http::URL m_ProxyURL; i2p::http::URL m_RequestURL; - uint8_t m_socks_buf[255+8]; // for socks request/response int m_req_len; i2p::http::URL m_ClientRequestURL; i2p::http::HTTPReq m_ClientRequest; From 7691a5b4a92acd72cb2b676bf921928f978cdf3b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 12 Feb 2024 13:22:26 -0500 Subject: [PATCH 062/787] use common SOCK5 code for reseed --- libi2pd/Reseed.cpp | 66 +++++++++------------------------------------- 1 file changed, 13 insertions(+), 53 deletions(-) diff --git a/libi2pd/Reseed.cpp b/libi2pd/Reseed.cpp index 5fdc2fae..f8307a56 100644 --- a/libi2pd/Reseed.cpp +++ b/libi2pd/Reseed.cpp @@ -26,6 +26,7 @@ #include "HTTP.h" #include "util.h" #include "Config.h" +#include "Socks5.h" namespace i2p { @@ -615,62 +616,21 @@ namespace data { // assume socks if not http, is checked before this for other types // TODO: support username/password auth etc - uint8_t hs_writebuf[3] = {0x05, 0x01, 0x00}; - uint8_t hs_readbuf[2]; - boost::asio::write(sock, boost::asio::buffer(hs_writebuf, 3), boost::asio::transfer_all(), ecode); - if(ecode) + bool success = false; + i2p::transport::Socks5Handshake (sock, std::make_pair(url.host, url.port), + [&success](const boost::system::error_code& ec) + { + if (!ec) + success = true; + else + LogPrint (eLogError, "Reseed: SOCKS handshake failed: ", ec.message()); + }); + service.run (); // execute all async operations + if (!success) { sock.close(); - LogPrint(eLogError, "Reseed: SOCKS handshake write failed: ", ecode.message()); return ""; - } - boost::asio::read(sock, boost::asio::buffer(hs_readbuf, 2), ecode); - if(ecode) - { - sock.close(); - LogPrint(eLogError, "Reseed: SOCKS handshake read failed: ", ecode.message()); - return ""; - } - size_t sz = 0; - uint8_t buf[256]; - - buf[0] = 0x05; - buf[1] = 0x01; - buf[2] = 0x00; - buf[3] = 0x03; - sz += 4; - size_t hostsz = url.host.size(); - if(1 + 2 + hostsz + sz > sizeof(buf)) - { - sock.close(); - LogPrint(eLogError, "Reseed: SOCKS handshake failed, hostname too big: ", url.host); - return ""; - } - buf[4] = (uint8_t) hostsz; - memcpy(buf+5, url.host.c_str(), hostsz); - sz += hostsz + 1; - htobe16buf(buf+sz, url.port); - sz += 2; - boost::asio::write(sock, boost::asio::buffer(buf, sz), boost::asio::transfer_all(), ecode); - if(ecode) - { - sock.close(); - LogPrint(eLogError, "Reseed: SOCKS handshake failed writing: ", ecode.message()); - return ""; - } - boost::asio::read(sock, boost::asio::buffer(buf, 10), ecode); - if(ecode) - { - sock.close(); - LogPrint(eLogError, "Reseed: SOCKS handshake failed reading: ", ecode.message()); - return ""; - } - if(buf[1] != 0x00) - { - sock.close(); - LogPrint(eLogError, "Reseed: SOCKS handshake bad reply code: ", std::to_string(buf[1])); - return ""; - } + } } } } From 967627e58a3730d143aa0b15693a54bb93f0d0e8 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 12 Feb 2024 21:55:30 -0500 Subject: [PATCH 063/787] read correct reply length and handle reply codes --- libi2pd/Socks5.h | 106 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 81 insertions(+), 25 deletions(-) diff --git a/libi2pd/Socks5.h b/libi2pd/Socks5.h index 84a23997..d611bff3 100644 --- a/libi2pd/Socks5.h +++ b/libi2pd/Socks5.h @@ -29,7 +29,87 @@ namespace transport const size_t SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE = 10; const size_t SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE = 22; + const uint8_t SOCKS5_REPLY_SUCCESS = 0x00; + const uint8_t SOCKS5_REPLY_SERVER_FAILURE = 0x01; + const uint8_t SOCKS5_REPLY_CONNECTION_NOT_ALLOWED = 0x02; + const uint8_t SOCKS5_REPLY_NETWORK_UNREACHABLE = 0x03; + const uint8_t SOCKS5_REPLY_HOST_UNREACHABLE = 0x04; + const uint8_t SOCKS5_REPLY_CONNECTION_REFUSED = 0x05; + const uint8_t SOCKS5_REPLY_TTL_EXPIRED = 0x06; + const uint8_t SOCKS5_REPLY_COMMAND_NOT_SUPPORTED = 0x07; + const uint8_t SOCKS5_REPLY_ADDRESS_TYPE_NOT_SUPPORTED = 0x08; + // SOCKS5 handshake + template + void Socks5ReadReply (Socket& s, Handler handler) + { + auto readbuff = std::make_shared >(258); // max possible + boost::asio::async_read(s, boost::asio::buffer(readbuff->data (), 5), boost::asio::transfer_all(), // read 4 bytes of header + first byte of address + [readbuff, &s, handler](const boost::system::error_code& ec, std::size_t transferred) + { + if (!ec) + { + if ((*readbuff)[1] == SOCKS5_REPLY_SUCCESS) + { + size_t len = 0; + switch ((*readbuff)[3]) // ATYP + { + case SOCKS5_ATYP_IPV4: len = 3; break; // address length 4 bytes + case SOCKS5_ATYP_IPV6: len = 15; break; // address length 16 bytes + case SOCKS5_ATYP_NAME: len += (*readbuff)[4]; break; // first byte of address is length + default: ; + } + if (len) + { + len += 2; // port + boost::asio::async_read(s, boost::asio::buffer(readbuff->data (), len), boost::asio::transfer_all(), + [readbuff, &s, handler](const boost::system::error_code& ec, std::size_t transferred) + { + if (!ec) + handler (boost::system::error_code ()); // success + else + handler (boost::asio::error::make_error_code (boost::asio::error::connection_aborted)); + }); + } + else + handler (boost::asio::error::make_error_code (boost::asio::error::fault)); // unknown address type + } + else + switch ((*readbuff)[1]) // REP + { + case SOCKS5_REPLY_SERVER_FAILURE: + handler (boost::asio::error::make_error_code (boost::asio::error::access_denied )); + break; + case SOCKS5_REPLY_CONNECTION_NOT_ALLOWED: + handler (boost::asio::error::make_error_code (boost::asio::error::no_permission)); + break; + case SOCKS5_REPLY_HOST_UNREACHABLE: + handler (boost::asio::error::make_error_code (boost::asio::error::host_unreachable)); + break; + case SOCKS5_REPLY_NETWORK_UNREACHABLE: + handler (boost::asio::error::make_error_code (boost::asio::error::network_unreachable)); + break; + case SOCKS5_REPLY_CONNECTION_REFUSED: + handler (boost::asio::error::make_error_code (boost::asio::error::connection_refused)); + break; + case SOCKS5_REPLY_TTL_EXPIRED: + handler (boost::asio::error::make_error_code (boost::asio::error::timed_out)); + break; + case SOCKS5_REPLY_COMMAND_NOT_SUPPORTED: + handler (boost::asio::error::make_error_code (boost::asio::error::operation_not_supported)); + break; + case SOCKS5_REPLY_ADDRESS_TYPE_NOT_SUPPORTED: + handler (boost::asio::error::make_error_code (boost::asio::error::no_protocol_option)); + break; + default: + handler (boost::asio::error::make_error_code (boost::asio::error::connection_aborted)); + } + } + else + handler (ec); + }); + } + template void Socks5Connect (Socket& s, Handler handler, std::shared_ptr > buff, uint16_t port) { @@ -44,31 +124,7 @@ namespace transport { (void) transferred; if (!ec) - { - auto readbuff = std::make_shared >(262); // max possible - boost::asio::async_read(s, boost::asio::buffer(readbuff->data (), 7), boost::asio::transfer_all(), // read min reply size - [readbuff, &s, handler](const boost::system::error_code& ec, std::size_t transferred) - { - if (!ec) - { - if (!(*readbuff)[1]) // succeeded - { - boost::system::error_code ec; - size_t moreBytes = s.available(ec); - if (!ec && moreBytes) // read remaining portion of reply - boost::asio::read (s, boost::asio::buffer(readbuff->data (), moreBytes), boost::asio::transfer_all (), ec); - if (!ec) - handler (boost::system::error_code ()); - else - handler (boost::asio::error::make_error_code (boost::asio::error::connection_aborted)); - } - else - handler (boost::asio::error::make_error_code (boost::asio::error::connection_refused)); - } - else - handler (ec); - }); - } + Socks5ReadReply (s, handler); else handler (ec); }); From a9ad6fc31e3b733d285dcdad61dfa42bc262c13c Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 13 Feb 2024 18:52:18 -0500 Subject: [PATCH 064/787] renamed TCPIPPipe to SocketsPipe --- libi2pd_client/HTTPProxy.cpp | 2 +- libi2pd_client/I2PService.cpp | 52 +++++++++++++++++------------------ libi2pd_client/I2PService.h | 28 ++++++++++++------- libi2pd_client/SOCKS.cpp | 3 +- 4 files changed, 46 insertions(+), 39 deletions(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 8f9f8ada..01678f4a 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -638,7 +638,7 @@ namespace proxy { void HTTPReqHandler::HandoverToUpstreamProxy() { LogPrint(eLogDebug, "HTTPProxy: Handover to SOCKS proxy"); - auto connection = std::make_shared(GetOwner(), m_proxysock, m_sock); + auto connection = CreateSocketsPipe (GetOwner(), m_proxysock, m_sock); m_sock = nullptr; m_proxysock = nullptr; GetOwner()->AddHandler(connection); diff --git a/libi2pd_client/I2PService.cpp b/libi2pd_client/I2PService.cpp index 9b0b8028..27e34b69 100644 --- a/libi2pd_client/I2PService.cpp +++ b/libi2pd_client/I2PService.cpp @@ -148,25 +148,25 @@ namespace client } } - TCPIPPipe::TCPIPPipe(I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream) : I2PServiceHandler(owner), m_up(upstream), m_down(downstream) + SocketsPipe::SocketsPipe(I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream) : I2PServiceHandler(owner), m_up(upstream), m_down(downstream) { - boost::asio::socket_base::receive_buffer_size option(TCP_IP_PIPE_BUFFER_SIZE); + boost::asio::socket_base::receive_buffer_size option(SOCKETS_PIPE_BUFFER_SIZE); upstream->set_option(option); downstream->set_option(option); } - TCPIPPipe::~TCPIPPipe() + SocketsPipe::~SocketsPipe() { Terminate(); } - void TCPIPPipe::Start() + void SocketsPipe::Start() { AsyncReceiveUpstream(); AsyncReceiveDownstream(); } - void TCPIPPipe::Terminate() + void SocketsPipe::Terminate() { if(Kill()) return; if (m_up) @@ -184,52 +184,52 @@ namespace client Done(shared_from_this()); } - void TCPIPPipe::AsyncReceiveUpstream() + void SocketsPipe::AsyncReceiveUpstream() { if (m_up) { - m_up->async_read_some(boost::asio::buffer(m_upstream_to_down_buf, TCP_IP_PIPE_BUFFER_SIZE), - std::bind(&TCPIPPipe::HandleUpstreamReceived, shared_from_this(), + m_up->async_read_some(boost::asio::buffer(m_upstream_to_down_buf, SOCKETS_PIPE_BUFFER_SIZE), + std::bind(&SocketsPipe::HandleUpstreamReceived, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } else - LogPrint(eLogError, "TCPIPPipe: Upstream receive: No socket"); + LogPrint(eLogError, "SocketsPipe: Upstream receive: No socket"); } - void TCPIPPipe::AsyncReceiveDownstream() + void SocketsPipe::AsyncReceiveDownstream() { if (m_down) { - m_down->async_read_some(boost::asio::buffer(m_downstream_to_up_buf, TCP_IP_PIPE_BUFFER_SIZE), - std::bind(&TCPIPPipe::HandleDownstreamReceived, shared_from_this(), + m_down->async_read_some(boost::asio::buffer(m_downstream_to_up_buf, SOCKETS_PIPE_BUFFER_SIZE), + std::bind(&SocketsPipe::HandleDownstreamReceived, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } else - LogPrint(eLogError, "TCPIPPipe: Downstream receive: No socket"); + LogPrint(eLogError, "SocketsPipe: Downstream receive: No socket"); } - void TCPIPPipe::UpstreamWrite(size_t len) + void SocketsPipe::UpstreamWrite(size_t len) { if (m_up) { - LogPrint(eLogDebug, "TCPIPPipe: Upstream: ", (int) len, " bytes written"); + LogPrint(eLogDebug, "SocketsPipe: Upstream: ", (int) len, " bytes written"); boost::asio::async_write(*m_up, boost::asio::buffer(m_upstream_buf, len), boost::asio::transfer_all(), - std::bind(&TCPIPPipe::HandleUpstreamWrite, + std::bind(&SocketsPipe::HandleUpstreamWrite, shared_from_this(), std::placeholders::_1)); } else - LogPrint(eLogError, "TCPIPPipe: Upstream write: no socket"); + LogPrint(eLogError, "SocketsPipe: Upstream write: no socket"); } - void TCPIPPipe::DownstreamWrite(size_t len) + void SocketsPipe::DownstreamWrite(size_t len) { if (m_down) { LogPrint(eLogDebug, "TCPIPPipe: Downstream: ", (int) len, " bytes written"); boost::asio::async_write(*m_down, boost::asio::buffer(m_downstream_buf, len), boost::asio::transfer_all(), - std::bind(&TCPIPPipe::HandleDownstreamWrite, + std::bind(&SocketsPipe::HandleDownstreamWrite, shared_from_this(), std::placeholders::_1)); } @@ -238,7 +238,7 @@ namespace client } - void TCPIPPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) + void SocketsPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) { if (ecode != boost::asio::error::operation_aborted) { @@ -257,7 +257,7 @@ namespace client } } - void TCPIPPipe::HandleDownstreamWrite(const boost::system::error_code & ecode) + void SocketsPipe::HandleDownstreamWrite(const boost::system::error_code & ecode) { if (ecode != boost::asio::error::operation_aborted) { @@ -271,13 +271,13 @@ namespace client } } - void TCPIPPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) + void SocketsPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) { if (ecode != boost::asio::error::operation_aborted) { if (ecode) { - LogPrint(eLogWarning, "TCPIPPipe: Upstream write error:" , ecode.message()); + LogPrint(eLogWarning, "SocketsPipe: Upstream write error:" , ecode.message()); Terminate(); } else @@ -285,14 +285,14 @@ namespace client } } - void TCPIPPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) + void SocketsPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) { if (ecode != boost::asio::error::operation_aborted) { - LogPrint(eLogDebug, "TCPIPPipe: Upstream ", (int)bytes_transfered, " bytes received"); + LogPrint(eLogDebug, "SocketsPipe: Upstream ", (int)bytes_transfered, " bytes received"); if (ecode) { - LogPrint(eLogWarning, "TCPIPPipe: Upstream read error:" , ecode.message()); + LogPrint(eLogWarning, "SocketsPipe: Upstream read error:" , ecode.message()); Terminate(); } else diff --git a/libi2pd_client/I2PService.h b/libi2pd_client/I2PService.h index 4f67e19c..4be7f2ca 100644 --- a/libi2pd_client/I2PService.h +++ b/libi2pd_client/I2PService.h @@ -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 * @@ -99,6 +99,7 @@ namespace client virtual ~I2PServiceHandler() { } //If you override this make sure you call it from the children virtual void Handle() {}; //Start handling the socket + virtual void Start () {}; void Terminate () { Kill (); }; @@ -119,16 +120,16 @@ namespace client std::atomic m_Dead; //To avoid cleaning up multiple times }; - const size_t TCP_IP_PIPE_BUFFER_SIZE = 8192 * 8; + const size_t SOCKETS_PIPE_BUFFER_SIZE = 8192 * 8; - // bidirectional pipe for 2 tcp/ip sockets - class TCPIPPipe: public I2PServiceHandler, public std::enable_shared_from_this + // bidirectional pipe for 2 stream sockets + class SocketsPipe: public I2PServiceHandler, public std::enable_shared_from_this { public: - TCPIPPipe(I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream); - ~TCPIPPipe(); - void Start(); + SocketsPipe(I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream); + ~SocketsPipe(); + void Start() override; protected: @@ -144,11 +145,18 @@ namespace client private: - uint8_t m_upstream_to_down_buf[TCP_IP_PIPE_BUFFER_SIZE], m_downstream_to_up_buf[TCP_IP_PIPE_BUFFER_SIZE]; - uint8_t m_upstream_buf[TCP_IP_PIPE_BUFFER_SIZE], m_downstream_buf[TCP_IP_PIPE_BUFFER_SIZE]; - std::shared_ptr m_up, m_down; + uint8_t m_upstream_to_down_buf[SOCKETS_PIPE_BUFFER_SIZE], m_downstream_to_up_buf[SOCKETS_PIPE_BUFFER_SIZE]; + uint8_t m_upstream_buf[SOCKETS_PIPE_BUFFER_SIZE], m_downstream_buf[SOCKETS_PIPE_BUFFER_SIZE]; + std::shared_ptr m_up; + std::shared_ptr m_down; }; + template + std::shared_ptr CreateSocketsPipe (I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream) + { + return std::make_shared(owner, upstream, downstream); + } + /* TODO: support IPv6 too */ //This is a service that listens for connections on the IP network and interacts with I2P class TCPIPAcceptor: public I2PService diff --git a/libi2pd_client/SOCKS.cpp b/libi2pd_client/SOCKS.cpp index 49a04b81..65bad1cf 100644 --- a/libi2pd_client/SOCKS.cpp +++ b/libi2pd_client/SOCKS.cpp @@ -700,13 +700,12 @@ namespace proxy break; } m_sock->send(response); - auto forwarder = std::make_shared(GetOwner(), m_sock, m_upstreamSock); + auto forwarder = CreateSocketsPipe (GetOwner(), m_sock, m_upstreamSock); m_upstreamSock = nullptr; m_sock = nullptr; GetOwner()->AddHandler(forwarder); forwarder->Start(); Terminate(); - } From 710b27688ba03dc580839fb7b4270ecfd4943014 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 14 Feb 2024 15:35:47 -0500 Subject: [PATCH 065/787] generic SocketsPipe for different socket types --- libi2pd_client/I2PService.cpp | 156 ---------------------------------- libi2pd_client/I2PService.h | 99 ++++++++++++++++----- 2 files changed, 76 insertions(+), 179 deletions(-) diff --git a/libi2pd_client/I2PService.cpp b/libi2pd_client/I2PService.cpp index 27e34b69..5604f950 100644 --- a/libi2pd_client/I2PService.cpp +++ b/libi2pd_client/I2PService.cpp @@ -148,162 +148,6 @@ namespace client } } - SocketsPipe::SocketsPipe(I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream) : I2PServiceHandler(owner), m_up(upstream), m_down(downstream) - { - boost::asio::socket_base::receive_buffer_size option(SOCKETS_PIPE_BUFFER_SIZE); - upstream->set_option(option); - downstream->set_option(option); - } - - SocketsPipe::~SocketsPipe() - { - Terminate(); - } - - void SocketsPipe::Start() - { - AsyncReceiveUpstream(); - AsyncReceiveDownstream(); - } - - void SocketsPipe::Terminate() - { - if(Kill()) return; - if (m_up) - { - if (m_up->is_open()) - m_up->close(); - m_up = nullptr; - } - if (m_down) - { - if (m_down->is_open()) - m_down->close(); - m_down = nullptr; - } - Done(shared_from_this()); - } - - void SocketsPipe::AsyncReceiveUpstream() - { - if (m_up) - { - m_up->async_read_some(boost::asio::buffer(m_upstream_to_down_buf, SOCKETS_PIPE_BUFFER_SIZE), - std::bind(&SocketsPipe::HandleUpstreamReceived, shared_from_this(), - std::placeholders::_1, std::placeholders::_2)); - } - else - LogPrint(eLogError, "SocketsPipe: Upstream receive: No socket"); - } - - void SocketsPipe::AsyncReceiveDownstream() - { - if (m_down) { - m_down->async_read_some(boost::asio::buffer(m_downstream_to_up_buf, SOCKETS_PIPE_BUFFER_SIZE), - std::bind(&SocketsPipe::HandleDownstreamReceived, shared_from_this(), - std::placeholders::_1, std::placeholders::_2)); - } - else - LogPrint(eLogError, "SocketsPipe: Downstream receive: No socket"); - } - - void SocketsPipe::UpstreamWrite(size_t len) - { - if (m_up) - { - LogPrint(eLogDebug, "SocketsPipe: Upstream: ", (int) len, " bytes written"); - boost::asio::async_write(*m_up, boost::asio::buffer(m_upstream_buf, len), - boost::asio::transfer_all(), - std::bind(&SocketsPipe::HandleUpstreamWrite, - shared_from_this(), - std::placeholders::_1)); - } - else - LogPrint(eLogError, "SocketsPipe: Upstream write: no socket"); - } - - void SocketsPipe::DownstreamWrite(size_t len) - { - if (m_down) - { - LogPrint(eLogDebug, "TCPIPPipe: Downstream: ", (int) len, " bytes written"); - boost::asio::async_write(*m_down, boost::asio::buffer(m_downstream_buf, len), - boost::asio::transfer_all(), - std::bind(&SocketsPipe::HandleDownstreamWrite, - shared_from_this(), - std::placeholders::_1)); - } - else - LogPrint(eLogError, "TCPIPPipe: Downstream write: No socket"); - } - - - void SocketsPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) - { - if (ecode != boost::asio::error::operation_aborted) - { - LogPrint(eLogDebug, "TCPIPPipe: Downstream: ", (int) bytes_transfered, " bytes received"); - if (ecode) - { - LogPrint(eLogWarning, "TCPIPPipe: Downstream read error:" , ecode.message()); - Terminate(); - } - else - { - if (bytes_transfered > 0 ) - memcpy(m_upstream_buf, m_downstream_to_up_buf, bytes_transfered); - UpstreamWrite(bytes_transfered); - } - } - } - - void SocketsPipe::HandleDownstreamWrite(const boost::system::error_code & ecode) - { - if (ecode != boost::asio::error::operation_aborted) - { - if (ecode) - { - LogPrint(eLogWarning, "TCPIPPipe: Downstream write error:" , ecode.message()); - Terminate(); - } - else - AsyncReceiveUpstream(); - } - } - - void SocketsPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) - { - if (ecode != boost::asio::error::operation_aborted) - { - if (ecode) - { - LogPrint(eLogWarning, "SocketsPipe: Upstream write error:" , ecode.message()); - Terminate(); - } - else - AsyncReceiveDownstream(); - } - } - - void SocketsPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) - { - if (ecode != boost::asio::error::operation_aborted) - { - LogPrint(eLogDebug, "SocketsPipe: Upstream ", (int)bytes_transfered, " bytes received"); - if (ecode) - { - LogPrint(eLogWarning, "SocketsPipe: Upstream read error:" , ecode.message()); - Terminate(); - } - else - { - if (bytes_transfered > 0 ) - memcpy(m_downstream_buf, m_upstream_to_down_buf, bytes_transfered); - DownstreamWrite(bytes_transfered); - } - } - } - void TCPIPAcceptor::Start () { m_Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), m_LocalEndpoint)); diff --git a/libi2pd_client/I2PService.h b/libi2pd_client/I2PService.h index 4be7f2ca..b8973f9d 100644 --- a/libi2pd_client/I2PService.h +++ b/libi2pd_client/I2PService.h @@ -123,38 +123,91 @@ namespace client const size_t SOCKETS_PIPE_BUFFER_SIZE = 8192 * 8; // bidirectional pipe for 2 stream sockets - class SocketsPipe: public I2PServiceHandler, public std::enable_shared_from_this + template + class SocketsPipe: public I2PServiceHandler, + public std::enable_shared_from_this > { public: - SocketsPipe(I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream); - ~SocketsPipe(); - void Start() override; - - protected: - - void Terminate(); - void AsyncReceiveUpstream(); - void AsyncReceiveDownstream(); - void HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transferred); - void HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transferred); - void HandleUpstreamWrite(const boost::system::error_code & ecode); - void HandleDownstreamWrite(const boost::system::error_code & ecode); - void UpstreamWrite(size_t len); - void DownstreamWrite(size_t len); + SocketsPipe(I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream): + I2PServiceHandler(owner), m_up(upstream), m_down(downstream) + { + boost::asio::socket_base::receive_buffer_size option(SOCKETS_PIPE_BUFFER_SIZE); + upstream->set_option(option); + downstream->set_option(option); + } + ~SocketsPipe() { Terminate(); } + + void Start() override + { + Transfer (m_up, m_down, m_upstream_to_down_buf, SOCKETS_PIPE_BUFFER_SIZE); // receive from upstream + Transfer (m_down, m_up, m_downstream_to_up_buf, SOCKETS_PIPE_BUFFER_SIZE); // receive from upstream + } private: - uint8_t m_upstream_to_down_buf[SOCKETS_PIPE_BUFFER_SIZE], m_downstream_to_up_buf[SOCKETS_PIPE_BUFFER_SIZE]; - uint8_t m_upstream_buf[SOCKETS_PIPE_BUFFER_SIZE], m_downstream_buf[SOCKETS_PIPE_BUFFER_SIZE]; - std::shared_ptr m_up; - std::shared_ptr m_down; + void Terminate() + { + if(Kill()) return; + if (m_up) + { + if (m_up->is_open()) + m_up->close(); + m_up = nullptr; + } + if (m_down) + { + if (m_down->is_open()) + m_down->close(); + m_down = nullptr; + } + Done(SocketsPipe::shared_from_this()); + } + + template + void Transfer (std::shared_ptr from, std::shared_ptr to, uint8_t * buf, size_t len) + { + if (!from || !to || !buf) return; + auto s = SocketsPipe::shared_from_this (); + from->async_read_some(boost::asio::buffer(buf, len), + [from, to, s, buf, len](const boost::system::error_code& ecode, std::size_t transferred) + { + if (ecode == boost::asio::error::operation_aborted) return; + if (!ecode) + { + boost::asio::async_write(*to, boost::asio::buffer(buf, transferred), boost::asio::transfer_all(), + [from, to, s, buf, len](const boost::system::error_code& ecode, std::size_t transferred) + { + (void) transferred; + if (ecode == boost::asio::error::operation_aborted) return; + if (!ecode) + s->Transfer (from, to, buf, len); + else + { + LogPrint(eLogWarning, "SocketsPipe: Write error:" , ecode.message()); + s->Terminate(); + } + }); + } + else + { + LogPrint(eLogWarning, "SocketsPipe: Read error:" , ecode.message()); + s->Terminate(); + } + }); + } + + private: + + uint8_t m_upstream_to_down_buf[SOCKETS_PIPE_BUFFER_SIZE], m_downstream_to_up_buf[SOCKETS_PIPE_BUFFER_SIZE]; + std::shared_ptr m_up; + std::shared_ptr m_down; }; - template - std::shared_ptr CreateSocketsPipe (I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream) + template + std::shared_ptr CreateSocketsPipe (I2PService * owner, std::shared_ptr upstream, std::shared_ptr downstream) { - return std::make_shared(owner, upstream, downstream); + return std::make_shared >(owner, upstream, downstream); } /* TODO: support IPv6 too */ From 0e502c49b5c8274e8c2e6d8b1b226e1002ef02de Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 14 Feb 2024 18:53:28 -0500 Subject: [PATCH 066/787] show correct tunnel status. restore tunnel if delivery status or data for inbound tunnel received --- daemon/HTTPServer.cpp | 18 +++++++----------- libi2pd/Tunnel.cpp | 2 +- libi2pd/TunnelPool.cpp | 4 ++-- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 2d6800b4..862d6e4a 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -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 * @@ -133,23 +133,19 @@ namespace http { static void ShowTunnelDetails (std::stringstream& s, enum i2p::tunnel::TunnelState eState, bool explr, int bytes) { std::string state, stateText; - switch (eState) { + switch (eState) + { case i2p::tunnel::eTunnelStateBuildReplyReceived : case i2p::tunnel::eTunnelStatePending : state = "building"; break; - case i2p::tunnel::eTunnelStateBuildFailed : - case i2p::tunnel::eTunnelStateTestFailed : + case i2p::tunnel::eTunnelStateBuildFailed : state = "failed"; stateText = "declined"; break; + case i2p::tunnel::eTunnelStateTestFailed : state = "failed"; stateText = "test failed"; break; case i2p::tunnel::eTunnelStateFailed : state = "failed"; break; case i2p::tunnel::eTunnelStateExpiring : state = "expiring"; break; case i2p::tunnel::eTunnelStateEstablished : state = "established"; break; default: state = "unknown"; break; } - - if (state == "building") stateText = tr("building"); - else if (state == "failed") stateText = tr("failed"); - else if (state == "expiring") stateText = tr("expiring"); - else if (state == "established") stateText = tr("established"); - else stateText = tr("unknown"); - + if (stateText.empty ()) stateText = tr(state); + s << " " << stateText << ((explr) ? " (" + tr("exploratory") + ")" : "") << ", "; ShowTraffic(s, bytes); s << "\r\n"; diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index b578217f..d46da5b9 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -250,7 +250,7 @@ namespace tunnel void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr&& msg) { - if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive + if (GetState () != eTunnelStateExpiring) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive EncryptTunnelMsg (msg, msg); msg->from = GetSharedFromThis (); m_Endpoint.HandleDecryptedTunnelDataMsg (msg); diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 93df99be..dc43a025 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -461,7 +461,7 @@ namespace tunnel // restore from test failed state if any if (test.first) { - if (test.first->GetState () == eTunnelStateTestFailed) + if (test.first->GetState () != eTunnelStateExpiring) test.first->SetState (eTunnelStateEstablished); // update latency uint64_t latency = 0; @@ -471,7 +471,7 @@ namespace tunnel } if (test.second) { - if (test.second->GetState () == eTunnelStateTestFailed) + if (test.second->GetState () != eTunnelStateExpiring) test.second->SetState (eTunnelStateEstablished); // update latency uint64_t latency = 0; From 56619caa71bdf306dbd480445d6e2835a5ec603d Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 14 Feb 2024 20:16:36 -0500 Subject: [PATCH 067/787] random shuffle of tunnels for peer test pairs --- libi2pd/TunnelPool.cpp | 56 +++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index dc43a025..2e306ba3 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -361,31 +361,43 @@ namespace tunnel // new tests std::vector, std::shared_ptr > > newTests; + std::random_device rd; + std::mt19937 rnd(rd()); + std::vector > outboundTunnels; { - std::unique_lock l1(m_OutboundTunnelsMutex); - auto it1 = m_OutboundTunnels.begin (); - std::unique_lock l2(m_InboundTunnelsMutex); - auto it2 = m_InboundTunnels.begin (); - while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ()) + std::unique_lock l(m_OutboundTunnelsMutex); + for (auto& it: m_OutboundTunnels) + outboundTunnels.push_back (it); + } + std::shuffle (outboundTunnels.begin(), outboundTunnels.end(), rnd); + std::vector > inboundTunnels; + { + std::unique_lock l(m_InboundTunnelsMutex); + for (auto& it: m_InboundTunnels) + inboundTunnels.push_back (it); + } + std::shuffle (inboundTunnels.begin(), inboundTunnels.end(), rnd); + auto it1 = outboundTunnels.begin (); + auto it2 = inboundTunnels.begin (); + while (it1 != outboundTunnels.end () && it2 != inboundTunnels.end ()) + { + bool failed = false; + if ((*it1)->IsFailed ()) { - bool failed = false; - if ((*it1)->IsFailed ()) - { - failed = true; - ++it1; - } - if ((*it2)->IsFailed ()) - { - failed = true; - ++it2; - } - if (!failed) - { - newTests.push_back(std::make_pair (*it1, *it2)); - ++it1; ++it2; - } + failed = true; + ++it1; } - } + if ((*it2)->IsFailed ()) + { + failed = true; + ++it2; + } + if (!failed) + { + newTests.push_back(std::make_pair (*it1, *it2)); + ++it1; ++it2; + } + } for (auto& it: newTests) { uint32_t msgID; From dddbca6ffbd316cb4195181e955a804d17dfd2ff Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 14 Feb 2024 21:35:41 -0500 Subject: [PATCH 068/787] common rng for random shuffle --- libi2pd/Tunnel.cpp | 2 +- libi2pd/TunnelPool.cpp | 9 +++------ libi2pd/TunnelPool.h | 6 ++++++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index d46da5b9..ac0418d7 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -52,7 +52,7 @@ namespace tunnel // shuffle records std::vector recordIndicies; for (int i = 0; i < numRecords; i++) recordIndicies.push_back(i); - std::shuffle (recordIndicies.begin(), recordIndicies.end(), std::mt19937(std::random_device()())); + std::shuffle (recordIndicies.begin(), recordIndicies.end(), m_Pool ? m_Pool->GetRng () : std::mt19937(std::random_device()())); // create real records uint8_t * records = msg->GetPayload () + 1; diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 2e306ba3..550a75c5 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -7,7 +7,6 @@ */ #include -#include #include "I2PEndian.h" #include "Crypto.h" #include "Tunnel.h" @@ -45,7 +44,7 @@ namespace tunnel m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops), m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_InboundVariance (inboundVariance), m_OutboundVariance (outboundVariance), - m_IsActive (true), m_CustomPeerSelector(nullptr) + m_IsActive (true), m_CustomPeerSelector(nullptr), m_Rng(m_Rd()) { if (m_NumInboundTunnels > TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY) m_NumInboundTunnels = TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY; @@ -361,22 +360,20 @@ namespace tunnel // new tests std::vector, std::shared_ptr > > newTests; - std::random_device rd; - std::mt19937 rnd(rd()); std::vector > outboundTunnels; { std::unique_lock l(m_OutboundTunnelsMutex); for (auto& it: m_OutboundTunnels) outboundTunnels.push_back (it); } - std::shuffle (outboundTunnels.begin(), outboundTunnels.end(), rnd); + std::shuffle (outboundTunnels.begin(), outboundTunnels.end(), m_Rng); std::vector > inboundTunnels; { std::unique_lock l(m_InboundTunnelsMutex); for (auto& it: m_InboundTunnels) inboundTunnels.push_back (it); } - std::shuffle (inboundTunnels.begin(), inboundTunnels.end(), rnd); + std::shuffle (inboundTunnels.begin(), inboundTunnels.end(), m_Rng); auto it1 = outboundTunnels.begin (); auto it2 = inboundTunnels.begin (); while (it1 != outboundTunnels.end () && it2 != inboundTunnels.end ()) diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index 7cb1f5c9..3d3d4e33 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "Identity.h" #include "LeaseSet.h" #include "RouterInfo.h" @@ -115,6 +116,8 @@ namespace tunnel std::shared_ptr SelectNextHop (std::shared_ptr prevHop, bool reverse, bool endpoint) const; bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop); + std::mt19937& GetRng () { return m_Rng; } + private: void TestTunnels (); @@ -148,6 +151,9 @@ namespace tunnel uint64_t m_MinLatency = 0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms uint64_t m_MaxLatency = 0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms + std::random_device m_Rd; + std::mt19937 m_Rng; + public: // for HTTP only From d8be5b8ce1876f28615e051b683c840481c1b00f Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 14 Feb 2024 21:58:03 -0500 Subject: [PATCH 069/787] fixed warning --- libi2pd/Socks5.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Socks5.h b/libi2pd/Socks5.h index d611bff3..8db8939b 100644 --- a/libi2pd/Socks5.h +++ b/libi2pd/Socks5.h @@ -63,7 +63,7 @@ namespace transport { len += 2; // port boost::asio::async_read(s, boost::asio::buffer(readbuff->data (), len), boost::asio::transfer_all(), - [readbuff, &s, handler](const boost::system::error_code& ec, std::size_t transferred) + [readbuff, handler](const boost::system::error_code& ec, std::size_t transferred) { if (!ec) handler (boost::system::error_code ()); // success From def404b61aceaf02ff247392f56984430b90aa6b Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 14 Feb 2024 22:19:07 -0500 Subject: [PATCH 070/787] skip failed and expiring tunnels for peer tests --- libi2pd/TunnelPool.cpp | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 550a75c5..5b472232 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -364,36 +364,24 @@ namespace tunnel { std::unique_lock l(m_OutboundTunnelsMutex); for (auto& it: m_OutboundTunnels) - outboundTunnels.push_back (it); + if (it->IsEstablished () || it->GetState () == eTunnelStateTestFailed) + outboundTunnels.push_back (it); } std::shuffle (outboundTunnels.begin(), outboundTunnels.end(), m_Rng); std::vector > inboundTunnels; { std::unique_lock l(m_InboundTunnelsMutex); for (auto& it: m_InboundTunnels) - inboundTunnels.push_back (it); + if (it->IsEstablished () || it->GetState () == eTunnelStateTestFailed) + inboundTunnels.push_back (it); } std::shuffle (inboundTunnels.begin(), inboundTunnels.end(), m_Rng); auto it1 = outboundTunnels.begin (); auto it2 = inboundTunnels.begin (); while (it1 != outboundTunnels.end () && it2 != inboundTunnels.end ()) { - bool failed = false; - if ((*it1)->IsFailed ()) - { - failed = true; - ++it1; - } - if ((*it2)->IsFailed ()) - { - failed = true; - ++it2; - } - if (!failed) - { - newTests.push_back(std::make_pair (*it1, *it2)); - ++it1; ++it2; - } + newTests.push_back(std::make_pair (*it1, *it2)); + ++it1; ++it2; } for (auto& it: newTests) { From 6439e227f67d88cb9bc6ac95c04b397faa148727 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 15 Feb 2024 19:29:33 -0500 Subject: [PATCH 071/787] consider test failed state as established. Delete failed tunnels sooner --- libi2pd/Tunnel.cpp | 9 +++++---- libi2pd/Tunnel.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index ac0418d7..3e10ef1b 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -679,9 +679,10 @@ namespace tunnel for (auto it = m_OutboundTunnels.begin (); it != m_OutboundTunnels.end ();) { auto tunnel = *it; - if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) + if (tunnel->IsFailed () || ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT || + ts + TUNNEL_EXPIRATION_TIMEOUT < tunnel->GetCreationTime ()) { - LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired"); + LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired or failed"); auto pool = tunnel->GetTunnelPool (); if (pool) pool->TunnelExpired (tunnel); @@ -730,10 +731,10 @@ namespace tunnel for (auto it = m_InboundTunnels.begin (); it != m_InboundTunnels.end ();) { auto tunnel = *it; - if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT || + if (tunnel->IsFailed () || ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT || ts + TUNNEL_EXPIRATION_TIMEOUT < tunnel->GetCreationTime ()) { - LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired"); + LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired or failed"); auto pool = tunnel->GetTunnelPool (); if (pool) pool->TunnelExpired (tunnel); diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 47ff0465..a0815cba 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -91,7 +91,7 @@ namespace tunnel i2p::data::RouterInfo::CompatibleTransports GetFarEndTransports () const { return m_FarEndTransports; }; TunnelState GetState () const { return m_State; }; void SetState (TunnelState state); - bool IsEstablished () const { return m_State == eTunnelStateEstablished; }; + bool IsEstablished () const { return m_State == eTunnelStateEstablished || m_State == eTunnelStateTestFailed; }; bool IsFailed () const { return m_State == eTunnelStateFailed; }; bool IsRecreated () const { return m_IsRecreated; }; void SetRecreated (bool recreated) { m_IsRecreated = recreated; }; From 441e847de8278d3cc9703ec9bbefec836296ff8f Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 16 Feb 2024 14:49:12 -0500 Subject: [PATCH 072/787] don't try to decrypt dulpicate message --- libi2pd/Garlic.cpp | 18 +++++++++++++++--- libi2pd/Garlic.h | 4 ++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 3f885186..7157052c 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -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 * @@ -588,11 +588,17 @@ namespace garlic auto it = m_ECIESx25519Tags.find (tag); if (it != m_ECIESx25519Tags.end ()) { - if (it->second.tagset && it->second.tagset->HandleNextMessage (buf, len, it->second.index)) + if (!it->second.tagset) return true; // duplicate + if (it->second.tagset->HandleNextMessage (buf, len, it->second.index)) + { m_LastTagset = it->second.tagset; + it->second.tagset = nullptr; // mark as used + } else + { LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); - m_ECIESx25519Tags.erase (it); + m_ECIESx25519Tags.erase (it); + } return true; } return false; @@ -879,6 +885,12 @@ namespace garlic numExpiredTags = 0; for (auto it = m_ECIESx25519Tags.begin (); it != m_ECIESx25519Tags.end ();) { + if (!it->second.tagset) + { + // delete used tag + it = m_ECIESx25519Tags.erase (it); + continue; + } if (it->second.tagset->IsExpired (ts) || it->second.tagset->IsIndexExpired (it->second.index)) { it->second.tagset->DeleteSymmKey (it->second.index); diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index b926abda..83e3b050 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -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 * @@ -221,7 +221,7 @@ namespace garlic struct ECIESX25519AEADRatchetIndexTagset { int index; - ReceiveRatchetTagSetPtr tagset; + ReceiveRatchetTagSetPtr tagset; // null if used }; class GarlicDestination: public i2p::data::LocalDestination From 900153765abbe87101a586f9648d21ee97d7a1b3 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 16 Feb 2024 18:56:04 -0500 Subject: [PATCH 073/787] move router's tags cleanup to router's thread --- libi2pd/NetDb.cpp | 9 +-------- libi2pd/RouterContext.cpp | 39 ++++++++++++++++++++++++++------------- libi2pd/RouterContext.h | 8 +++++--- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index e8c92658..0adeb2e7 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -106,7 +106,7 @@ namespace data { i2p::util::SetThreadName("NetDB"); - uint64_t lastManage = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0; + uint64_t lastManage = 0, lastExploratory = 0, lastManageRequest = 0; uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch (); int16_t profilesCleanupVariance = 0; @@ -165,13 +165,6 @@ namespace data lastManage = ts; } - if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT || - ts + i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT < lastDestinationCleanup) - { - i2p::context.CleanupDestination (); - lastDestinationCleanup = ts; - } - if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance) || ts + i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT < lastProfilesCleanup) { diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 40949891..02ebf22c 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -61,9 +61,11 @@ namespace i2p { m_PublishTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ())); ScheduleInitialPublish (); - m_CongestionUpdateTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ())); - ScheduleCongestionUpdate (); } + m_CongestionUpdateTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ())); + ScheduleCongestionUpdate (); + m_CleanupTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ())); + ScheduleCleanupTimer (); } } @@ -1223,17 +1225,6 @@ namespace i2p else LogPrint (eLogError, "Router: service is NULL"); } - - void RouterContext::CleanupDestination () - { - if (m_Service) - m_Service->GetService ().post ([this]() - { - this->i2p::garlic::GarlicDestination::CleanupExpiredTags (); - }); - else - LogPrint (eLogError, "Router: service is NULL"); - } uint32_t RouterContext::GetUptime () const { @@ -1465,4 +1456,26 @@ namespace i2p ScheduleCongestionUpdate (); } } + + void RouterContext::ScheduleCleanupTimer () + { + if (m_CleanupTimer) + { + m_CleanupTimer->cancel (); + m_CleanupTimer->expires_from_now (boost::posix_time::minutes(ROUTER_INFO_CLEANUP_INTERVAL)); + m_CleanupTimer->async_wait (std::bind (&RouterContext::HandleCleanupTimer, + this, std::placeholders::_1)); + } + else + LogPrint (eLogError, "Router: Cleanup timer is NULL"); + } + + void RouterContext::HandleCleanupTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + CleanupExpiredTags (); + ScheduleCleanupTimer (); + } + } } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index ddfc65de..d85ef282 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -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 * @@ -38,6 +38,7 @@ namespace garlic const int ROUTER_INFO_CONFIRMATION_TIMEOUT = 5; // in seconds const int ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15; const int ROUTER_INFO_CONGESTION_UPDATE_INTERVAL = 12*60; // in seconds + const int ROUTER_INFO_CLEANUP_INTERVAL = 5; // in minutes enum RouterStatus { @@ -181,7 +182,6 @@ namespace garlic void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove void UpdateStats (); void UpdateTimestamp (uint64_t ts); // in seconds, called from NetDb before publishing - void CleanupDestination (); // garlic destination // implements LocalDestination std::shared_ptr GetIdentity () const { return m_Keys.GetPublic (); }; @@ -230,6 +230,8 @@ namespace garlic void HandlePublishResendTimer (const boost::system::error_code& ecode); void ScheduleCongestionUpdate (); void HandleCongestionUpdateTimer (const boost::system::error_code& ecode); + void ScheduleCleanupTimer (); + void HandleCleanupTimer (const boost::system::error_code& ecode); private: @@ -253,7 +255,7 @@ namespace garlic i2p::crypto::NoiseSymmetricState m_InitialNoiseState, m_CurrentNoiseState; // publish std::unique_ptr m_Service; - std::unique_ptr m_PublishTimer, m_CongestionUpdateTimer; + std::unique_ptr m_PublishTimer, m_CongestionUpdateTimer, m_CleanupTimer; std::set m_PublishExcluded; uint32_t m_PublishReplyToken; bool m_IsHiddenMode; // not publish From 2b6a95cbee8c5216beafbac6116ade4c5230cfc2 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 16 Feb 2024 21:30:40 -0500 Subject: [PATCH 074/787] don't check session for symmetric key tagset. re-create tags hash if too many used tags --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 6 +++ libi2pd/ECIESX25519AEADRatchetSession.h | 10 ++-- libi2pd/Garlic.cpp | 56 +++++++++++++++-------- libi2pd/Garlic.h | 3 +- 4 files changed, 52 insertions(+), 23 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 6f56f2e5..3513b7ac 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -117,6 +117,12 @@ namespace garlic return session->HandleNextMessage (buf, len, shared_from_this (), index); } + bool ReceiveRatchetTagSet::IsSessionTerminated () const + { + return !m_Session || m_Session->IsTerminated (); + } + + SymmetricKeyTagSet::SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key): ReceiveRatchetTagSet (nullptr), m_Destination (destination) { diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 517833e8..030e2c45 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -86,7 +86,8 @@ namespace garlic virtual bool IsIndexExpired (int index) const; virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index); - + virtual bool IsSessionTerminated () const; + private: int m_TrimBehindIndex = 0; @@ -101,9 +102,10 @@ namespace garlic SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key); - bool IsIndexExpired (int index) const { return false; }; - bool HandleNextMessage (uint8_t * buf, size_t len, int index); - + bool IsIndexExpired (int index) const override { return false; }; + bool HandleNextMessage (uint8_t * buf, size_t len, int index) override; + bool IsSessionTerminated () const override { return false; } + private: GarlicDestination * m_Destination; diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 7157052c..ba35995f 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -431,7 +431,8 @@ namespace garlic } GarlicDestination::GarlicDestination (): m_NumTags (32), // 32 tags by default - m_PayloadBuffer (nullptr), m_NumRatchetInboundTags (0) // 0 means standard + m_PayloadBuffer (nullptr), m_NumRatchetInboundTags (0), // 0 means standard + m_NumUsedECIESx25519Tags (0) { } @@ -599,6 +600,7 @@ namespace garlic LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); m_ECIESx25519Tags.erase (it); } + m_NumUsedECIESx25519Tags++; return true; } return false; @@ -883,24 +885,41 @@ namespace garlic } numExpiredTags = 0; - for (auto it = m_ECIESx25519Tags.begin (); it != m_ECIESx25519Tags.end ();) + if (m_NumUsedECIESx25519Tags > ECIESX25519_TAGSET_MAX_NUM_TAGS) // too many used tags { - if (!it->second.tagset) + std::unordered_map oldTags; + std::swap (m_ECIESx25519Tags, oldTags); // re-create + for (auto& it: oldTags) + if (it.second.tagset) + { + if (it.second.tagset->IsExpired (ts) || it.second.tagset->IsIndexExpired (it.second.index)) + { + it.second.tagset->DeleteSymmKey (it.second.index); + numExpiredTags++; + } + else if (it.second.tagset->IsSessionTerminated()) + numExpiredTags++; + else + m_ECIESx25519Tags.emplace (it); + } + } + else + { + for (auto it = m_ECIESx25519Tags.begin (); it != m_ECIESx25519Tags.end ();) { - // delete used tag - it = m_ECIESx25519Tags.erase (it); - continue; - } - if (it->second.tagset->IsExpired (ts) || it->second.tagset->IsIndexExpired (it->second.index)) - { - it->second.tagset->DeleteSymmKey (it->second.index); - it = m_ECIESx25519Tags.erase (it); - numExpiredTags++; - } - else - { - auto session = it->second.tagset->GetSession (); - if (!session || session->IsTerminated()) + if (!it->second.tagset) + { + // delete used tag + it = m_ECIESx25519Tags.erase (it); + continue; + } + if (it->second.tagset->IsExpired (ts) || it->second.tagset->IsIndexExpired (it->second.index)) + { + it->second.tagset->DeleteSymmKey (it->second.index); + it = m_ECIESx25519Tags.erase (it); + numExpiredTags++; + } + else if (it->second.tagset->IsSessionTerminated()) { it = m_ECIESx25519Tags.erase (it); numExpiredTags++; @@ -908,7 +927,8 @@ namespace garlic else ++it; } - } + } + m_NumUsedECIESx25519Tags = 0; if (numExpiredTags > 0) LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " ECIESx25519 tags expired for ", GetIdentHash().ToBase64 ()); if (m_LastTagset && m_LastTagset->IsExpired (ts)) diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 83e3b050..0386752b 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -291,6 +291,7 @@ namespace garlic std::unordered_map, std::hash > > m_Tags; std::unordered_map m_ECIESx25519Tags; // session tag -> session ReceiveRatchetTagSetPtr m_LastTagset; // tagset last message came for + int m_NumUsedECIESx25519Tags; // DeliveryStatus std::mutex m_DeliveryStatusSessionsMutex; std::unordered_map m_DeliveryStatusSessions; // msgID -> session @@ -299,7 +300,7 @@ namespace garlic // for HTTP only size_t GetNumIncomingTags () const { return m_Tags.size (); } - size_t GetNumIncomingECIESx25519Tags () const { return m_ECIESx25519Tags.size (); } + size_t GetNumIncomingECIESx25519Tags () const { return m_ECIESx25519Tags.size () - m_NumUsedECIESx25519Tags; } const decltype(m_Sessions)& GetSessions () const { return m_Sessions; }; const decltype(m_ECIESx25519Sessions)& GetECIESx25519Sessions () const { return m_ECIESx25519Sessions; } }; From 7e3157b162b644e8624aaea1057fb712052c4761 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 18 Feb 2024 21:28:06 -0500 Subject: [PATCH 075/787] don't process packet in terminated stream --- libi2pd/Streaming.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 74fb3d97..fa809c19 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -129,6 +129,11 @@ namespace stream void Stream::HandleNextPacket (Packet * packet) { + if (m_Status == eStreamStatusTerminated) + { + m_LocalDestination.DeletePacket (packet); + return; + } m_NumReceivedBytes += packet->GetLength (); if (!m_SendStreamID) { @@ -159,7 +164,8 @@ namespace stream { // we have received next in sequence message ProcessPacket (packet); - + if (m_Status == eStreamStatusTerminated) return; + // we should also try stored messages if any for (auto it = m_SavedPackets.begin (); it != m_SavedPackets.end ();) { @@ -169,6 +175,7 @@ namespace stream m_SavedPackets.erase (it++); ProcessPacket (savedPacket); + if (m_Status == eStreamStatusTerminated) return; } else break; From d677d67676eed2d84384797a6b662758878446bb Mon Sep 17 00:00:00 2001 From: Vort Date: Sun, 18 Feb 2024 22:54:43 +0200 Subject: [PATCH 076/787] implement medium congestion indication --- libi2pd/I2NPProtocol.cpp | 4 +- libi2pd/RouterContext.cpp | 25 +++++++---- libi2pd/RouterContext.h | 2 +- libi2pd/Transports.cpp | 87 ++++++++++++++++++++++++--------------- libi2pd/Transports.h | 26 ++++++++---- libi2pd/Tunnel.h | 2 +- 6 files changed, 92 insertions(+), 54 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 70cefbdc..78493df2 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -376,7 +376,7 @@ namespace i2p if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false; uint8_t retCode = 0; // replace record to reply - if (i2p::context.AcceptsTunnels () && !i2p::context.IsHighCongestion ()) + if (i2p::context.AcceptsTunnels () && i2p::context.GetCongestionLevel (false) < 100) { auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), @@ -586,7 +586,7 @@ namespace i2p // check if we accept this tunnel std::shared_ptr transitTunnel; uint8_t retCode = 0; - if (!i2p::context.AcceptsTunnels () || i2p::context.IsHighCongestion ()) + if (!i2p::context.AcceptsTunnels () || i2p::context.GetCongestionLevel (false) >= 100) retCode = 30; if (!retCode) { diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 02ebf22c..64dd43e4 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -1137,13 +1137,14 @@ namespace i2p return i2p::tunnel::tunnels.GetExploratoryPool (); } - bool RouterContext::IsHighCongestion () const + int RouterContext::GetCongestionLevel (bool longTerm) const { - return i2p::tunnel::tunnels.IsTooManyTransitTunnels () || - i2p::transport::transports.IsBandwidthExceeded () || - i2p::transport::transports.IsTransitBandwidthExceeded (); - } - + return std::max ( + i2p::tunnel::tunnels.GetCongestionLevel (), + i2p::transport::transports.GetCongestionLevel (longTerm) + ); + } + void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len) { i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len))); @@ -1447,10 +1448,16 @@ namespace i2p if (ecode != boost::asio::error::operation_aborted) { auto c = i2p::data::RouterInfo::eLowCongestion; - if (!AcceptsTunnels ()) + if (!AcceptsTunnels () || m_ShareRatio == 0) c = i2p::data::RouterInfo::eRejectAll; - else if (IsHighCongestion ()) - c = i2p::data::RouterInfo::eHighCongestion; + else + { + int congestionLevel = GetCongestionLevel (true); + if (congestionLevel > 90) + c = i2p::data::RouterInfo::eHighCongestion; + else if (congestionLevel > 70) + c = i2p::data::RouterInfo::eMediumCongestion; + } if (m_RouterInfo.UpdateCongestion (c)) UpdateRouterInfo (); ScheduleCongestionUpdate (); diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index d85ef282..062c187d 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -167,7 +167,7 @@ namespace garlic void SetShareRatio (int percents); // 0 - 100 bool AcceptsTunnels () const { return m_AcceptsTunnels; }; void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; }; - bool IsHighCongestion () const; + int GetCongestionLevel (bool longTerm) const; bool SupportsV6 () const { return m_RouterInfo.IsV6 (); }; bool SupportsV4 () const { return m_RouterInfo.IsV4 (); }; bool SupportsMesh () const { return m_RouterInfo.IsMesh (); }; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 0afe47a1..a3914d7c 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -140,10 +140,8 @@ namespace transport m_X25519KeysPairSupplier (15), // 15 pre-generated keys m_TotalSentBytes (0), m_TotalReceivedBytes (0), m_TotalTransitTransmittedBytes (0), m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth (0), - m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), m_LastTransitBandwidthUpdateBytes (0), m_InBandwidth15s (0), m_OutBandwidth15s (0), m_TransitBandwidth15s (0), - m_LastInBandwidth15sUpdateBytes (0), m_LastOutBandwidth15sUpdateBytes (0), m_LastTransitBandwidth15sUpdateBytes (0), - m_LastBandwidth15sUpdateTime (0) + m_InBandwidth5m (0), m_OutBandwidth5m (0), m_TransitBandwidth5m (0) { } @@ -306,6 +304,16 @@ namespace transport m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5 * SESSION_CREATION_TIMEOUT)); m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); + uint64_t ts = i2p::util::GetMillisecondsSinceEpoch(); + for (int i = 0; i < TRAFFIC_SAMPLE_COUNT; i++) + { + m_TrafficSamples[i].Timestamp = ts - (TRAFFIC_SAMPLE_COUNT - i - 1) * 1000; + m_TrafficSamples[i].TotalReceivedBytes = 0; + m_TrafficSamples[i].TotalSentBytes = 0; + m_TrafficSamples[i].TotalTransitTransmittedBytes = 0; + } + m_TrafficSamplePtr = TRAFFIC_SAMPLE_COUNT - 1; + m_UpdateBandwidthTimer->expires_from_now (boost::posix_time::seconds(1)); m_UpdateBandwidthTimer->async_wait (std::bind (&Transports::HandleUpdateBandwidthTimer, this, std::placeholders::_1)); @@ -364,51 +372,62 @@ namespace transport } } + void Transports::UpdateBandwidthValues(int interval, uint32_t& in, uint32_t& out, uint32_t& transit) + { + TrafficSample& sample1 = m_TrafficSamples[m_TrafficSamplePtr]; + TrafficSample& sample2 = m_TrafficSamples[(TRAFFIC_SAMPLE_COUNT + m_TrafficSamplePtr - interval) % TRAFFIC_SAMPLE_COUNT]; + auto delta = sample1.Timestamp - sample2.Timestamp; + in = (sample1.TotalReceivedBytes - sample2.TotalReceivedBytes) * 1000 / delta; + out = (sample1.TotalSentBytes - sample2.TotalSentBytes) * 1000 / delta; + transit = (sample1.TotalTransitTransmittedBytes - sample2.TotalTransitTransmittedBytes) * 1000 / delta; + } + void Transports::HandleUpdateBandwidthTimer (const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) { - uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); + m_TrafficSamplePtr++; + if (m_TrafficSamplePtr == TRAFFIC_SAMPLE_COUNT) + m_TrafficSamplePtr = 0; - // updated every second - m_InBandwidth = m_TotalReceivedBytes - m_LastInBandwidthUpdateBytes; - m_OutBandwidth = m_TotalSentBytes - m_LastOutBandwidthUpdateBytes; - m_TransitBandwidth = m_TotalTransitTransmittedBytes - m_LastTransitBandwidthUpdateBytes; + TrafficSample& sample = m_TrafficSamples[m_TrafficSamplePtr]; + sample.Timestamp = i2p::util::GetMillisecondsSinceEpoch(); + sample.TotalReceivedBytes = m_TotalReceivedBytes; + sample.TotalSentBytes = m_TotalSentBytes; + sample.TotalTransitTransmittedBytes = m_TotalTransitTransmittedBytes; - m_LastInBandwidthUpdateBytes = m_TotalReceivedBytes; - m_LastOutBandwidthUpdateBytes = m_TotalSentBytes; - m_LastTransitBandwidthUpdateBytes = m_TotalTransitTransmittedBytes; - - // updated every 15 seconds - auto delta = ts - m_LastBandwidth15sUpdateTime; - if (delta > 15 * 1000) - { - m_InBandwidth15s = (m_TotalReceivedBytes - m_LastInBandwidth15sUpdateBytes) * 1000 / delta; - m_OutBandwidth15s = (m_TotalSentBytes - m_LastOutBandwidth15sUpdateBytes) * 1000 / delta; - m_TransitBandwidth15s = (m_TotalTransitTransmittedBytes - m_LastTransitBandwidth15sUpdateBytes) * 1000 / delta; - - m_LastBandwidth15sUpdateTime = ts; - m_LastInBandwidth15sUpdateBytes = m_TotalReceivedBytes; - m_LastOutBandwidth15sUpdateBytes = m_TotalSentBytes; - m_LastTransitBandwidth15sUpdateBytes = m_TotalTransitTransmittedBytes; - } + UpdateBandwidthValues (1, m_InBandwidth, m_OutBandwidth, m_TransitBandwidth); + UpdateBandwidthValues (15, m_InBandwidth15s, m_OutBandwidth15s, m_TransitBandwidth15s); + UpdateBandwidthValues (300, m_InBandwidth5m, m_OutBandwidth5m, m_TransitBandwidth5m); m_UpdateBandwidthTimer->expires_from_now (boost::posix_time::seconds(1)); m_UpdateBandwidthTimer->async_wait (std::bind (&Transports::HandleUpdateBandwidthTimer, this, std::placeholders::_1)); } } - bool Transports::IsBandwidthExceeded () const + int Transports::GetCongestionLevel (bool longTerm) const { - auto limit = i2p::context.GetBandwidthLimit() * 1024; // convert to bytes - auto bw = std::max (m_InBandwidth15s, m_OutBandwidth15s); - return bw > limit; - } + auto bwLimit = i2p::context.GetBandwidthLimit () * 1024; // convert to bytes + auto tbwLimit = i2p::context.GetTransitBandwidthLimit () * 1024; // convert to bytes - bool Transports::IsTransitBandwidthExceeded () const - { - auto limit = i2p::context.GetTransitBandwidthLimit() * 1024; // convert to bytes - return m_TransitBandwidth > limit; + if (tbwLimit == 0 || bwLimit == 0) + return 100; + + uint32_t bw; + uint32_t tbw; + if (longTerm) + { + bw = std::max (m_InBandwidth5m, m_OutBandwidth5m); + tbw = m_TransitBandwidth5m; + } + else + { + bw = std::max (m_InBandwidth15s, m_OutBandwidth15s); + tbw = m_TransitBandwidth; + } + auto bwCongestionLevel = 100 * bw / bwLimit; + auto tbwCongestionLevel = 100 * tbw / tbwLimit; + return std::max (bwCongestionLevel, tbwCongestionLevel); } void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg) diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 206b0256..92d75efd 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -114,6 +114,17 @@ namespace transport const int PEER_TEST_DELAY_INTERVAL_VARIANCE = 30; // in milliseconds const int MAX_NUM_DELAYED_MESSAGES = 150; const int CHECK_PROFILE_NUM_DELAYED_MESSAGES = 15; // check profile after + + const int TRAFFIC_SAMPLE_COUNT = 301; // seconds + + struct TrafficSample + { + uint64_t Timestamp; + uint64_t TotalReceivedBytes; + uint64_t TotalSentBytes; + uint64_t TotalTransitTransmittedBytes; + }; + class Transports { public: @@ -153,8 +164,7 @@ namespace transport uint32_t GetInBandwidth15s () const { return m_InBandwidth15s; }; uint32_t GetOutBandwidth15s () const { return m_OutBandwidth15s; }; uint32_t GetTransitBandwidth15s () const { return m_TransitBandwidth15s; }; - bool IsBandwidthExceeded () const; - bool IsTransitBandwidthExceeded () const; + int GetCongestionLevel (bool longTerm) const; size_t GetNumPeers () const { return m_Peers.size (); }; std::shared_ptr GetRandomPeer (bool isHighBandwidth) const; @@ -186,6 +196,7 @@ namespace transport void HandlePeerCleanupTimer (const boost::system::error_code& ecode); void HandlePeerTestTimer (const boost::system::error_code& ecode); void HandleUpdateBandwidthTimer (const boost::system::error_code& ecode); + void UpdateBandwidthValues (int interval, uint32_t& in, uint32_t& out, uint32_t& transit); void DetectExternalIP (); @@ -210,14 +221,15 @@ namespace transport std::atomic m_TotalSentBytes, m_TotalReceivedBytes, m_TotalTransitTransmittedBytes; + TrafficSample m_TrafficSamples[TRAFFIC_SAMPLE_COUNT]; + int m_TrafficSamplePtr; + // Bandwidth per second uint32_t m_InBandwidth, m_OutBandwidth, m_TransitBandwidth; - uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes, m_LastTransitBandwidthUpdateBytes; - - // Bandwidth every 15 seconds + // Bandwidth during last 15 seconds uint32_t m_InBandwidth15s, m_OutBandwidth15s, m_TransitBandwidth15s; - uint64_t m_LastInBandwidth15sUpdateBytes, m_LastOutBandwidth15sUpdateBytes, m_LastTransitBandwidth15sUpdateBytes; - uint64_t m_LastBandwidth15sUpdateTime; + // Bandwidth during last 5 minutes + uint32_t m_InBandwidth5m, m_OutBandwidth5m, m_TransitBandwidth5m; /** which router families to trust for first hops */ std::vector m_TrustedFamilies; diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index a0815cba..0b125c70 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -240,7 +240,7 @@ namespace tunnel void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels); uint16_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; }; - bool IsTooManyTransitTunnels () const { return m_TransitTunnels.size () >= m_MaxNumTransitTunnels; }; + int GetCongestionLevel() const { return 100 * m_TransitTunnels.size() / m_MaxNumTransitTunnels; } private: From a4a3f8e96b55c83bcf3af66abf7e500cd47684b8 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 19 Feb 2024 22:04:43 -0500 Subject: [PATCH 077/787] support upstream proxy through local sockets --- libi2pd_client/SOCKS.cpp | 77 +++++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/libi2pd_client/SOCKS.cpp b/libi2pd_client/SOCKS.cpp index 65bad1cf..3174bdb3 100644 --- a/libi2pd_client/SOCKS.cpp +++ b/libi2pd_client/SOCKS.cpp @@ -139,9 +139,11 @@ namespace proxy void HandleStreamRequestComplete (std::shared_ptr stream); void ForwardSOCKS(); - void SocksUpstreamSuccess(); + template + void SocksUpstreamSuccess(std::shared_ptr& upstreamSock); void AsyncUpstreamSockRead(); - void SendUpstreamRequest(); + template + void SendUpstreamRequest(std::shared_ptr& upstreamSock); void HandleUpstreamConnected(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr); void HandleUpstreamResolved(const boost::system::error_code & ecode, @@ -150,6 +152,9 @@ namespace proxy boost::asio::ip::tcp::resolver m_proxy_resolver; uint8_t m_sock_buff[socks_buffer_size]; std::shared_ptr m_sock, m_upstreamSock; +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + std::shared_ptr m_upstreamLocalSock; +#endif std::shared_ptr m_stream; uint8_t *m_remaining_data; //Data left to be sent uint8_t *m_remaining_upstream_data; //upstream data left to be forwarded @@ -212,6 +217,14 @@ namespace proxy m_upstreamSock->close(); m_upstreamSock = nullptr; } +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + if (m_upstreamLocalSock) + { + LogPrint(eLogDebug, "SOCKS: Closing upstream local socket"); + m_upstreamLocalSock->close(); + m_upstreamLocalSock = nullptr; + } +#endif if (m_stream) { LogPrint(eLogDebug, "SOCKS: Closing stream"); @@ -677,13 +690,45 @@ namespace proxy void SOCKSHandler::ForwardSOCKS() { LogPrint(eLogInfo, "SOCKS: Forwarding to upstream"); - EnterState(UPSTREAM_RESOLVE); - boost::asio::ip::tcp::resolver::query q(m_UpstreamProxyAddress, std::to_string(m_UpstreamProxyPort)); - m_proxy_resolver.async_resolve(q, std::bind(&SOCKSHandler::HandleUpstreamResolved, shared_from_this(), - std::placeholders::_1, std::placeholders::_2)); + if (m_UpstreamProxyPort) // TCP + { + EnterState(UPSTREAM_RESOLVE); + boost::asio::ip::tcp::resolver::query q(m_UpstreamProxyAddress, std::to_string(m_UpstreamProxyPort)); + m_proxy_resolver.async_resolve(q, std::bind(&SOCKSHandler::HandleUpstreamResolved, shared_from_this(), + std::placeholders::_1, std::placeholders::_2)); + } + else if (!m_UpstreamProxyAddress.empty ())// local + { +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + EnterState(UPSTREAM_CONNECT); + m_upstreamLocalSock = std::make_shared(GetOwner()->GetService()); + auto s = shared_from_this (); + m_upstreamLocalSock->async_connect(m_UpstreamProxyAddress, + [s](const boost::system::error_code& ecode) + { + if (ecode) + { + LogPrint(eLogWarning, "SOCKS: Could not connect to local upstream proxy: ", ecode.message()); + s->SocksRequestFailed(SOCKS5_NET_UNREACH); + return; + } + LogPrint(eLogInfo, "SOCKS: Connected to local upstream proxy"); + s->SendUpstreamRequest(s->m_upstreamLocalSock); + }); +#else + LogPrint(eLogError, "SOCKS: Local sockets for upstream proxy not supported"); + SocksRequestFailed(SOCKS5_ADDR_UNSUP); +#endif + } + else + { + LogPrint(eLogError, "SOCKS: Incorrect upstream proxy address"); + SocksRequestFailed(SOCKS5_ADDR_UNSUP); + } } - void SOCKSHandler::SocksUpstreamSuccess() + template + void SOCKSHandler::SocksUpstreamSuccess(std::shared_ptr& upstreamSock) { LogPrint(eLogInfo, "SOCKS: Upstream success"); boost::asio::const_buffers_1 response(nullptr, 0); @@ -700,27 +745,27 @@ namespace proxy break; } m_sock->send(response); - auto forwarder = CreateSocketsPipe (GetOwner(), m_sock, m_upstreamSock); - m_upstreamSock = nullptr; + auto forwarder = CreateSocketsPipe (GetOwner(), m_sock, upstreamSock); + upstreamSock = nullptr; m_sock = nullptr; GetOwner()->AddHandler(forwarder); forwarder->Start(); Terminate(); } - - void SOCKSHandler::SendUpstreamRequest() + template + void SOCKSHandler::SendUpstreamRequest(std::shared_ptr& upstreamSock) { LogPrint(eLogInfo, "SOCKS: Negotiating with upstream proxy"); EnterState(UPSTREAM_HANDSHAKE); - if (m_upstreamSock) + if (upstreamSock) { auto s = shared_from_this (); - i2p::transport::Socks5Handshake (*m_upstreamSock, std::make_pair(m_address.dns.ToString (), m_port), - [s](const boost::system::error_code& ec) + i2p::transport::Socks5Handshake (*upstreamSock, std::make_pair(m_address.dns.ToString (), m_port), + [s, &upstreamSock](const boost::system::error_code& ec) { if (!ec) - s->SocksUpstreamSuccess(); + s->SocksUpstreamSuccess(upstreamSock); else { s->SocksRequestFailed(SOCKS5_NET_UNREACH); @@ -740,7 +785,7 @@ namespace proxy return; } LogPrint(eLogInfo, "SOCKS: Connected to upstream proxy"); - SendUpstreamRequest(); + SendUpstreamRequest(m_upstreamSock); } void SOCKSHandler::HandleUpstreamResolved(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr) From 19e23b34da807476c4e1ed0dea3c1bef15df3a06 Mon Sep 17 00:00:00 2001 From: Vort Date: Tue, 20 Feb 2024 10:30:05 +0200 Subject: [PATCH 078/787] add constants for congestion levels --- libi2pd/I2NPProtocol.cpp | 4 ++-- libi2pd/I2NPProtocol.h | 4 ++++ libi2pd/RouterContext.cpp | 6 +++--- libi2pd/Transports.cpp | 6 +++--- libi2pd/Tunnel.h | 2 +- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 78493df2..a1638326 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -376,7 +376,7 @@ namespace i2p if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false; uint8_t retCode = 0; // replace record to reply - if (i2p::context.AcceptsTunnels () && i2p::context.GetCongestionLevel (false) < 100) + if (i2p::context.AcceptsTunnels () && i2p::context.GetCongestionLevel (false) < CONGESTION_LEVEL_FULL) { auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), @@ -586,7 +586,7 @@ namespace i2p // check if we accept this tunnel std::shared_ptr transitTunnel; uint8_t retCode = 0; - if (!i2p::context.AcceptsTunnels () || i2p::context.GetCongestionLevel (false) >= 100) + if (!i2p::context.AcceptsTunnels () || i2p::context.GetCongestionLevel (false) >= CONGESTION_LEVEL_FULL) retCode = 30; if (!retCode) { diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index a2877a08..36facbe3 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -139,6 +139,10 @@ namespace tunnel class TunnelPool; } + const int CONGESTION_LEVEL_MEDIUM = 70; + const int CONGESTION_LEVEL_HIGH = 90; + const int CONGESTION_LEVEL_FULL = 100; + const size_t I2NP_MAX_MESSAGE_SIZE = 62708; const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096; const size_t I2NP_MAX_MEDIUM_MESSAGE_SIZE = 16384; diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 64dd43e4..013f4dc5 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -1448,14 +1448,14 @@ namespace i2p if (ecode != boost::asio::error::operation_aborted) { auto c = i2p::data::RouterInfo::eLowCongestion; - if (!AcceptsTunnels () || m_ShareRatio == 0) + if (!AcceptsTunnels () || !m_ShareRatio) c = i2p::data::RouterInfo::eRejectAll; else { int congestionLevel = GetCongestionLevel (true); - if (congestionLevel > 90) + if (congestionLevel > CONGESTION_LEVEL_HIGH) c = i2p::data::RouterInfo::eHighCongestion; - else if (congestionLevel > 70) + else if (congestionLevel > CONGESTION_LEVEL_MEDIUM) c = i2p::data::RouterInfo::eMediumCongestion; } if (m_RouterInfo.UpdateCongestion (c)) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index a3914d7c..bb5dcecc 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -411,7 +411,7 @@ namespace transport auto tbwLimit = i2p::context.GetTransitBandwidthLimit () * 1024; // convert to bytes if (tbwLimit == 0 || bwLimit == 0) - return 100; + return CONGESTION_LEVEL_FULL; uint32_t bw; uint32_t tbw; @@ -425,8 +425,8 @@ namespace transport bw = std::max (m_InBandwidth15s, m_OutBandwidth15s); tbw = m_TransitBandwidth; } - auto bwCongestionLevel = 100 * bw / bwLimit; - auto tbwCongestionLevel = 100 * tbw / tbwLimit; + auto bwCongestionLevel = CONGESTION_LEVEL_FULL * bw / bwLimit; + auto tbwCongestionLevel = CONGESTION_LEVEL_FULL * tbw / tbwLimit; return std::max (bwCongestionLevel, tbwCongestionLevel); } diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 0b125c70..cc5b9461 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -240,7 +240,7 @@ namespace tunnel void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels); uint16_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; }; - int GetCongestionLevel() const { return 100 * m_TransitTunnels.size() / m_MaxNumTransitTunnels; } + int GetCongestionLevel() const { return CONGESTION_LEVEL_FULL * m_TransitTunnels.size() / m_MaxNumTransitTunnels; } private: From b092e712ec0d9616eef7d73eb2d9e2bd11afba6d Mon Sep 17 00:00:00 2001 From: Vort Date: Tue, 20 Feb 2024 17:39:48 +0200 Subject: [PATCH 079/787] make more attempts to select not bad hop --- libi2pd/NetDb.cpp | 2 +- libi2pd/TunnelPool.cpp | 22 +++++++++++++++++----- libi2pd/TunnelPool.h | 1 + 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 0adeb2e7..bfd07df3 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1257,7 +1257,7 @@ namespace data std::shared_ptr NetDb::GetRandomRouter (Filter filter) const { if (m_RouterInfos.empty()) - return 0; + return nullptr; uint16_t inds[3]; RAND_bytes ((uint8_t *)inds, sizeof (inds)); std::lock_guard l(m_RouterInfosMutex); diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 5b472232..c342d546 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -494,11 +494,23 @@ namespace tunnel std::shared_ptr TunnelPool::SelectNextHop (std::shared_ptr prevHop, bool reverse, bool endpoint) const { - auto hop = IsExploratory () ? i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint): - i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop, reverse, endpoint); - - if (!hop || hop->GetProfile ()->IsBad ()) - hop = i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint); + bool tryHighBandwidth = !IsExploratory (); + std::shared_ptr hop; + for (int i = 0; i < TUNNEL_POOL_MAX_HOP_SELECTION_ATTEMPTS; i++) + { + hop = tryHighBandwidth ? + i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop, reverse, endpoint) : + i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint); + if (hop) + { + if (!hop->GetProfile ()->IsBad ()) + break; + } + else if (tryHighBandwidth) + tryHighBandwidth = false; + else + return nullptr; + } return hop; } diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index 3d3d4e33..d9f5966d 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -32,6 +32,7 @@ namespace tunnel const int TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY = 16; const int TUNNEL_POOL_MAX_OUTBOUND_TUNNELS_QUANTITY = 16; const int TUNNEL_POOL_MAX_NUM_BUILD_REQUESTS = 3; + const int TUNNEL_POOL_MAX_HOP_SELECTION_ATTEMPTS = 3; class Tunnel; class InboundTunnel; From d524105727797825cf8e0310eef7120060b28c60 Mon Sep 17 00:00:00 2001 From: Vort Date: Tue, 20 Feb 2024 22:48:45 +0200 Subject: [PATCH 080/787] skip bandwidth updates in case of time going backwards --- libi2pd/Transports.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index bb5dcecc..04c58cf3 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -376,7 +376,12 @@ namespace transport { TrafficSample& sample1 = m_TrafficSamples[m_TrafficSamplePtr]; TrafficSample& sample2 = m_TrafficSamples[(TRAFFIC_SAMPLE_COUNT + m_TrafficSamplePtr - interval) % TRAFFIC_SAMPLE_COUNT]; - auto delta = sample1.Timestamp - sample2.Timestamp; + auto delta = (int64_t)sample1.Timestamp - (int64_t)sample2.Timestamp; + if (delta <= 0) + { + LogPrint (eLogError, "Transports: Backward clock jump detected, got ", delta, " instead of ", interval * 1000); + return; + } in = (sample1.TotalReceivedBytes - sample2.TotalReceivedBytes) * 1000 / delta; out = (sample1.TotalSentBytes - sample2.TotalSentBytes) * 1000 / delta; transit = (sample1.TotalTransitTransmittedBytes - sample2.TotalTransitTransmittedBytes) * 1000 / delta; From 2692aef53d45eb7b9a2a82a1c241a0f7ca9b175a Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 21 Feb 2024 01:36:32 +0300 Subject: [PATCH 081/787] [gha] update windows msvc action --- .github/workflows/build-windows-msvc.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-windows-msvc.yml b/.github/workflows/build-windows-msvc.yml index dea64644..36a70d5a 100644 --- a/.github/workflows/build-windows-msvc.yml +++ b/.github/workflows/build-windows-msvc.yml @@ -38,13 +38,13 @@ jobs: - name: Install Boost run: | - powershell -Command "(Invoke-WebRequest -UserAgent "Wget" -Uri https://sourceforge.net/projects/boost/files/boost-binaries/1.81.0/boost_1_81_0-msvc-14.3-64.exe/download -OutFile boost_1_84_0-msvc-14.3-64.exe)" - ./boost_1_84_0-msvc-14.3-64.exe /VERYSILENT + powershell -Command "(Invoke-WebRequest -UserAgent "Wget" -Uri https://sourceforge.net/projects/boost/files/boost-binaries/1.81.0/boost_1_81_0-msvc-14.3-64.exe/download -OutFile boost_1_81_0-msvc-14.3-64.exe)" + ./boost_1_81_0-msvc-14.3-64.exe /VERYSILENT - name: Install OpenSSL run: | - powershell -Command "(Invoke-WebRequest -UserAgent "Wget" -Uri https://slproweb.com/download/Win64OpenSSL-3_2_0.exe -OutFile Win64OpenSSL-3_2_0.exe)" - ./Win64OpenSSL-3_2_0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- + powershell -Command "(Invoke-WebRequest -UserAgent "Wget" -Uri https://slproweb.com/download/Win64OpenSSL-3_2_1.exe -OutFile Win64OpenSSL-3_2_1.exe)" + ./Win64OpenSSL-3_2_1.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- - name: Configure working-directory: build From 695dc96a837d029999375ef80084c923d65cc4ad Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 20 Feb 2024 18:32:51 -0500 Subject: [PATCH 082/787] common ServiceAcceptor for all stream protocols --- libi2pd_client/I2PService.cpp | 49 ---------------- libi2pd_client/I2PService.h | 103 +++++++++++++++++++++++----------- 2 files changed, 71 insertions(+), 81 deletions(-) diff --git a/libi2pd_client/I2PService.cpp b/libi2pd_client/I2PService.cpp index 5604f950..e9513e48 100644 --- a/libi2pd_client/I2PService.cpp +++ b/libi2pd_client/I2PService.cpp @@ -147,54 +147,5 @@ namespace client m_LocalDestination->CreateStream (streamRequestComplete, address->blindedPublicKey, port); } } - - void TCPIPAcceptor::Start () - { - m_Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), m_LocalEndpoint)); - // update the local end point in case port has been set zero and got updated now - m_LocalEndpoint = m_Acceptor->local_endpoint(); - m_Acceptor->listen (); - Accept (); - } - - void TCPIPAcceptor::Stop () - { - if (m_Acceptor) - { - m_Acceptor->close(); - m_Acceptor.reset (nullptr); - } - m_Timer.cancel (); - ClearHandlers(); - } - - void TCPIPAcceptor::Accept () - { - auto newSocket = std::make_shared (GetService ()); - m_Acceptor->async_accept (*newSocket, std::bind (&TCPIPAcceptor::HandleAccept, this, - std::placeholders::_1, newSocket)); - } - - void TCPIPAcceptor::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr socket) - { - if (!ecode) - { - LogPrint(eLogDebug, "I2PService: ", GetName(), " accepted"); - auto handler = CreateHandler(socket); - if (handler) - { - AddHandler(handler); - handler->Handle(); - } - else - socket->close(); - Accept(); - } - else - { - if (ecode != boost::asio::error::operation_aborted) - LogPrint (eLogError, "I2PService: ", GetName(), " closing socket on accept because: ", ecode.message ()); - } - } } } diff --git a/libi2pd_client/I2PService.h b/libi2pd_client/I2PService.h index b8973f9d..d35c954d 100644 --- a/libi2pd_client/I2PService.h +++ b/libi2pd_client/I2PService.h @@ -210,42 +210,81 @@ namespace client return std::make_shared >(owner, upstream, downstream); } - /* TODO: support IPv6 too */ - //This is a service that listens for connections on the IP network and interacts with I2P - class TCPIPAcceptor: public I2PService + //This is a service that listens for connections on the IP network or local socket and interacts with I2P + template + class ServiceAcceptor: public I2PService + { + public: + + ServiceAcceptor (const typename Protocol::endpoint& localEndpoint, std::shared_ptr localDestination = nullptr) : + I2PService(localDestination), m_LocalEndpoint (localEndpoint) {} + + virtual ~ServiceAcceptor () { Stop(); } + void Start () override + { + m_Acceptor.reset (new typename Protocol::acceptor (GetService (), m_LocalEndpoint)); + // update the local end point in case port has been set zero and got updated now + m_LocalEndpoint = m_Acceptor->local_endpoint(); + m_Acceptor->listen (); + Accept (); + } + void Stop () override + { + if (m_Acceptor) + { + m_Acceptor->close(); + m_Acceptor.reset (nullptr); + } + ClearHandlers(); + } + const typename Protocol::endpoint& GetLocalEndpoint () const { return m_LocalEndpoint; }; + + const char* GetName() override { return "Generic TCP/IP accepting daemon"; } + + protected: + + virtual std::shared_ptr CreateHandler(std::shared_ptr socket) = 0; + + private: + + void Accept() + { + auto newSocket = std::make_shared (GetService ()); + m_Acceptor->async_accept (*newSocket, + [newSocket, this](const boost::system::error_code& ecode) + { + if (ecode == boost::asio::error::operation_aborted) return; + if (!ecode) + { + LogPrint(eLogDebug, "ServiceAcceptor: ", GetName(), " accepted"); + auto handler = CreateHandler(newSocket); + if (handler) + { + AddHandler(handler); + handler->Handle(); + } + else + newSocket->close(); + Accept(); + } + else + LogPrint (eLogError, "ServiceAcceptor: ", GetName(), " closing socket on accept because: ", ecode.message ()); + }); + } + + private: + + typename Protocol::endpoint m_LocalEndpoint; + std::unique_ptr m_Acceptor; + }; + + class TCPIPAcceptor: public ServiceAcceptor { public: TCPIPAcceptor (const std::string& address, uint16_t port, std::shared_ptr localDestination = nullptr) : - I2PService(localDestination), - m_LocalEndpoint (boost::asio::ip::address::from_string(address), port), - m_Timer (GetService ()) {} - TCPIPAcceptor (const std::string& address, uint16_t port, i2p::data::SigningKeyType kt) : - I2PService(kt), - m_LocalEndpoint (boost::asio::ip::address::from_string(address), port), - m_Timer (GetService ()) {} - virtual ~TCPIPAcceptor () { TCPIPAcceptor::Stop(); } - //If you override this make sure you call it from the children - void Start (); - //If you override this make sure you call it from the children - void Stop (); - - const boost::asio::ip::tcp::endpoint& GetLocalEndpoint () const { return m_LocalEndpoint; }; - - virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; } - - protected: - - virtual std::shared_ptr CreateHandler(std::shared_ptr socket) = 0; - - private: - - void Accept(); - void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); - boost::asio::ip::tcp::endpoint m_LocalEndpoint; - std::unique_ptr m_Acceptor; - boost::asio::deadline_timer m_Timer; - }; + ServiceAcceptor (boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port), localDestination) {} + }; } } From 577ed56af023c792dccee3bed9fe731b59e137bd Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 20 Feb 2024 18:51:37 -0500 Subject: [PATCH 083/787] store HTTP and SOCKS proxy as pointer to I2PService --- libi2pd_client/ClientContext.cpp | 1 + libi2pd_client/ClientContext.h | 11 ++++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index c27ce625..62295842 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -16,6 +16,7 @@ #include "Identity.h" #include "util.h" #include "ClientContext.h" +#include "HTTPProxy.h" #include "SOCKS.h" #include "MatchedDestination.h" diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index 4e969a6b..adec607a 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.h @@ -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 * @@ -15,8 +15,6 @@ #include #include "Destination.h" #include "I2PService.h" -#include "HTTPProxy.h" -#include "SOCKS.h" #include "I2PTunnel.h" #include "UDPTunnel.h" #include "SAM.h" @@ -141,8 +139,7 @@ namespace client AddressBook m_AddressBook; - i2p::proxy::HTTPProxy * m_HttpProxy; - i2p::proxy::SOCKSProxy * m_SocksProxy; + I2PService * m_HttpProxy, * m_SocksProxy; std::map > m_ClientTunnels; // local endpoint -> tunnel std::map, std::shared_ptr > m_ServerTunnels; // -> tunnel @@ -167,8 +164,8 @@ namespace client const decltype(m_ServerTunnels)& GetServerTunnels () const { return m_ServerTunnels; }; const decltype(m_ClientForwards)& GetClientForwards () const { return m_ClientForwards; } const decltype(m_ServerForwards)& GetServerForwards () const { return m_ServerForwards; } - const i2p::proxy::HTTPProxy * GetHttpProxy () const { return m_HttpProxy; } - const i2p::proxy::SOCKSProxy * GetSocksProxy () const { return m_SocksProxy; } + const I2PService * GetHttpProxy () const { return m_HttpProxy; } + const I2PService * GetSocksProxy () const { return m_SocksProxy; } }; extern ClientContext context; From 36a060d50f66230251fe737b4c497eed961c1e67 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 21 Feb 2024 12:37:33 -0500 Subject: [PATCH 084/787] Consider 'M' routers as low bandwidth --- libi2pd/RouterContext.cpp | 6 +++--- libi2pd/RouterInfo.cpp | 5 ++--- libi2pd/RouterInfo.h | 8 ++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 013f4dc5..864d2c61 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -602,9 +602,9 @@ namespace i2p { case i2p::data::CAPS_FLAG_LOW_BANDWIDTH1 : limit = 12; type = low; break; case i2p::data::CAPS_FLAG_LOW_BANDWIDTH2 : limit = i2p::data::LOW_BANDWIDTH_LIMIT; type = low; break; // 48 - case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH1 : limit = 64; type = high; break; - case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH2 : limit = 128; type = high; break; - case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH3 : limit = i2p::data::HIGH_BANDWIDTH_LIMIT; type = high; break; // 256 + case i2p::data::CAPS_FLAG_LOW_BANDWIDTH3 : limit = 64; type = low; break; + case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH1 : limit = 128; type = high; break; + case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH2 : limit = i2p::data::HIGH_BANDWIDTH_LIMIT; type = high; break; // 256 case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1 : limit = i2p::data::EXTRA_BANDWIDTH_LIMIT; type = extra; break; // 2048 case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2 : limit = 1000000; type = unlim; break; // 1Gbyte/s default: diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index a034691a..a9c43b2e 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -516,7 +516,6 @@ namespace data break; case CAPS_FLAG_HIGH_BANDWIDTH1: case CAPS_FLAG_HIGH_BANDWIDTH2: - case CAPS_FLAG_HIGH_BANDWIDTH3: m_Caps |= Caps::eHighBandwidth; break; case CAPS_FLAG_EXTRA_BANDWIDTH1: @@ -1178,7 +1177,7 @@ namespace data CAPS_FLAG_EXTRA_BANDWIDTH2 : // 'X' CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P' else - caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O' + caps += CAPS_FLAG_HIGH_BANDWIDTH2; // 'O' caps += CAPS_FLAG_FLOODFILL; // floodfill } else @@ -1186,7 +1185,7 @@ namespace data if (c & eExtraBandwidth) caps += (c & eHighBandwidth) ? CAPS_FLAG_EXTRA_BANDWIDTH2 /* 'X' */ : CAPS_FLAG_EXTRA_BANDWIDTH1; /*'P' */ else - caps += (c & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth + caps += (c & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH2 /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth } if (c & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden if (c & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index a95119ed..9e074b9a 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -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 * @@ -39,9 +39,9 @@ namespace data /* bandwidth flags */ const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; /* < 12 KBps */ const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L'; /* 12-48 KBps */ - const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M'; /* 48-64 KBps */ - const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N'; /* 64-128 KBps */ - const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */ + const char CAPS_FLAG_LOW_BANDWIDTH3 = 'M'; /* 48-64 KBps */ + const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'N'; /* 64-128 KBps */ + const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'O'; /* 128-256 KBps */ const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2048 KBps */ const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2048 KBps */ // bandwidth limits in kBps From 5d7c6fb0b3e89d672a631392f6b15f19156dee2c Mon Sep 17 00:00:00 2001 From: r4sas Date: Wed, 21 Feb 2024 22:31:20 +0300 Subject: [PATCH 085/787] [gha] msvc: copy openssl libraries to fix build Signed-off-by: r4sas --- .github/workflows/build-windows-msvc.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-windows-msvc.yml b/.github/workflows/build-windows-msvc.yml index 36a70d5a..ef0bc52c 100644 --- a/.github/workflows/build-windows-msvc.yml +++ b/.github/workflows/build-windows-msvc.yml @@ -45,6 +45,7 @@ jobs: run: | powershell -Command "(Invoke-WebRequest -UserAgent "Wget" -Uri https://slproweb.com/download/Win64OpenSSL-3_2_1.exe -OutFile Win64OpenSSL-3_2_1.exe)" ./Win64OpenSSL-3_2_1.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- + xcopy "c:\Program Files\OpenSSL-Win64\lib\VC\x64\MTd\*" "c:\Program Files\OpenSSL-Win64\lib\" - name: Configure working-directory: build From d25206abcefff1c914ee16adad8229197f14ca3b Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 21 Feb 2024 19:46:29 -0500 Subject: [PATCH 086/787] encrypted tunnel test messages --- libi2pd/Destination.cpp | 5 ++-- libi2pd/ECIESX25519AEADRatchetSession.cpp | 8 +++++- libi2pd/ECIESX25519AEADRatchetSession.h | 2 +- libi2pd/RouterContext.cpp | 7 +++++ libi2pd/TunnelPool.cpp | 33 ++++++++++++++++------- libi2pd/TunnelPool.h | 1 + 6 files changed, 43 insertions(+), 13 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index ef0d5db3..64e5d085 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -367,8 +367,9 @@ namespace client HandleDataMessage (payload, len); break; case eI2NPDeliveryStatus: - // we assume tunnel tests non-encrypted - HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET)); + // try tunnel test first + if (!m_Pool || !m_Pool->ProcessDeliveryStatus (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET), bufbe64toh (payload + DELIVERY_STATUS_TIMESTAMP_OFFSET))) + HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET)); break; case eI2NPDatabaseStore: HandleDatabaseStoreMessage (payload, len); diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 3513b7ac..b4730d0e 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -1154,7 +1154,7 @@ namespace garlic return len; } - std::shared_ptr WrapECIESX25519Message (std::shared_ptr msg, const uint8_t * key, uint64_t tag) + std::shared_ptr WrapECIESX25519Message (std::shared_ptr msg, const uint8_t * key, uint64_t tag) { auto m = NewI2NPMessage ((msg ? msg->GetPayloadLength () : 0) + 128); m->Align (12); // in order to get buf aligned to 16 (12 + 4) @@ -1174,6 +1174,12 @@ namespace garlic htobe32buf (m->GetPayload (), offset); m->len += offset + 4; m->FillI2NPMessageHeader (eI2NPGarlic); + if (msg->onDrop) + { + // move onDrop to the wrapping I2NP messages + m->onDrop = msg->onDrop; + msg->onDrop = nullptr; + } return m; } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 030e2c45..e6deb2bc 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -247,7 +247,7 @@ namespace garlic i2p::crypto::NoiseSymmetricState m_CurrentNoiseState; }; - std::shared_ptr WrapECIESX25519Message (std::shared_ptr msg, const uint8_t * key, uint64_t tag); + std::shared_ptr WrapECIESX25519Message (std::shared_ptr msg, const uint8_t * key, uint64_t tag); std::shared_ptr WrapECIESX25519MessageForRouter (std::shared_ptr msg, const uint8_t * routerPublicKey); } } diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 864d2c61..2c1dc979 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -1152,6 +1152,13 @@ namespace i2p bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) { + if (typeID == eI2NPDeliveryStatus) + { + // try tunnel test + auto pool = GetTunnelPool (); + if (pool && pool->ProcessDeliveryStatus (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET), bufbe64toh (payload + DELIVERY_STATUS_TIMESTAMP_OFFSET))) + return true; + } auto msg = CreateI2NPMessage (typeID, payload, len, msgID); if (!msg) return false; i2p::HandleI2NPMessage (msg); diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index c342d546..898a05bc 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -13,6 +13,7 @@ #include "NetDb.hpp" #include "Timestamp.h" #include "Garlic.h" +#include "ECIESX25519AEADRatchetSession.h" #include "Transports.h" #include "Log.h" #include "Tunnel.h" @@ -383,6 +384,7 @@ namespace tunnel newTests.push_back(std::make_pair (*it1, *it2)); ++it1; ++it2; } + bool encrypt = m_LocalDestination ? m_LocalDestination->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) : false; for (auto& it: newTests) { uint32_t msgID; @@ -407,6 +409,14 @@ namespace tunnel s->m_OutboundTunnels.erase (outbound); } }; + if (encrypt) + { + // encrypt + uint8_t key[32]; RAND_bytes (key, 32); + uint64_t tag; RAND_bytes ((uint8_t *)&tag, 8); + m_LocalDestination->SubmitECIESx25519Key (key, tag); + msg = i2p::garlic::WrapECIESX25519Message (msg, key, tag); + } outbound->SendTunnelDataMsgTo (it.second->GetNextIdentHash (), it.second->GetNextTunnelID (), msg); } } @@ -436,6 +446,17 @@ namespace tunnel buf += 4; uint64_t timestamp = bufbe64toh (buf); + if (!ProcessDeliveryStatus (msgID, timestamp)) + { + if (m_LocalDestination) + m_LocalDestination->ProcessDeliveryStatusMessage (msg); + else + LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, dropped"); + } + } + + bool TunnelPool::ProcessDeliveryStatus (uint32_t msgID, uint64_t timestamp) + { decltype(m_Tests)::mapped_type test; bool found = false; { @@ -477,15 +498,9 @@ namespace tunnel test.second->AddLatencySample(latency); } } - else - { - if (m_LocalDestination) - m_LocalDestination->ProcessDeliveryStatusMessage (msg); - else - LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, dropped"); - } - } - + return found; + } + bool TunnelPool::IsExploratory () const { return i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this (); diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index d9f5966d..3e845c0e 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -85,6 +85,7 @@ namespace tunnel void ManageTunnels (uint64_t ts); void ProcessGarlicMessage (std::shared_ptr msg); void ProcessDeliveryStatus (std::shared_ptr msg); + bool ProcessDeliveryStatus (uint32_t msgID, uint64_t timestamp); bool IsExploratory () const; bool IsActive () const { return m_IsActive; }; From 7d73c304b5b77493079b9aa2c5f9e927c89e2907 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 22 Feb 2024 14:22:11 -0500 Subject: [PATCH 087/787] Extend transit tunnels limit to 4 bytes. Bump default value to 10K --- daemon/Daemon.cpp | 2 +- daemon/HTTPServer.cpp | 2 +- daemon/HTTPServer.h | 4 ++-- libi2pd/Config.cpp | 2 +- libi2pd/Tunnel.cpp | 2 +- libi2pd/Tunnel.h | 6 +++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 17d17f72..090792bf 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -179,7 +179,7 @@ namespace util bool transit; i2p::config::GetOption("notransit", transit); i2p::context.SetAcceptsTunnels (!transit); - uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels); + uint32_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels); if (isFloodfill && i2p::config::IsDefault ("limits.transittunnels")) transitTunnels *= 2; // double default number of transit tunnels for floodfill i2p::tunnel::tunnels.SetMaxNumTransitTunnels (transitTunnels); diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 862d6e4a..494a4e8e 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -772,7 +772,7 @@ namespace http { s << " info \r\n"; s << " debug
\r\n
\r\n"; - uint16_t maxTunnels = i2p::tunnel::tunnels.GetMaxNumTransitTunnels (); + uint32_t maxTunnels = i2p::tunnel::tunnels.GetMaxNumTransitTunnels (); s << "" << tr("Transit tunnels limit") << "
\r\n"; s << "
\r\n"; s << " \r\n"; diff --git a/daemon/HTTPServer.h b/daemon/HTTPServer.h index f41d925d..f751c5a8 100644 --- a/daemon/HTTPServer.h +++ b/daemon/HTTPServer.h @@ -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 * @@ -25,7 +25,7 @@ namespace http const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192; const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds const int COMMAND_REDIRECT_TIMEOUT = 5; // in seconds - const int TRANSIT_TUNNELS_LIMIT = 65535; + const int TRANSIT_TUNNELS_LIMIT = 1000000; class HTTPConnection: public std::enable_shared_from_this { diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index b2ad7a17..a6885178 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -77,7 +77,7 @@ namespace config { limits.add_options() ("limits.coresize", value()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)") ("limits.openfiles", value()->default_value(0), "Maximum number of open files (0 - use system default)") - ("limits.transittunnels", value()->default_value(5000), "Maximum active transit tunnels (default:5000)") + ("limits.transittunnels", value()->default_value(10000), "Maximum active transit tunnels (default:10000)") ("limits.zombies", value()->default_value(0), "Minimum percentage of successfully created tunnels under which tunnel cleanup is paused (default [%]: 0.00)") ("limits.ntcpsoft", value()->default_value(0), "Ignored") ("limits.ntcphard", value()->default_value(0), "Ignored") diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 3e10ef1b..246f68e4 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -986,7 +986,7 @@ namespace tunnel return m_OutboundTunnels.size(); } - void Tunnels::SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels) + void Tunnels::SetMaxNumTransitTunnels (uint32_t maxNumTransitTunnels) { if (maxNumTransitTunnels > 0 && m_MaxNumTransitTunnels != maxNumTransitTunnels) { diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index cc5b9461..4903c75b 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -238,8 +238,8 @@ namespace tunnel std::shared_ptr NewI2NPTunnelMessage (bool endpoint); - void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels); - uint16_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; }; + void SetMaxNumTransitTunnels (uint32_t maxNumTransitTunnels); + uint32_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; }; int GetCongestionLevel() const { return CONGESTION_LEVEL_FULL * m_TransitTunnels.size() / m_MaxNumTransitTunnels; } private: @@ -300,7 +300,7 @@ namespace tunnel i2p::util::Queue > m_Queue; i2p::util::MemoryPoolMt > m_I2NPTunnelEndpointMessagesMemoryPool; i2p::util::MemoryPoolMt > m_I2NPTunnelMessagesMemoryPool; - uint16_t m_MaxNumTransitTunnels; + uint32_t m_MaxNumTransitTunnels; // count of tunnels for total TCSR algorithm int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations; double m_TunnelCreationSuccessRate; From 5415598f60878cd4879f3ce265f5d791da9b7fe8 Mon Sep 17 00:00:00 2001 From: Vort Date: Thu, 22 Feb 2024 21:50:05 +0200 Subject: [PATCH 088/787] add zero check to congestion level calculations --- libi2pd/Tunnel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 4903c75b..4d9ea830 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -240,7 +240,7 @@ namespace tunnel void SetMaxNumTransitTunnels (uint32_t maxNumTransitTunnels); uint32_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; }; - int GetCongestionLevel() const { return CONGESTION_LEVEL_FULL * m_TransitTunnels.size() / m_MaxNumTransitTunnels; } + int GetCongestionLevel() const { return m_MaxNumTransitTunnels ? CONGESTION_LEVEL_FULL * m_TransitTunnels.size() / m_MaxNumTransitTunnels : CONGESTION_LEVEL_FULL; } private: From fd4513ebb232b42c6246b1d226be0a05ef863b72 Mon Sep 17 00:00:00 2001 From: Vort Date: Thu, 22 Feb 2024 23:07:07 +0200 Subject: [PATCH 089/787] show bandwidth caps for hops --- daemon/HTTPServer.cpp | 25 +++++++++++++++++++++---- libi2pd/RouterInfo.cpp | 7 +++++++ libi2pd/RouterInfo.h | 2 ++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 494a4e8e..7a6656dc 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -417,6 +417,15 @@ namespace http { } } + static void ShowHop(std::stringstream& s, const i2p::data::IdentityEx& ident) + { + auto identHash = ident.GetIdentHash(); + auto router = i2p::data::netdb.FindRouter(identHash); + s << i2p::data::GetIdentHashAbbreviation(identHash); + if (router) + s << " " << router->GetBandwidthCap() << ""; + } + static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr dest, uint32_t token) { s << "Base32:
\r\n\r\n
\r\n
\r\n" @@ -1434,7 +1432,6 @@ namespace http { "\r\n" "\r\n
\r\n"; delete[] signature; - delete[] sig; } else s << "" << tr("ERROR") << ": " << tr("Domain can't end with .b32.i2p") << "\r\n
\r\n
\r\n"; diff --git a/libi2pd/Base.cpp b/libi2pd/Base.cpp index bce303a2..bc9da4fb 100644 --- a/libi2pd/Base.cpp +++ b/libi2pd/Base.cpp @@ -58,15 +58,13 @@ namespace data /* * Reverse Substitution Table (built in run time) */ - static char iT64[256]; static int isFirstTime = 1; /* * Padding */ - - static char P64 = '='; + static constexpr char P64 = '='; /* * @@ -76,80 +74,6 @@ namespace data * Converts binary encoded data to BASE64 format. * */ - - size_t ByteStreamToBase64 ( // Number of bytes in the encoded buffer - const uint8_t * InBuffer, // Input buffer, binary data - size_t InCount, // Number of bytes in the input buffer - char * OutBuffer, // output buffer - size_t len // length of output buffer - ) - { - unsigned char * ps; - unsigned char * pd; - unsigned char acc_1; - unsigned char acc_2; - int i; - int n; - int m; - size_t outCount; - - ps = (unsigned char *)InBuffer; - n = InCount / 3; - m = InCount % 3; - if (!m) - outCount = 4 * n; - else - outCount = 4 * (n + 1); - - if (outCount > len) return 0; - - pd = (unsigned char *)OutBuffer; - for ( i = 0; i < n; i++ ) - { - acc_1 = *ps++; - acc_2 = (acc_1 << 4) & 0x30; - acc_1 >>= 2; // base64 digit #1 - *pd++ = T64[acc_1]; - acc_1 = *ps++; - acc_2 |= acc_1 >> 4; // base64 digit #2 - *pd++ = T64[acc_2]; - acc_1 &= 0x0f; - acc_1 <<= 2; - acc_2 = *ps++; - acc_1 |= acc_2 >> 6; // base64 digit #3 - *pd++ = T64[acc_1]; - acc_2 &= 0x3f; // base64 digit #4 - *pd++ = T64[acc_2]; - } - if ( m == 1 ) - { - acc_1 = *ps++; - acc_2 = (acc_1 << 4) & 0x3f; // base64 digit #2 - acc_1 >>= 2; // base64 digit #1 - *pd++ = T64[acc_1]; - *pd++ = T64[acc_2]; - *pd++ = P64; - *pd++ = P64; - - } - else if ( m == 2 ) - { - acc_1 = *ps++; - acc_2 = (acc_1 << 4) & 0x3f; - acc_1 >>= 2; // base64 digit #1 - *pd++ = T64[acc_1]; - acc_1 = *ps++; - acc_2 |= acc_1 >> 4; // base64 digit #2 - *pd++ = T64[acc_2]; - acc_1 &= 0x0f; - acc_1 <<= 2; // base64 digit #3 - *pd++ = T64[acc_1]; - *pd++ = P64; - } - - return outCount; - } - std::string ByteStreamToBase64 (// base64 encoded string const uint8_t * InBuffer, // Input buffer, binary data size_t InCount // Number of bytes in the input buffer diff --git a/libi2pd/Base.h b/libi2pd/Base.h index daf0f7ed..945dc8b3 100644 --- a/libi2pd/Base.h +++ b/libi2pd/Base.h @@ -18,7 +18,6 @@ namespace i2p { namespace data { - size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len); // called from SAM TODO: rewrite std::string ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount); size_t Base64ToByteStream (std::string_view base64Str, uint8_t * OutBuffer, size_t len); From 609cd401bb80129d00add10c2808b8b932033eb7 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 17 Mar 2025 20:08:39 -0400 Subject: [PATCH 732/787] don't calculate key's base64 if not used --- libi2pd/NetDb.cpp | 5 +++-- libi2pd/NetDbRequests.cpp | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 2bfaa8d8..e53738e5 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -951,12 +951,13 @@ namespace data LogPrint (eLogError, "NetDb: DatabaseLookup for zero ident. Ignored"); return; } - auto key = i2p::data::ByteStreamToBase64 (buf, 32); + std::string key; + if (CheckLogLevel (eLogInfo)) + key = i2p::data::ByteStreamToBase64 (buf, 32); IdentHash replyIdent(buf + 32); uint8_t flag = buf[64]; - LogPrint (eLogDebug, "NetDb: DatabaseLookup for ", key, " received flags=", (int)flag); uint8_t lookupType = flag & DATABASE_LOOKUP_TYPE_FLAGS_MASK; const uint8_t * excluded = buf + 65; diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index 0648d6bf..94633e10 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -360,9 +360,12 @@ namespace data void NetDbRequests::HandleDatabaseSearchReplyMsg (std::shared_ptr msg) { const uint8_t * buf = msg->GetPayload (); - auto key = i2p::data::ByteStreamToBase64 (buf, 32); + std::string key; size_t num = buf[32]; // num + if (CheckLogLevel (eLogInfo)) + key = i2p::data::ByteStreamToBase64 (buf, 32); LogPrint (eLogDebug, "NetDbReq: DatabaseSearchReply for ", key, " num=", num); + IdentHash ident (buf); bool isExploratory = false; auto dest = FindRequest (ident); From bd2b96627c7328ee23ed43a3d6c83c9f0b30d878 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 18 Mar 2025 19:23:13 -0400 Subject: [PATCH 733/787] calculate crypto key length from key type --- libi2pd/CryptoKey.cpp | 17 +++++++++++------ libi2pd/CryptoKey.h | 28 ++++++++++++++++++++++++++-- libi2pd/Destination.cpp | 34 +++++++++++++++++++++------------- libi2pd/Destination.h | 13 +++++++++---- libi2pd/Identity.cpp | 4 ++-- libi2pd/Identity.h | 6 +++++- libi2pd/LeaseSet.cpp | 3 ++- libi2pd/RouterContext.cpp | 1 + libi2pd/RouterInfo.cpp | 1 + libi2pd_client/I2CP.h | 1 + 10 files changed, 79 insertions(+), 29 deletions(-) diff --git a/libi2pd/CryptoKey.cpp b/libi2pd/CryptoKey.cpp index ad986129..7ea0fc2c 100644 --- a/libi2pd/CryptoKey.cpp +++ b/libi2pd/CryptoKey.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2021, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -174,12 +174,17 @@ namespace crypto return m_StaticKeys.Agree (epub, sharedSecret); } - void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub) + bool CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub, i2p::data::CryptoKeyType type) { - X25519Keys k; - k.GenerateKeys (); - k.GetPrivateKey (priv); - memcpy (pub, k.GetPublicKey (), 32); + if (type == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) + { + X25519Keys k; + k.GenerateKeys (); + k.GetPrivateKey (priv); + memcpy (pub, k.GetPublicKey (), 32); + return true; + } + return false; } } } diff --git a/libi2pd/CryptoKey.h b/libi2pd/CryptoKey.h index a7d86d09..5fe72307 100644 --- a/libi2pd/CryptoKey.h +++ b/libi2pd/CryptoKey.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2021, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -11,6 +11,7 @@ #include #include "Crypto.h" +#include "Identity.h" namespace i2p { @@ -157,7 +158,30 @@ namespace crypto X25519Keys m_StaticKeys; }; - void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub); + bool CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub, + i2p::data::CryptoKeyType type = i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); + + constexpr size_t GetCryptoPrivateKeyLen (i2p::data::CryptoKeyType type) + { + switch (type) + { + case i2p::data::CRYPTO_KEY_TYPE_ELGAMAL: return 256; + case i2p::data::CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: return 32; + case i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: return 32; + }; + return 0; + } + + constexpr size_t GetCryptoPublicKeyLen (i2p::data::CryptoKeyType type) + { + switch (type) + { + case i2p::data::CRYPTO_KEY_TYPE_ELGAMAL: return 256; + case i2p::data::CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: return 32; + case i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: return 32; + }; + return 0; + } } } diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index be079ee3..8ba29ca5 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1416,21 +1416,29 @@ namespace client std::string path = i2p::fs::DataDirPath("destinations", ident + "." + std::to_string (keys->keyType) + ".dat"); std::ifstream f(path, std::ifstream::binary); - if (f) { - f.read ((char *)keys->pub, 256); - f.read ((char *)keys->priv, 256); + if (f) + { + char pub[256], priv[256]; + f.read (pub, 256); + memcpy (keys->pub.data(), pub, keys->pub.size()); + f.read (priv, 256); + memcpy (keys->priv.data (), priv, keys->priv.size ()); return; } LogPrint (eLogInfo, "Destination: Creating new temporary keys of type for address ", ident, ".b32.i2p"); - memset (keys->priv, 0, 256); - memset (keys->pub, 0, 256); + memset (keys->priv.data (), 0, keys->priv.size ()); + memset (keys->pub.data (), 0, keys->pub.size ()); keys->GenerateKeys (); // TODO:: persist crypto key type std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out); - if (f1) { - f1.write ((char *)keys->pub, 256); - f1.write ((char *)keys->priv, 256); + if (f1) + { + char pub[256], priv[256]; + memset (pub, 0, 256); memcpy (pub, keys->pub.data (), keys->pub.size ()); + f1.write (pub, 256); + memset (priv, 0, 256); memcpy (priv, keys->priv.data (), keys->priv.size ()); + f1.write (priv, 256); return; } LogPrint(eLogCritical, "Destinations: Can't save keys to ", path); @@ -1443,7 +1451,7 @@ namespace client { if (m_StandardEncryptionKey) { - leaseSet = std::make_shared (GetIdentity (), m_StandardEncryptionKey->pub, tunnels); + leaseSet = std::make_shared (GetIdentity (), m_StandardEncryptionKey->pub.data (), tunnels); // sign Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ()); } @@ -1455,9 +1463,9 @@ namespace client // standard LS2 (type 3) first i2p::data::LocalLeaseSet2::KeySections keySections; if (m_ECIESx25519EncryptionKey) - keySections.push_back ({m_ECIESx25519EncryptionKey->keyType, 32, m_ECIESx25519EncryptionKey->pub} ); + keySections.push_back ({m_ECIESx25519EncryptionKey->keyType, (uint16_t)m_ECIESx25519EncryptionKey->pub.size (), m_ECIESx25519EncryptionKey->pub.data ()} ); if (m_StandardEncryptionKey) - keySections.push_back ({m_StandardEncryptionKey->keyType, (uint16_t)m_StandardEncryptionKey->decryptor->GetPublicKeyLen (), m_StandardEncryptionKey->pub} ); + keySections.push_back ({m_StandardEncryptionKey->keyType, (uint16_t)m_StandardEncryptionKey->decryptor->GetPublicKeyLen (), m_StandardEncryptionKey->pub.data ()} ); auto publishedTimestamp = i2p::util::GetSecondsSinceEpoch (); if (publishedTimestamp <= m_LastPublishedTimestamp) @@ -1501,8 +1509,8 @@ namespace client const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const { if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) - return m_ECIESx25519EncryptionKey ? m_ECIESx25519EncryptionKey->pub : nullptr; - return m_StandardEncryptionKey ? m_StandardEncryptionKey->pub : nullptr; + return m_ECIESx25519EncryptionKey ? m_ECIESx25519EncryptionKey->pub.data () : nullptr; + return m_StandardEncryptionKey ? m_StandardEncryptionKey->pub.data () : nullptr; } void ClientDestination::ReadAuthKey (const std::string& group, const std::map * params) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 4278f1fd..7684c0f6 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -22,6 +22,7 @@ #include "Identity.h" #include "TunnelPool.h" #include "Crypto.h" +#include "CryptoKey.h" #include "LeaseSet.h" #include "Garlic.h" #include "NetDb.hpp" @@ -231,13 +232,17 @@ namespace client { struct EncryptionKey { - uint8_t pub[256], priv[256]; + std::vector pub, priv; i2p::data::CryptoKeyType keyType; std::shared_ptr decryptor; - EncryptionKey (i2p::data::CryptoKeyType t):keyType(t) { memset (pub, 0, 256); memset (priv, 0, 256); }; - void GenerateKeys () { i2p::data::PrivateKeys::GenerateCryptoKeyPair (keyType, priv, pub); }; - void CreateDecryptor () { decryptor = i2p::data::PrivateKeys::CreateDecryptor (keyType, priv); }; + EncryptionKey (i2p::data::CryptoKeyType t): keyType(t) + { + pub.resize (i2p::crypto::GetCryptoPublicKeyLen (keyType)); + priv.resize (i2p::crypto::GetCryptoPrivateKeyLen (keyType)); + } + void GenerateKeys () { i2p::data::PrivateKeys::GenerateCryptoKeyPair (keyType, priv.data (), pub.data ()); }; + void CreateDecryptor () { decryptor = i2p::data::PrivateKeys::CreateDecryptor (keyType, priv.data ()); }; }; public: diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index e98e5fbc..b5f86f11 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -10,6 +10,7 @@ #include "I2PEndian.h" #include "Log.h" #include "Timestamp.h" +#include "CryptoKey.h" #include "Identity.h" namespace i2p @@ -658,8 +659,7 @@ namespace data size_t PrivateKeys::GetPrivateKeyLen () const { - // private key length always 256, but type 4 - return (m_Public->GetCryptoKeyType () == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) ? 32 : 256; + return i2p::crypto::GetCryptoPrivateKeyLen (m_Public->GetCryptoKeyType ()); } uint8_t * PrivateKeys::GetPadding() diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index e08ac802..1891c7a2 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -17,10 +17,14 @@ #include #include "Base.h" #include "Signature.h" -#include "CryptoKey.h" namespace i2p { +namespace crypto +{ + class CryptoKeyEncryptor; + class CryptoKeyDecryptor; +} namespace data { typedef Tag<32> IdentHash; diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index ee1964fc..3068b35d 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2024, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -14,6 +14,7 @@ #include "Timestamp.h" #include "NetDb.hpp" #include "Tunnel.h" +#include "CryptoKey.h" #include "LeaseSet.h" namespace i2p diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 6819a185..af90a46a 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -22,6 +22,7 @@ #include "ECIESX25519AEADRatchetSession.h" #include "Transports.h" #include "Tunnel.h" +#include "CryptoKey.h" #include "RouterContext.h" namespace i2p diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 41f71e14..4af32f57 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -25,6 +25,7 @@ #include "Transports.h" #include "NetDb.hpp" #include "RouterContext.h" +#include "CryptoKey.h" #include "RouterInfo.h" namespace i2p diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index d3949eaa..597a4878 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -21,6 +21,7 @@ #include "util.h" #include "Destination.h" #include "Streaming.h" +#include "CryptoKey.h" namespace i2p { From 46f530bfcd6b32ecb6557870ec5922a230503903 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 18 Mar 2025 21:15:37 -0400 Subject: [PATCH 734/787] persist temporary keys of actual size --- libi2pd/Destination.cpp | 49 +++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 8ba29ca5..bb77b804 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1415,33 +1415,50 @@ namespace client std::string ident = GetIdentHash().ToBase32(); std::string path = i2p::fs::DataDirPath("destinations", ident + "." + std::to_string (keys->keyType) + ".dat"); std::ifstream f(path, std::ifstream::binary); - if (f) { - char pub[256], priv[256]; - f.read (pub, 256); - memcpy (keys->pub.data(), pub, keys->pub.size()); - f.read (priv, 256); - memcpy (keys->priv.data (), priv, keys->priv.size ()); - return; + size_t len = 0; + if (keys->keyType == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) + len = 512; + else if (keys->keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) + { + f.seekg (0, std::ios::end); + len = f.tellg(); + f.seekg (0, std::ios::beg); + } + + if (len == 512) + { + char pub[256], priv[256]; + f.read (pub, 256); + memcpy (keys->pub.data(), pub, keys->pub.size()); + f.read (priv, 256); + memcpy (keys->priv.data (), priv, keys->priv.size ()); + } + else + { + f.read ((char *)keys->pub.data(), keys->pub.size()); + f.read ((char *)keys->priv.data(), keys->priv.size()); + } + if (f) + return; + else + LogPrint(eLogWarning, "Destination: Can't read keys from ", path); } - LogPrint (eLogInfo, "Destination: Creating new temporary keys of type for address ", ident, ".b32.i2p"); + LogPrint (eLogInfo, "Destination: Creating new temporary keys of type ", keys->keyType, " for address ", ident, ".b32.i2p"); memset (keys->priv.data (), 0, keys->priv.size ()); memset (keys->pub.data (), 0, keys->pub.size ()); keys->GenerateKeys (); - // TODO:: persist crypto key type + std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out); if (f1) { - char pub[256], priv[256]; - memset (pub, 0, 256); memcpy (pub, keys->pub.data (), keys->pub.size ()); - f1.write (pub, 256); - memset (priv, 0, 256); memcpy (priv, keys->priv.data (), keys->priv.size ()); - f1.write (priv, 256); - return; + f1.write ((char *)keys->pub.data (), keys->pub.size ()); + f1.write ((char *)keys->priv.data (), keys->priv.size ()); } - LogPrint(eLogCritical, "Destinations: Can't save keys to ", path); + if (!f1) + LogPrint(eLogError, "Destination: Can't save keys to ", path); } void ClientDestination::CreateNewLeaseSet (const std::vector >& tunnels) From 9ce515ff793271363b3a33fcd333154eb75455cd Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 19 Mar 2025 08:40:10 -0400 Subject: [PATCH 735/787] MLKEM512_X25519 crypto key added --- libi2pd/CryptoKey.cpp | 15 +++++---------- libi2pd/CryptoKey.h | 5 +++-- libi2pd/Destination.cpp | 8 ++++---- libi2pd/Identity.h | 1 + 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/libi2pd/CryptoKey.cpp b/libi2pd/CryptoKey.cpp index 7ea0fc2c..bac5d740 100644 --- a/libi2pd/CryptoKey.cpp +++ b/libi2pd/CryptoKey.cpp @@ -174,17 +174,12 @@ namespace crypto return m_StaticKeys.Agree (epub, sharedSecret); } - bool CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub, i2p::data::CryptoKeyType type) + void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub) { - if (type == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) - { - X25519Keys k; - k.GenerateKeys (); - k.GetPrivateKey (priv); - memcpy (pub, k.GetPublicKey (), 32); - return true; - } - return false; + X25519Keys k; + k.GenerateKeys (); + k.GetPrivateKey (priv); + memcpy (pub, k.GetPublicKey (), 32); } } } diff --git a/libi2pd/CryptoKey.h b/libi2pd/CryptoKey.h index 5fe72307..14ef4fa8 100644 --- a/libi2pd/CryptoKey.h +++ b/libi2pd/CryptoKey.h @@ -158,8 +158,7 @@ namespace crypto X25519Keys m_StaticKeys; }; - bool CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub, - i2p::data::CryptoKeyType type = i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); + void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub); // including hybrid constexpr size_t GetCryptoPrivateKeyLen (i2p::data::CryptoKeyType type) { @@ -168,6 +167,7 @@ namespace crypto case i2p::data::CRYPTO_KEY_TYPE_ELGAMAL: return 256; case i2p::data::CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: return 32; case i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: return 32; + case i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: return 32; }; return 0; } @@ -179,6 +179,7 @@ namespace crypto case i2p::data::CRYPTO_KEY_TYPE_ELGAMAL: return 256; case i2p::data::CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: return 32; case i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: return 32; + case i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: return 32; }; return 0; } diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index bb77b804..4621e147 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1520,14 +1520,14 @@ namespace client bool ClientDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const { - return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? (bool)m_ECIESx25519EncryptionKey : (bool)m_StandardEncryptionKey; + return keyType == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL ? (bool)m_StandardEncryptionKey : (bool)m_ECIESx25519EncryptionKey; } const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const { - if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) - return m_ECIESx25519EncryptionKey ? m_ECIESx25519EncryptionKey->pub.data () : nullptr; - return m_StandardEncryptionKey ? m_StandardEncryptionKey->pub.data () : nullptr; + if (keyType == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) + return m_StandardEncryptionKey ? m_StandardEncryptionKey->pub.data () : nullptr; + return m_ECIESx25519EncryptionKey ? m_ECIESx25519EncryptionKey->pub.data () : nullptr; } void ClientDestination::ReadAuthKey (const std::string& group, const std::map * params) diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index 1891c7a2..576ede0d 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -70,6 +70,7 @@ namespace data const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0; const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 1; const uint16_t CRYPTO_KEY_TYPE_ECIES_X25519_AEAD = 4; + const uint16_t CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD = 5; const uint16_t SIGNING_KEY_TYPE_DSA_SHA1 = 0; const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA256_P256 = 1; From b2fd30d042588349f8587e38f9eeb6e5d309162e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 19 Mar 2025 15:22:09 -0400 Subject: [PATCH 736/787] map of encryption keys --- libi2pd/Destination.cpp | 60 ++++++++++++++++++++++++----------------- libi2pd/Destination.h | 5 ++-- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 4621e147..414ef61c 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1046,20 +1046,15 @@ namespace client for (auto& it: encryptionKeyTypes) { - auto encryptionKey = new EncryptionKey (it); + auto encryptionKey = std::make_shared (it); if (IsPublic ()) PersistTemporaryKeys (encryptionKey); else encryptionKey->GenerateKeys (); encryptionKey->CreateDecryptor (); - if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) - { - m_ECIESx25519EncryptionKey.reset (encryptionKey); - if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) - SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // Rathets must use LeaseSet2 - } - else - m_StandardEncryptionKey.reset (encryptionKey); + if (it > i2p::data::CRYPTO_KEY_TYPE_ELGAMAL && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) + SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // Only DSA can use LeaseSet1 + m_EncryptionKeys.emplace (it, encryptionKey); } if (IsPublic ()) @@ -1409,7 +1404,7 @@ namespace client return ret; } - void ClientDestination::PersistTemporaryKeys (EncryptionKey * keys) + void ClientDestination::PersistTemporaryKeys (std::shared_ptr keys) { if (!keys) return; std::string ident = GetIdentHash().ToBase32(); @@ -1466,9 +1461,10 @@ namespace client std::shared_ptr leaseSet; if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) { - if (m_StandardEncryptionKey) + auto it = m_EncryptionKeys.find (i2p::data::CRYPTO_KEY_TYPE_ELGAMAL); + if (it != m_EncryptionKeys.end ()) { - leaseSet = std::make_shared (GetIdentity (), m_StandardEncryptionKey->pub.data (), tunnels); + leaseSet = std::make_shared (GetIdentity (), it->second->pub.data (), tunnels); // sign Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ()); } @@ -1479,10 +1475,8 @@ namespace client { // standard LS2 (type 3) first i2p::data::LocalLeaseSet2::KeySections keySections; - if (m_ECIESx25519EncryptionKey) - keySections.push_back ({m_ECIESx25519EncryptionKey->keyType, (uint16_t)m_ECIESx25519EncryptionKey->pub.size (), m_ECIESx25519EncryptionKey->pub.data ()} ); - if (m_StandardEncryptionKey) - keySections.push_back ({m_StandardEncryptionKey->keyType, (uint16_t)m_StandardEncryptionKey->decryptor->GetPublicKeyLen (), m_StandardEncryptionKey->pub.data ()} ); + for (const auto& it: m_EncryptionKeys) + keySections.push_back ({it.first, (uint16_t)it.second->pub.size (), it.second->pub.data ()} ); auto publishedTimestamp = i2p::util::GetSecondsSinceEpoch (); if (publishedTimestamp <= m_LastPublishedTimestamp) @@ -1508,11 +1502,22 @@ namespace client bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const { - if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) - if (m_ECIESx25519EncryptionKey && m_ECIESx25519EncryptionKey->decryptor) - return m_ECIESx25519EncryptionKey->decryptor->Decrypt (encrypted, data); - if (m_StandardEncryptionKey && m_StandardEncryptionKey->decryptor) - return m_StandardEncryptionKey->decryptor->Decrypt (encrypted, data); + std::shared_ptr encryptionKey; + if (!m_EncryptionKeys.empty ()) + { + if (m_EncryptionKeys.rbegin ()->first == preferredCrypto) + encryptionKey = m_EncryptionKeys.rbegin ()->second; + else + { + auto it = m_EncryptionKeys.find (preferredCrypto); + if (it != m_EncryptionKeys.end ()) + encryptionKey = it->second; + } + if (!encryptionKey) + encryptionKey = m_EncryptionKeys.rbegin ()->second; + } + if (encryptionKey) + return encryptionKey->decryptor->Decrypt (encrypted, data); else LogPrint (eLogError, "Destinations: Decryptor is not set"); return false; @@ -1520,14 +1525,19 @@ namespace client bool ClientDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const { - return keyType == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL ? (bool)m_StandardEncryptionKey : (bool)m_ECIESx25519EncryptionKey; +#if __cplusplus >= 202002L // C++20 + return m_EncryptionKeys.contains (keyType); +#else + return m_EncryptionKeys.count (keyType) > 0; +#endif } const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const { - if (keyType == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) - return m_StandardEncryptionKey ? m_StandardEncryptionKey->pub.data () : nullptr; - return m_ECIESx25519EncryptionKey ? m_ECIESx25519EncryptionKey->pub.data () : nullptr; + auto it = m_EncryptionKeys.find (keyType); + if (it != m_EncryptionKeys.end ()) + return it->second->pub.data (); + return nullptr; } void ClientDestination::ReadAuthKey (const std::string& group, const std::map * params) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 7684c0f6..df87256d 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -306,7 +306,7 @@ namespace client std::shared_ptr GetSharedFromThis () { return std::static_pointer_cast(shared_from_this ()); } - void PersistTemporaryKeys (EncryptionKey * keys); + void PersistTemporaryKeys (std::shared_ptr keys); void ReadAuthKey (const std::string& group, const std::map * params); template @@ -315,8 +315,7 @@ namespace client private: i2p::data::PrivateKeys m_Keys; - std::unique_ptr m_StandardEncryptionKey; - std::unique_ptr m_ECIESx25519EncryptionKey; + std::map > m_EncryptionKeys; // last is most preferable int m_StreamingAckDelay,m_StreamingOutboundSpeed, m_StreamingInboundSpeed, m_StreamingMaxConcurrentStreams; bool m_IsStreamingAnswerPings; From 9684c86a6939667a96fdb7abcdd4cfd31df74930 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 19 Mar 2025 20:49:52 -0400 Subject: [PATCH 737/787] select key with max key type if no preferred. Changed default preferred type to 4 --- libi2pd/LeaseSet.cpp | 18 +++++++++++------- libi2pd/LeaseSet.h | 6 +++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 3068b35d..e4edcb31 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -400,6 +400,7 @@ namespace data offset += propertiesLen; // skip for now. TODO: implement properties // key sections CryptoKeyType preferredKeyType = m_EncryptionType; + m_EncryptionType = 0; bool preferredKeyFound = false; if (offset + 1 > len) return 0; int numKeySections = buf[offset]; offset++; @@ -411,14 +412,17 @@ namespace data if (offset + encryptionKeyLen > len) return 0; if (IsStoreLeases () && !preferredKeyFound) // create encryptor with leases only { - // we pick first valid key if preferred not found - auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); - if (encryptor && (!m_Encryptor || keyType == preferredKeyType)) + // we pick max key type if preferred not found + if (keyType == preferredKeyType || !m_Encryptor || keyType > m_EncryptionType) { - m_Encryptor = encryptor; // TODO: atomic - m_EncryptionType = keyType; - if (keyType == preferredKeyType) preferredKeyFound = true; - } + auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); + if (encryptor) + { + m_Encryptor = encryptor; // TODO: atomic + m_EncryptionType = keyType; + if (keyType == preferredKeyType) preferredKeyFound = true; + } + } } offset += encryptionKeyLen; } diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index a365ae77..1a89229a 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2024, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -150,8 +150,8 @@ namespace data public: LeaseSet2 (uint8_t storeType): LeaseSet (true), m_StoreType (storeType) {}; // for update - LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); - LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); // store type 5, called from local netdb only + LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); + LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // store type 5, called from local netdb only uint8_t GetStoreType () const { return m_StoreType; }; uint32_t GetPublishedTimestamp () const { return m_PublishedTimestamp; }; bool IsPublic () const { return m_IsPublic; }; From 9769ab0a465a6a1dca8a73995d3f169f1a85019c Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 19 Mar 2025 21:56:59 -0400 Subject: [PATCH 738/787] changed ML-DSA-44 code --- libi2pd/Identity.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index 576ede0d..ee736441 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -84,7 +84,7 @@ namespace data const uint16_t SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256 = 9; const uint16_t SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512 = 10; // approved by FSB const uint16_t SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519 = 11; // for LeaseSet2 only - const uint16_t SIGNING_KEY_TYPE_MLDSA44 = 15; + const uint16_t SIGNING_KEY_TYPE_MLDSA44 = 12; typedef uint16_t SigningKeyType; typedef uint16_t CryptoKeyType; From 935c055a35d92dcd045e9d2fd29e2913f0458c3e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 19 Mar 2025 22:00:08 -0400 Subject: [PATCH 739/787] encryptor/decryptor/keygen for ECIES_MLKEM512_X25519_AEAD --- libi2pd/Identity.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index b5f86f11..3b2f5b97 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -419,6 +419,7 @@ namespace data return std::make_shared(key); break; case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: + case CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: return std::make_shared(key); break; case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: @@ -685,6 +686,7 @@ namespace data return std::make_shared(key); break; case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: + case CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: return std::make_shared(key); break; case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: @@ -772,6 +774,7 @@ namespace data i2p::crypto::CreateECIESP256RandomKeys (priv, pub); break; case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: + case CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: i2p::crypto::CreateECIESX25519AEADRatchetRandomKeys (priv, pub); break; default: From 9fdbb14075c57e6c9baa5e0df0869d011448c90e Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 20 Mar 2025 18:56:10 -0400 Subject: [PATCH 740/787] calculate preferred crypto based i2cp.leaseSetEncType --- libi2pd/Destination.cpp | 14 +++++--------- libi2pd/Destination.h | 21 ++++++++++++--------- libi2pd_client/I2CP.cpp | 8 +++++++- libi2pd_client/I2CP.h | 18 ++++++++++-------- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 414ef61c..d7f311cf 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -994,17 +994,10 @@ namespace client } } - i2p::data::CryptoKeyType LeaseSetDestination::GetPreferredCryptoType () const - { - if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) - return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; - return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL; - } - ClientDestination::ClientDestination (boost::asio::io_context& service, const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): LeaseSetDestination (service, isPublic, params), - m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), + m_Keys (keys), m_PreferredCryptoType (0), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_StreamingOutboundSpeed (DEFAULT_MAX_OUTBOUND_SPEED), m_StreamingInboundSpeed (DEFAULT_MAX_INBOUND_SPEED), m_StreamingMaxConcurrentStreams (DEFAULT_MAX_CONCURRENT_STREAMS), @@ -1029,7 +1022,10 @@ namespace client { try { - encryptionKeyTypes.insert (std::stoi(it1)); + i2p::data::CryptoKeyType preferredCryptoType = std::stoi(it1); + if (!m_PreferredCryptoType && preferredCryptoType) + m_PreferredCryptoType = preferredCryptoType; // first non-zero in the list + encryptionKeyTypes.insert (preferredCryptoType); } catch (std::exception& ex) { diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index df87256d..d844c085 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -171,10 +171,11 @@ namespace client void SetLeaseSetType (int leaseSetType) { m_LeaseSetType = leaseSetType; }; int GetAuthType () const { return m_AuthType; }; virtual void CleanupDestination () {}; // additional clean up in derived classes + virtual i2p::data::CryptoKeyType GetPreferredCryptoType () const = 0; // I2CP virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0; virtual void CreateNewLeaseSet (const std::vector >& tunnels) = 0; - + private: void UpdateLeaseSet (); @@ -193,7 +194,6 @@ namespace client void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest); void HandleCleanupTimer (const boost::system::error_code& ecode); void CleanupRemoteLeaseSets (); - i2p::data::CryptoKeyType GetPreferredCryptoType () const; private: @@ -289,18 +289,20 @@ namespace client i2p::datagram::DatagramDestination * CreateDatagramDestination (bool gzip = true); // implements LocalDestination - bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const; - std::shared_ptr GetIdentity () const { return m_Keys.GetPublic (); }; - bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const; - const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const; + bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const override; + std::shared_ptr GetIdentity () const override { return m_Keys.GetPublic (); }; + bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const override; + const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const override; protected: - void CleanupDestination (); + // LeaseSetDestination + void CleanupDestination () override; + i2p::data::CryptoKeyType GetPreferredCryptoType () const override { return m_PreferredCryptoType; } // I2CP void HandleDataMessage (const uint8_t * buf, size_t len); void CreateNewLeaseSet (const std::vector >& tunnels); - + private: std::shared_ptr GetSharedFromThis () { @@ -316,7 +318,8 @@ namespace client i2p::data::PrivateKeys m_Keys; std::map > m_EncryptionKeys; // last is most preferable - + i2p::data::CryptoKeyType m_PreferredCryptoType; + int m_StreamingAckDelay,m_StreamingOutboundSpeed, m_StreamingInboundSpeed, m_StreamingMaxConcurrentStreams; bool m_IsStreamingAnswerPings; std::shared_ptr m_StreamingDestination; // default diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index df93082b..09fcee71 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -79,7 +79,13 @@ namespace client return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? (bool)m_ECIESx25519Decryptor : m_EncryptionKeyType == keyType; } - + i2p::data::CryptoKeyType I2CPDestination::GetPreferredCryptoType () const + { + if (m_ECIESx25519Decryptor) + return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; + return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL; + } + void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len) { uint32_t length = bufbe32toh (buf); diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 597a4878..936f3c49 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -101,18 +101,20 @@ namespace client bool SendMsg (const uint8_t * payload, size_t len, std::shared_ptr remoteSession, uint32_t nonce); // implements LocalDestination - bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const; - bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const; - const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const; // for 4 only - std::shared_ptr GetIdentity () const { return m_Identity; }; + bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const override; + bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const override; + const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const override; // for 4 only + std::shared_ptr GetIdentity () const override { return m_Identity; }; protected: - void CleanupDestination (); + // LeaseSetDestination + void CleanupDestination () override; + i2p::data::CryptoKeyType GetPreferredCryptoType () const override; // I2CP - void HandleDataMessage (const uint8_t * buf, size_t len); - void CreateNewLeaseSet (const std::vector >& tunnels); - + void HandleDataMessage (const uint8_t * buf, size_t len) override; + void CreateNewLeaseSet (const std::vector >& tunnels) override; + private: std::shared_ptr GetSharedFromThis () From 7b98dd84d880a4ef8286d442f233fdab74c14ec2 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 21 Mar 2025 19:40:02 -0400 Subject: [PATCH 741/787] pass type with static key --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 4 +- libi2pd/ECIESX25519AEADRatchetSession.h | 9 +++-- libi2pd/Garlic.cpp | 48 ++++++++++++----------- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index bdf5f7f7..7a799d29 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -167,7 +167,7 @@ namespace garlic } ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSetNS): - GarlicRoutingSession (owner, true) + GarlicRoutingSession (owner, true), m_RemoteStaticKeyType (0) { if (!attachLeaseSetNS) SetLeaseSetUpdateStatus (eLeaseSetUpToDate); RAND_bytes (m_PaddingSizes, 32); m_NextPaddingSize = 0; @@ -291,7 +291,7 @@ namespace garlic if (isStatic) { // static key, fs is apk - memcpy (m_RemoteStaticKey, fs, 32); + SetRemoteStaticKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD, fs); // TODO: actual key type if (!GetOwner ()->Decrypt (fs, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, apk) { LogPrint (eLogWarning, "Garlic: Incorrect Alice static key"); diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index d17565a8..5614e6cb 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -168,14 +168,16 @@ namespace garlic std::shared_ptr WrapOneTimeMessage (std::shared_ptr msg); const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } - void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); } - + void SetRemoteStaticKey (i2p::data::CryptoKeyType keyType, const uint8_t * key) + { + m_RemoteStaticKeyType = keyType; + memcpy (m_RemoteStaticKey, key, 32); + } void Terminate () { m_IsTerminated = true; } void SetDestination (const i2p::data::IdentHash& dest) { if (!m_Destination) m_Destination.reset (new i2p::data::IdentHash (dest)); } - bool CheckExpired (uint64_t ts); // true is expired bool CanBeRestarted (uint64_t ts) const { return ts > m_SessionCreatedTimestamp + ECIESX25519_RESTART_TIMEOUT; } bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); } @@ -219,6 +221,7 @@ namespace garlic private: + i2p::data::CryptoKeyType m_RemoteStaticKeyType; uint8_t m_RemoteStaticKey[32]; uint8_t m_Aepk[32]; // Alice's ephemeral keys, for incoming only uint8_t m_NSREncodedKey[32], m_NSRH[32], m_NSRKey[32]; // new session reply, for incoming only diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 89737db0..0098bdcd 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2024, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -747,31 +747,35 @@ namespace garlic std::shared_ptr destination, bool attachLeaseSet, bool requestNewIfNotFound) { - if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && - SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) + if (destination->GetEncryptionType () >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) { - ECIESX25519AEADRatchetSessionPtr session; - uint8_t staticKey[32]; - destination->Encrypt (nullptr, staticKey); // we are supposed to get static key - auto it = m_ECIESx25519Sessions.find (staticKey); - if (it != m_ECIESx25519Sessions.end ()) - { - session = it->second; - if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ())) + if (SupportsEncryptionType (destination->GetEncryptionType ())) + { + ECIESX25519AEADRatchetSessionPtr session; + uint8_t staticKey[32]; + destination->Encrypt (nullptr, staticKey); // we are supposed to get static key + auto it = m_ECIESx25519Sessions.find (staticKey); + if (it != m_ECIESx25519Sessions.end ()) { - LogPrint (eLogDebug, "Garlic: Session restarted"); - requestNewIfNotFound = true; // it's not a new session - session = nullptr; + session = it->second; + if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ())) + { + LogPrint (eLogDebug, "Garlic: Session restarted"); + requestNewIfNotFound = true; // it's not a new session + session = nullptr; + } } + if (!session && requestNewIfNotFound) + { + session = std::make_shared (this, true); + session->SetRemoteStaticKey (destination->GetEncryptionType (), staticKey); + } + if (session && destination->IsDestination ()) + session->SetDestination (destination->GetIdentHash ()); // NS or NSR + return session; } - if (!session && requestNewIfNotFound) - { - session = std::make_shared (this, true); - session->SetRemoteStaticKey (staticKey); - } - if (session && destination->IsDestination ()) - session->SetDestination (destination->GetIdentHash ()); // NS or NSR - return session; + else + LogPrint (eLogError, "Garlic: Non-supported encryption type ", destination->GetEncryptionType ()); } else { From af5d2a415c26fffb7c5158cbea9fa716d5e2960e Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 22 Mar 2025 12:01:47 -0400 Subject: [PATCH 742/787] c++20 --- Makefile.haiku | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.haiku b/Makefile.haiku index bc3094f6..5dce7d7f 100644 --- a/Makefile.haiku +++ b/Makefile.haiku @@ -1,8 +1,8 @@ CXX = g++ -CXXFLAGS := -Wall -std=c++17 +CXXFLAGS := -Wall -std=c++20 INCFLAGS = -I/system/develop/headers DEFINES = -D_DEFAULT_SOURCE -D_GNU_SOURCE -LDLIBS = -lbe -lbsd -lnetwork -lz -lssl -lcrypto -lboost_system -lboost_program_options -lpthread +LDLIBS = -lbe -lbsd -lnetwork -lz -lssl -lcrypto -lboost_program_options -lpthread ifeq ($(USE_UPNP),yes) DEFINES += -DUSE_UPNP From 029e279b487af61cb9577d40baa46642060c76f2 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 22 Mar 2025 12:30:51 -0400 Subject: [PATCH 743/787] fixed typo --- libi2pd_client/AddressBook.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index c0f440f9..8333e87d 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -584,7 +584,7 @@ namespace client } #if __cplusplus >= 202002L // C++20 - if (name.ends_with (".i2p")) + if (!name.ends_with (".i2p")) #else if (name.find(".i2p") == name.npos) #endif From 41197264c626f908c3afcea0b0d162e6349aac2a Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 22 Mar 2025 15:42:22 -0400 Subject: [PATCH 744/787] fixed warning --- libi2pd/Destination.h | 8 ++++---- libi2pd_client/I2CP.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index d844c085..802d7780 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -251,8 +251,8 @@ namespace client bool isPublic, const std::map * params = nullptr); ~ClientDestination (); - void Start (); - void Stop (); + void Start () override; + void Stop () override; const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; @@ -300,8 +300,8 @@ namespace client void CleanupDestination () override; i2p::data::CryptoKeyType GetPreferredCryptoType () const override { return m_PreferredCryptoType; } // I2CP - void HandleDataMessage (const uint8_t * buf, size_t len); - void CreateNewLeaseSet (const std::vector >& tunnels); + void HandleDataMessage (const uint8_t * buf, size_t len) override; + void CreateNewLeaseSet (const std::vector >& tunnels) override; private: diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 936f3c49..3a9a7e7f 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -90,7 +90,7 @@ namespace client const std::map& params); ~I2CPDestination () {}; - void Stop (); + void Stop () override; void SetEncryptionPrivateKey (const uint8_t * key); void SetEncryptionType (i2p::data::CryptoKeyType keyType) { m_EncryptionKeyType = keyType; }; From a193186935a4098200ecfd19da1678b21bbc57dd Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 22 Mar 2025 22:25:06 -0400 Subject: [PATCH 745/787] MLKEM512 keygen added --- libi2pd/Crypto.cpp | 73 +++++++++++++++++++++++++++++++++++++--------- libi2pd/Crypto.h | 20 +++++++++++++ 2 files changed, 79 insertions(+), 14 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 095f25d6..cd3b0fbc 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -29,7 +29,7 @@ namespace i2p { namespace crypto { - const uint8_t elgp_[256]= + constexpr uint8_t elgp_[256]= { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, @@ -49,9 +49,9 @@ namespace crypto 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - const int elgg_ = 2; + constexpr int elgg_ = 2; - const uint8_t dsap_[128]= + constexpr uint8_t dsap_[128]= { 0x9c, 0x05, 0xb2, 0xaa, 0x96, 0x0d, 0x9b, 0x97, 0xb8, 0x93, 0x19, 0x63, 0xc9, 0xcc, 0x9e, 0x8c, 0x30, 0x26, 0xe9, 0xb8, 0xed, 0x92, 0xfa, 0xd0, 0xa6, 0x9c, 0xc8, 0x86, 0xd5, 0xbf, 0x80, 0x15, @@ -63,13 +63,13 @@ namespace crypto 0x28, 0x5d, 0x4c, 0xf2, 0x95, 0x38, 0xd9, 0xe3, 0xb6, 0x05, 0x1f, 0x5b, 0x22, 0xcc, 0x1c, 0x93 }; - const uint8_t dsaq_[20]= + constexpr uint8_t dsaq_[20]= { 0xa5, 0xdf, 0xc2, 0x8f, 0xef, 0x4c, 0xa1, 0xe2, 0x86, 0x74, 0x4c, 0xd8, 0xee, 0xd9, 0xd2, 0x9d, 0x68, 0x40, 0x46, 0xb7 }; - const uint8_t dsag_[128]= + constexpr uint8_t dsag_[128]= { 0x0c, 0x1f, 0x4d, 0x27, 0xd4, 0x00, 0x93, 0xb4, 0x29, 0xe9, 0x62, 0xd7, 0x22, 0x38, 0x24, 0xe0, 0xbb, 0xc4, 0x7e, 0x7c, 0x83, 0x2a, 0x39, 0x23, 0x6f, 0xc6, 0x83, 0xaf, 0x84, 0x88, 0x95, 0x81, @@ -81,7 +81,7 @@ namespace crypto 0xb3, 0xdb, 0xb1, 0x4a, 0x90, 0x5e, 0x7b, 0x2b, 0x3e, 0x93, 0xbe, 0x47, 0x08, 0xcb, 0xcc, 0x82 }; - const int rsae_ = 65537; + constexpr int rsae_ = 65537; struct CryptoConstants { @@ -824,8 +824,8 @@ namespace crypto void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub) { - static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars - static const uint8_t hh[32] = + static constexpr char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars + static constexpr uint8_t hh[32] = { 0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1, 0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54 @@ -835,12 +835,12 @@ namespace crypto void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub) { - static const uint8_t protocolNameHash[32] = + static constexpr uint8_t protocolNameHash[32] = { 0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed, 0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71 }; // SHA256 ("Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256") - static const uint8_t hh[32] = + static constexpr uint8_t hh[32] = { 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e @@ -850,12 +850,12 @@ namespace crypto void InitNoiseXKState1 (NoiseSymmetricState& state, const uint8_t * pub) { - static const uint8_t protocolNameHash[32] = + static constexpr uint8_t protocolNameHash[32] = { 0xb1, 0x37, 0x22, 0x81, 0x74, 0x23, 0xa8, 0xfd, 0xf4, 0x2d, 0xf2, 0xe6, 0x0e, 0xd1, 0xed, 0xf4, 0x1b, 0x93, 0x07, 0x1d, 0xb1, 0xec, 0x24, 0xa3, 0x67, 0xf7, 0x84, 0xec, 0x27, 0x0d, 0x81, 0x32 }; // SHA256 ("Noise_XKchaobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256") - static const uint8_t hh[32] = + static constexpr uint8_t hh[32] = { 0xdc, 0x85, 0xe6, 0xaf, 0x7b, 0x02, 0x65, 0x0c, 0xf1, 0xf9, 0x0d, 0x71, 0xfb, 0xc6, 0xd4, 0x53, 0xa7, 0xcf, 0x6d, 0xbf, 0xbd, 0x52, 0x5e, 0xa5, 0xb5, 0x79, 0x1c, 0x47, 0xb3, 0x5e, 0xbc, 0x33 @@ -865,12 +865,12 @@ namespace crypto void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub) { - static const uint8_t protocolNameHash[32] = + static constexpr uint8_t protocolNameHash[32] = { 0x4c, 0xaf, 0x11, 0xef, 0x2c, 0x8e, 0x36, 0x56, 0x4c, 0x53, 0xe8, 0x88, 0x85, 0x06, 0x4d, 0xba, 0xac, 0xbe, 0x00, 0x54, 0xad, 0x17, 0x8f, 0x80, 0x79, 0xa6, 0x46, 0x82, 0x7e, 0x6e, 0xe4, 0x0c }; // SHA256("Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"), 40 bytes - static const uint8_t hh[32] = + static constexpr uint8_t hh[32] = { 0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32, 0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c @@ -878,6 +878,21 @@ namespace crypto InitNoiseState (state, protocolNameHash, hh, pub); } + void InitNoiseIKStateMLKEM512 (NoiseSymmetricState& state, const uint8_t * pub) + { + static constexpr uint8_t protocolNameHash[32] = + { + 0xb0, 0x8f, 0xb1, 0x73, 0x92, 0x66, 0xc9, 0x90, 0x45, 0x7f, 0xdd, 0xc6, 0x4e, 0x55, 0x40, 0xd8, + 0x0a, 0x37, 0x99, 0x06, 0x92, 0x2a, 0x78, 0xc4, 0xb1, 0xef, 0x86, 0x06, 0xd0, 0x15, 0x9f, 0x4d + }; // SHA256("Noise_IKhfselg2_25519+MLKEM512_ChaChaPoly_SHA256") + static constexpr uint8_t hh[32] = + { + 0x95, 0x8d, 0xf6, 0x6c, 0x95, 0xce, 0xa9, 0xf7, 0x42, 0xfc, 0xfa, 0x62, 0x71, 0x36, 0x1e, 0xa7, + 0xdc, 0x7a, 0xc0, 0x75, 0x01, 0xcf, 0xf9, 0xfc, 0x9f, 0xdb, 0x4c, 0x68, 0x3a, 0x53, 0x49, 0xeb + }; // SHA256 (protocolNameHash) + InitNoiseState (state, protocolNameHash, hh, pub); + } + // init and terminate /* std::vector > m_OpenSSLMutexes; @@ -926,5 +941,35 @@ namespace crypto /* CRYPTO_set_locking_callback (nullptr); m_OpenSSLMutexes.clear ();*/ } + +#if OPENSSL_PQ +#include + + MLKEM512Keys::MLKEM512Keys (): + m_Pkey (nullptr) + { + } + + MLKEM512Keys::~MLKEM512Keys () + { + if (m_Pkey) EVP_PKEY_free (m_Pkey); + } + + void MLKEM512Keys::GenerateKeys () + { + if (m_Pkey) + { + EVP_PKEY_free (m_Pkey); + m_Pkey = nullptr; + } + m_Pkey = EVP_PKEY_Q_keygen(NULL, NULL, "ML-KEM-512"); + } + + void MLKEM512Keys::GetPublicKey (uint8_t * pub) const + { + size_t len = MLKEM512_KEY_LENGTH; + EVP_PKEY_get_octet_string_param (m_Pkey, OSSL_PKEY_PARAM_PUB_KEY, pub, MLKEM512_KEY_LENGTH, &len); + } +#endif } } diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index b2fa0292..6b7b0e30 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -261,10 +261,30 @@ namespace crypto void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (NTCP2) void InitNoiseXKState1 (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (SSU2) void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets) + void InitNoiseIKStateMLKEM512 (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets) PQ ML-KEM512 // init and terminate void InitCrypto (bool precomputation); void TerminateCrypto (); + +#if OPENSSL_PQ +// Post Quantum + constexpr size_t MLKEM512_KEY_LENGTH = 800; + class MLKEM512Keys + { + public: + + MLKEM512Keys (); + ~MLKEM512Keys (); + + void GenerateKeys (); + void GetPublicKey (uint8_t * pub) const; + + private: + + EVP_PKEY * m_Pkey; + }; +#endif } } From 75d5c6036e9b9df63443b04ce93606a1f34106fb Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 23 Mar 2025 18:53:32 -0400 Subject: [PATCH 746/787] use EVP interface for DSA sign/verify with OpenSSL 3 --- libi2pd/Crypto.cpp | 39 +++++++++- libi2pd/Crypto.h | 4 ++ libi2pd/Signature.cpp | 164 +++++++++++++++++++++++++++++++++++++++++- libi2pd/Signature.h | 88 +++++++---------------- 4 files changed, 227 insertions(+), 68 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index cd3b0fbc..414314cf 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -19,6 +19,10 @@ #if OPENSSL_HKDF #include #endif +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 +#include +#include +#endif #include "CPU.h" #include "Crypto.h" #include "Ed25519.h" @@ -146,6 +150,37 @@ namespace crypto #define dsap GetCryptoConstants ().dsap #define dsaq GetCryptoConstants ().dsaq #define dsag GetCryptoConstants ().dsag +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + EVP_PKEY * CreateDSA (BIGNUM * pubKey, BIGNUM * privKey) + { + EVP_PKEY * pkey = nullptr; + int selection = EVP_PKEY_KEY_PARAMETERS; + auto bld = OSSL_PARAM_BLD_new(); + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, dsap); + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, dsaq); + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, dsag); + if (pubKey) + { + OSSL_PARAM_BLD_push_BN (bld, OSSL_PKEY_PARAM_PUB_KEY, pubKey); + selection = EVP_PKEY_PUBLIC_KEY; + } + if (privKey) + { + OSSL_PARAM_BLD_push_BN (bld, OSSL_PKEY_PARAM_PRIV_KEY, privKey); + selection = EVP_PKEY_KEYPAIR; + } + auto params = OSSL_PARAM_BLD_to_param(bld); + + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "DSA", NULL); + EVP_PKEY_fromdata_init(ctx); + EVP_PKEY_fromdata(ctx, &pkey, selection, params); + + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + return pkey; + } +#else DSA * CreateDSA () { DSA * dsa = DSA_new (); @@ -153,7 +188,8 @@ namespace crypto DSA_set0_key (dsa, NULL, NULL); return dsa; } - +#endif + // DH/ElGamal #if !IS_X86_64 @@ -943,7 +979,6 @@ namespace crypto } #if OPENSSL_PQ -#include MLKEM512Keys::MLKEM512Keys (): m_Pkey (nullptr) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 6b7b0e30..b6ab3fa4 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -45,7 +45,11 @@ namespace crypto bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len); // DSA +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + EVP_PKEY * CreateDSA (BIGNUM * pubKey = nullptr, BIGNUM * privKey = nullptr); +#else DSA * CreateDSA (); +#endif // RSA const BIGNUM * GetRSAE (); diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index f684f10f..3e4b451b 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -7,6 +7,10 @@ */ #include +#include +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 +#include +#endif #include "Log.h" #include "Signature.h" @@ -14,6 +18,163 @@ namespace i2p { namespace crypto { +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + DSAVerifier::DSAVerifier (): + m_PublicKey (nullptr) + { + } + + DSAVerifier::~DSAVerifier () + { + if (m_PublicKey) + EVP_PKEY_free (m_PublicKey); + } + + void DSAVerifier::SetPublicKey (const uint8_t * signingKey) + { + if (m_PublicKey) + EVP_PKEY_free (m_PublicKey); + BIGNUM * pub = BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL); + m_PublicKey = CreateDSA (pub); + BN_free (pub); + } + + bool DSAVerifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const + { + // calculate SHA1 digest + uint8_t digest[20], sign[48]; + SHA1 (buf, len, digest); + // signature + DSA_SIG * sig = DSA_SIG_new(); + DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL)); + // to DER format + uint8_t * s = sign; + auto l = i2d_DSA_SIG (sig, &s); + DSA_SIG_free(sig); + // verify + auto ctx = EVP_PKEY_CTX_new (m_PublicKey, NULL); + EVP_PKEY_verify_init(ctx); + EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1()); + bool ret = EVP_PKEY_verify(ctx, sign, l, digest, 20); + EVP_PKEY_CTX_free(ctx); + return ret; + } + + DSASigner::DSASigner (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey) + { + BIGNUM * priv = BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL); + m_PrivateKey = CreateDSA (nullptr, priv); + BN_free (priv); + } + + DSASigner::~DSASigner () + { + if (m_PrivateKey) + EVP_PKEY_free (m_PrivateKey); + } + + void DSASigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const + { + uint8_t digest[20], sign[48]; + SHA1 (buf, len, digest); + auto ctx = EVP_PKEY_CTX_new (m_PrivateKey, NULL); + EVP_PKEY_sign_init(ctx); + EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1()); + size_t l = 48; + EVP_PKEY_sign(ctx, sign, &l, digest, 20); + const uint8_t * s1 = sign; + DSA_SIG * sig = d2i_DSA_SIG (NULL, &s1, l); + const BIGNUM * r, * s; + DSA_SIG_get0 (sig, &r, &s); + bn2buf (r, signature, DSA_SIGNATURE_LENGTH/2); + bn2buf (s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2); + DSA_SIG_free(sig); + EVP_PKEY_CTX_free(ctx); + } + + void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + EVP_PKEY * paramskey = CreateDSA(); + EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new_from_pkey(NULL, paramskey, NULL); + EVP_PKEY_keygen_init(ctx); + EVP_PKEY * pkey = nullptr; + EVP_PKEY_keygen(ctx, &pkey); + BIGNUM * pub = NULL, * priv = NULL; + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &pub); + bn2buf (pub, signingPublicKey, DSA_PUBLIC_KEY_LENGTH); + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv); + bn2buf (priv, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH); + BN_free (pub); BN_free (priv); + EVP_PKEY_free (pkey); + EVP_PKEY_free (paramskey); + EVP_PKEY_CTX_free (ctx); + } +#else + + DSAVerifier::DSAVerifier () + { + m_PublicKey = CreateDSA (); + } + + DSAVerifier::~DSAVerifier () + { + DSA_free (m_PublicKey); + } + + void DSAVerifier::SetPublicKey (const uint8_t * signingKey) + { + DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL); + } + + bool DSAVerifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const + { + // calculate SHA1 digest + uint8_t digest[20]; + SHA1 (buf, len, digest); + // signature + DSA_SIG * sig = DSA_SIG_new(); + DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL)); + // DSA verification + int ret = DSA_do_verify (digest, 20, sig, m_PublicKey); + DSA_SIG_free(sig); + return ret; + } + + DSASigner::DSASigner (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey) + { + m_PrivateKey = CreateDSA (); + DSA_set0_key (m_PrivateKey, BN_bin2bn (signingPublicKey, DSA_PUBLIC_KEY_LENGTH, NULL), BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL)); + } + + DSASigner::~DSASigner () + { + DSA_free (m_PrivateKey); + } + + void DSASigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const + { + uint8_t digest[20]; + SHA1 (buf, len, digest); + DSA_SIG * sig = DSA_do_sign (digest, 20, m_PrivateKey); + const BIGNUM * r, * s; + DSA_SIG_get0 (sig, &r, &s); + bn2buf (r, signature, DSA_SIGNATURE_LENGTH/2); + bn2buf (s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2); + DSA_SIG_free(sig); + } + + void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + DSA * dsa = CreateDSA (); + DSA_generate_key (dsa); + const BIGNUM * pub_key, * priv_key; + DSA_get0_key(dsa, &pub_key, &priv_key); + bn2buf (priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH); + bn2buf (pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH); + DSA_free (dsa); + } +#endif + #if OPENSSL_EDDSA EDDSA25519Verifier::EDDSA25519Verifier (): m_Pkey (nullptr) @@ -202,8 +363,7 @@ namespace crypto #endif #if OPENSSL_PQ -#include - + MLDSA44Verifier::MLDSA44Verifier (): m_Pkey (nullptr) { diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index c77e10dd..20c7e11b 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -43,94 +43,55 @@ namespace crypto virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0; }; + // DSA const size_t DSA_PUBLIC_KEY_LENGTH = 128; const size_t DSA_SIGNATURE_LENGTH = 40; const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH/2; class DSAVerifier: public Verifier { public: + + DSAVerifier (); + ~DSAVerifier (); - DSAVerifier () - { - m_PublicKey = CreateDSA (); - } - - void SetPublicKey (const uint8_t * signingKey) - { - DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL); - } - - ~DSAVerifier () - { - DSA_free (m_PublicKey); - } - - bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const - { - // calculate SHA1 digest - uint8_t digest[20]; - SHA1 (buf, len, digest); - // signature - DSA_SIG * sig = DSA_SIG_new(); - DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL)); - // DSA verification - int ret = DSA_do_verify (digest, 20, sig, m_PublicKey); - DSA_SIG_free(sig); - return ret; - } - - size_t GetPublicKeyLen () const { return DSA_PUBLIC_KEY_LENGTH; }; - size_t GetSignatureLen () const { return DSA_SIGNATURE_LENGTH; }; - + // implements Verifier + void SetPublicKey (const uint8_t * signingKey) override; + bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const override; + size_t GetPublicKeyLen () const override { return DSA_PUBLIC_KEY_LENGTH; }; + size_t GetSignatureLen () const override { return DSA_SIGNATURE_LENGTH; }; + private: +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + EVP_PKEY * m_PublicKey; +#else DSA * m_PublicKey; +#endif }; class DSASigner: public Signer { public: - DSASigner (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey) + DSASigner (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey); // openssl 1.1 always requires DSA public key even for signing - { - m_PrivateKey = CreateDSA (); - DSA_set0_key (m_PrivateKey, BN_bin2bn (signingPublicKey, DSA_PUBLIC_KEY_LENGTH, NULL), BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL)); - } + ~DSASigner (); - ~DSASigner () - { - DSA_free (m_PrivateKey); - } - - void Sign (const uint8_t * buf, int len, uint8_t * signature) const - { - uint8_t digest[20]; - SHA1 (buf, len, digest); - DSA_SIG * sig = DSA_do_sign (digest, 20, m_PrivateKey); - const BIGNUM * r, * s; - DSA_SIG_get0 (sig, &r, &s); - bn2buf (r, signature, DSA_SIGNATURE_LENGTH/2); - bn2buf (s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2); - DSA_SIG_free(sig); - } + // implements Signer + void Sign (const uint8_t * buf, int len, uint8_t * signature) const override; private: +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + EVP_PKEY * m_PrivateKey; +#else DSA * m_PrivateKey; +#endif }; - inline void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) - { - DSA * dsa = CreateDSA (); - DSA_generate_key (dsa); - const BIGNUM * pub_key, * priv_key; - DSA_get0_key(dsa, &pub_key, &priv_key); - bn2buf (priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH); - bn2buf (pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH); - DSA_free (dsa); - } + void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey); + // ECDSA struct SHA256Hash { static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) @@ -161,7 +122,6 @@ namespace crypto enum { hashLen = 64 }; }; - // EcDSA template class ECDSAVerifier: public Verifier { From 22d854a6be8d34cd63401c32f7afc1f6a7606913 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 24 Mar 2025 15:45:06 -0400 Subject: [PATCH 747/787] ML-KEM-512 encaps/decaps --- libi2pd/Crypto.cpp | 66 +++++++++++++++++++++++++++++++++++++++++----- libi2pd/Crypto.h | 4 +++ 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 414314cf..9bdfe43f 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -992,19 +992,71 @@ namespace crypto void MLKEM512Keys::GenerateKeys () { - if (m_Pkey) - { - EVP_PKEY_free (m_Pkey); - m_Pkey = nullptr; - } + if (m_Pkey) EVP_PKEY_free (m_Pkey); m_Pkey = EVP_PKEY_Q_keygen(NULL, NULL, "ML-KEM-512"); } void MLKEM512Keys::GetPublicKey (uint8_t * pub) const { - size_t len = MLKEM512_KEY_LENGTH; - EVP_PKEY_get_octet_string_param (m_Pkey, OSSL_PKEY_PARAM_PUB_KEY, pub, MLKEM512_KEY_LENGTH, &len); + if (m_Pkey) + { + size_t len = MLKEM512_KEY_LENGTH; + EVP_PKEY_get_octet_string_param (m_Pkey, OSSL_PKEY_PARAM_PUB_KEY, pub, MLKEM512_KEY_LENGTH, &len); + } } + + void MLKEM512Keys::SetPublicKey (const uint8_t * pub) + { + if (m_Pkey) + { + EVP_PKEY_free (m_Pkey); + m_Pkey = nullptr; + } + OSSL_PARAM params[] = + { + OSSL_PARAM_octet_string (OSSL_PKEY_PARAM_PUB_KEY, (uint8_t *)pub, MLKEM512_KEY_LENGTH), + OSSL_PARAM_END + }; + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "ML-KEM-512", NULL); + if (ctx) + { + EVP_PKEY_fromdata_init (ctx); + EVP_PKEY_fromdata (ctx, &m_Pkey, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, params); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "MLKEM512 can't create PKEY context"); + } + + void MLKEM512Keys::Encaps (uint8_t * ciphertext, uint8_t * shared) + { + if (!m_Pkey) return; + auto ctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL); + if (ctx) + { + EVP_PKEY_encapsulate_init (ctx, NULL); + size_t len = MLKEM512_CIPHER_TEXT_LENGTH, sharedLen = 32; + EVP_PKEY_encapsulate (ctx, ciphertext, &len, shared, &sharedLen); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "MLKEM512 can't create PKEY context"); + } + + void MLKEM512Keys::Decaps (const uint8_t * ciphertext, uint8_t * shared) + { + if (!m_Pkey) return; + auto ctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL); + if (ctx) + { + EVP_PKEY_decapsulate_init (ctx, NULL); + size_t sharedLen = 32; + EVP_PKEY_decapsulate (ctx, shared, &sharedLen, ciphertext, MLKEM512_CIPHER_TEXT_LENGTH); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "MLKEM512 can't create PKEY context"); + } #endif } } diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index b6ab3fa4..dcdc27d3 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -274,6 +274,7 @@ namespace crypto #if OPENSSL_PQ // Post Quantum constexpr size_t MLKEM512_KEY_LENGTH = 800; + constexpr size_t MLKEM512_CIPHER_TEXT_LENGTH = 768; class MLKEM512Keys { public: @@ -283,6 +284,9 @@ namespace crypto void GenerateKeys (); void GetPublicKey (uint8_t * pub) const; + void SetPublicKey (const uint8_t * pub); + void Encaps (uint8_t * ciphertext, uint8_t * shared); + void Decaps (const uint8_t * ciphertext, uint8_t * shared); private: From d3cfbbd6b0484c6b0c2c225de00f9bfbea384d29 Mon Sep 17 00:00:00 2001 From: AsciiMoth Date: Tue, 25 Mar 2025 09:35:00 +0400 Subject: [PATCH 748/787] Update dates range in licence --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 93280084..f59491f5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2023, The PurpleI2P Project +Copyright (c) 2013-2025, The PurpleI2P Project All rights reserved. From ecf19278e86d75e4834ad0af61a0c534f7332703 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 25 Mar 2025 18:55:28 -0400 Subject: [PATCH 749/787] skip post-quantum keys if not supported --- libi2pd/Destination.cpp | 13 +++++++++---- libi2pd/LeaseSet.cpp | 21 +++++++++++++-------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index d7f311cf..e20249c5 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1022,10 +1022,15 @@ namespace client { try { - i2p::data::CryptoKeyType preferredCryptoType = std::stoi(it1); - if (!m_PreferredCryptoType && preferredCryptoType) - m_PreferredCryptoType = preferredCryptoType; // first non-zero in the list - encryptionKeyTypes.insert (preferredCryptoType); + i2p::data::CryptoKeyType cryptoType = std::stoi(it1); +#if !OPENSSL_PQ + if (cryptoType <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // skip PQ keys if not supported +#endif + { + if (!m_PreferredCryptoType && cryptoType) + m_PreferredCryptoType = cryptoType; // first non-zero in the list + encryptionKeyTypes.insert (cryptoType); + } } catch (std::exception& ex) { diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index e4edcb31..db8c1aad 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -413,15 +413,20 @@ namespace data if (IsStoreLeases () && !preferredKeyFound) // create encryptor with leases only { // we pick max key type if preferred not found - if (keyType == preferredKeyType || !m_Encryptor || keyType > m_EncryptionType) - { - auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); - if (encryptor) +#if !OPENSSL_PQ + if (keyType <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // skip PQ keys if not supported +#endif + { + if (keyType == preferredKeyType || !m_Encryptor || keyType > m_EncryptionType) { - m_Encryptor = encryptor; // TODO: atomic - m_EncryptionType = keyType; - if (keyType == preferredKeyType) preferredKeyFound = true; - } + auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); + if (encryptor) + { + m_Encryptor = encryptor; // TODO: atomic + m_EncryptionType = keyType; + if (keyType == preferredKeyType) preferredKeyFound = true; + } + } } } offset += encryptionKeyLen; From 81ba19e1ae060347add0179f9594e0c3b9383473 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 25 Mar 2025 21:31:16 -0400 Subject: [PATCH 750/787] use find_directory to detect data dir in Haiku --- libi2pd/FS.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index a623a4eb..3f5fc6b9 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2024, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -15,6 +15,10 @@ #include #endif +#if defined(__HAIKU__) +#include +#endif + #ifdef _WIN32 #include #include @@ -169,12 +173,11 @@ namespace fs { dataDir += "/Library/Application Support/" + appName; return; #elif defined(__HAIKU__) - char *home = getenv("HOME"); - if (home != NULL && strlen(home) > 0) { - dataDir = std::string(home) + "/config/settings/" + appName; - } else { + char home[PATH_MAX]; // /boot/home/config/settings + if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, home, PATH_MAX) == B_OK) + dataDir = std::string(home) + "/" + appName; + else dataDir = "/tmp/" + appName; - } return; #else /* other unix */ #if defined(ANDROID) From 871fc14ba64bdeeab7a51914b5a9d266832afd27 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 27 Mar 2025 16:24:02 -0400 Subject: [PATCH 751/787] ML-KEM section for NS and NSR outgoing sessions --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 54 ++++++++++++++++++++++- libi2pd/ECIESX25519AEADRatchetSession.h | 3 ++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 7a799d29..865fc973 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -492,7 +492,16 @@ namespace garlic offset += 32; // KDF1 - i2p::crypto::InitNoiseIKState (GetNoiseState (), m_RemoteStaticKey); // bpk +#if OPENSSL_PQ + if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) + { + i2p::crypto::InitNoiseIKStateMLKEM512 (GetNoiseState (), m_RemoteStaticKey); // bpk + m_PQKeys = std::make_unique(); + m_PQKeys->GenerateKeys (); + } + else +#endif + i2p::crypto::InitNoiseIKState (GetNoiseState (), m_RemoteStaticKey); // bpk MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || aepk) uint8_t sharedSecret[32]; if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret)) // x25519(aesk, bpk) @@ -501,9 +510,29 @@ namespace garlic return false; } MixKey (sharedSecret); + uint64_t n = 0; // seqn +#if OPENSSL_PQ + if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) + { + uint8_t encapsKey[i2p::crypto::MLKEM512_KEY_LENGTH]; + m_PQKeys->GetPublicKey (encapsKey); + // encrypt encapsKey + uint8_t nonce[12]; + CreateNonce (n, nonce); + if (!i2p::crypto::AEADChaCha20Poly1305 (encapsKey, i2p::crypto::MLKEM512_KEY_LENGTH, + m_H, 32, m_CK + 32, nonce, out + offset, i2p::crypto::MLKEM512_KEY_LENGTH + 16, true)) // encrypt + { + LogPrint (eLogWarning, "Garlic: ML-KEM encap_key section AEAD encryption failed "); + return false; + } + MixHash (out + offset, i2p::crypto::MLKEM512_KEY_LENGTH + 16); // h = SHA256(h || ciphertext) + offset += i2p::crypto::MLKEM512_KEY_LENGTH + 16; + n++; + } +#endif // encrypt flags/static key section uint8_t nonce[12]; - CreateNonce (0, nonce); + CreateNonce (n, nonce); const uint8_t * fs; if (isStatic) fs = GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); @@ -675,6 +704,24 @@ namespace garlic uint8_t nonce[12]; CreateNonce (0, nonce); +#if OPENSSL_PQ + if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) + { + // decrypt kem_ciphertext section + uint8_t kemCiphertext[i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH]; + if (!i2p::crypto::AEADChaCha20Poly1305 (buf, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH, + m_H, 32, m_CK + 32, nonce, kemCiphertext, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH, false)) // decrypt, DECRYPT(k, n, ZEROLEN, ad) verification only + { + LogPrint (eLogWarning, "Garlic: Reply ML-KEM ciphertext section AEAD decryption failed"); + return false; + } + MixHash (buf, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16); + buf += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; + // decaps + m_PQKeys->Decaps (kemCiphertext, sharedSecret); + MixKey (sharedSecret); + } +#endif // calculate hash for zero length if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 0, m_H, 32, m_CK + 32, nonce, sharedSecret/* can be anything */, 0, false)) // decrypt, DECRYPT(k, n, ZEROLEN, ad) verification only { @@ -711,6 +758,9 @@ namespace garlic { m_State = eSessionStateEstablished; //m_EphemeralKeys = nullptr; // TODO: delete after a while +#if OPENSSL_PQ + // m_PQKeys = nullptr; // TODO: delete after a while +#endif m_SessionCreatedTimestamp = i2p::util::GetSecondsSinceEpoch (); GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 5614e6cb..cd32cb98 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -226,6 +226,9 @@ namespace garlic uint8_t m_Aepk[32]; // Alice's ephemeral keys, for incoming only uint8_t m_NSREncodedKey[32], m_NSRH[32], m_NSRKey[32]; // new session reply, for incoming only std::shared_ptr m_EphemeralKeys; +#if OPENSSL_PQ + std::unique_ptr m_PQKeys; +#endif SessionState m_State = eSessionStateNew; uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0, // incoming (in seconds) m_LastSentTimestamp = 0; // in milliseconds From 7404ce7fd2e69b8e3e70d90b594a04e44053836c Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 28 Mar 2025 19:34:36 -0400 Subject: [PATCH 752/787] update session's remote enpoint after receiving path response --- libi2pd/SSU2Session.cpp | 24 +++++++++++++++--------- libi2pd/SSU2Session.h | 4 ++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index e0a9a48f..dd170714 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1498,11 +1498,11 @@ namespace transport ResendHandshakePacket (); // assume we receive return; } - if (from != m_RemoteEndpoint && !i2p::transport::transports.IsInReservedRange (from.address ())) + if (from != m_RemoteEndpoint && !i2p::transport::transports.IsInReservedRange (from.address ()) && + (!m_PathChallenge || from != m_PathChallenge->second)) // path challenge was not sent to this endpoint yet { LogPrint (eLogInfo, "SSU2: Remote endpoint update ", m_RemoteEndpoint, "->", from); - m_RemoteEndpoint = from; - SendPathChallenge (); + SendPathChallenge (from); } if (len < 32) { @@ -1660,10 +1660,13 @@ namespace transport LogPrint (eLogDebug, "SSU2: Path response"); if (m_PathChallenge) { - i2p::data::IdentHash hash; + i2p::data::Tag<32> hash; SHA256 (buf + offset, size, hash); - if (hash == *m_PathChallenge) + if (hash == m_PathChallenge->first) + { + m_RemoteEndpoint = m_PathChallenge->second; m_PathChallenge.reset (nullptr); + } } break; } @@ -3070,7 +3073,7 @@ namespace transport SendData (payload, payloadSize); } - void SSU2Session::SendPathChallenge () + void SSU2Session::SendPathChallenge (const boost::asio::ip::udp::endpoint& to) { uint8_t payload[SSU2_MAX_PACKET_SIZE]; payload[0] = eSSU2BlkPathChallenge; @@ -3078,15 +3081,18 @@ namespace transport htobe16buf (payload + 1, len); if (len > 0) { + m_PathChallenge = std::make_unique, boost::asio::ip::udp::endpoint> >(); RAND_bytes (payload + 3, len); - i2p::data::IdentHash * hash = new i2p::data::IdentHash (); - SHA256 (payload + 3, len, *hash); - m_PathChallenge.reset (hash); + SHA256 (payload + 3, len, m_PathChallenge->first); + m_PathChallenge->second = to; } len += 3; if (len < m_MaxPayloadSize) len += CreatePaddingBlock (payload + len, m_MaxPayloadSize - len, len < 8 ? 8 : 0); + auto existing = m_RemoteEndpoint; + m_RemoteEndpoint = to; // send path challenge to new endpoint SendData (payload, len); + m_RemoteEndpoint = existing; // restore endpoint back until path response received } void SSU2Session::CleanUp (uint64_t ts) diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index ee295acb..6d2bf103 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -327,7 +327,7 @@ namespace transport void SendQuickAck (); void SendTermination (); void SendPathResponse (const uint8_t * data, size_t len); - void SendPathChallenge (); + void SendPathChallenge (const boost::asio::ip::udp::endpoint& to); void HandleDateTime (const uint8_t * buf, size_t len); void HandleRouterInfo (const uint8_t * buf, size_t len); @@ -394,7 +394,7 @@ namespace transport boost::asio::deadline_timer m_ConnectTimer; SSU2TerminationReason m_TerminationReason; size_t m_MaxPayloadSize; - std::unique_ptr m_PathChallenge; + std::unique_ptr, boost::asio::ip::udp::endpoint> > m_PathChallenge; std::unordered_map m_ReceivedI2NPMsgIDs; // msgID -> timestamp in seconds uint64_t m_LastResendTime, m_LastResendAttemptTime; // in milliseconds int m_NumRanges; From c2f68d70216466af48d805ad2fc3416ca9ea01da Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 29 Mar 2025 21:34:16 -0400 Subject: [PATCH 753/787] send datetime and address blocks with path challenge --- libi2pd/SSU2Session.cpp | 42 +++++++++++++++++++++++++++-------------- libi2pd/SSU2Session.h | 2 +- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index dd170714..a4a9fa03 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2562,17 +2562,19 @@ namespace transport return nullptr; } - void SSU2Session::AdjustMaxPayloadSize () + void SSU2Session::AdjustMaxPayloadSize (size_t maxMtu) { auto addr = FindLocalAddress (); if (addr && addr->ssu) { int mtu = addr->ssu->mtu; if (!mtu && addr->IsV4 ()) mtu = SSU2_MAX_PACKET_SIZE; + if (mtu > (int)maxMtu) mtu = maxMtu; if (m_Address && m_Address->ssu && (!mtu || m_Address->ssu->mtu < mtu)) mtu = m_Address->ssu->mtu; if (mtu) { + if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE; if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE; m_MaxPayloadSize = mtu - (addr->IsV6 () ? IPV6_HEADER_SIZE: IPV4_HEADER_SIZE) - UDP_HEADER_SIZE - 32; LogPrint (eLogDebug, "SSU2: Session MTU=", mtu, ", max payload size=", m_MaxPayloadSize); @@ -3075,23 +3077,35 @@ namespace transport void SSU2Session::SendPathChallenge (const boost::asio::ip::udp::endpoint& to) { + AdjustMaxPayloadSize (SSU2_MIN_PACKET_SIZE); // reduce to minimum + m_WindowSize = SSU2_MIN_WINDOW_SIZE; // reduce window to minimum + uint8_t payload[SSU2_MAX_PACKET_SIZE]; - payload[0] = eSSU2BlkPathChallenge; - size_t len = m_Server.GetRng ()() % (m_MaxPayloadSize - 3); - htobe16buf (payload + 1, len); - if (len > 0) - { - m_PathChallenge = std::make_unique, boost::asio::ip::udp::endpoint> >(); - RAND_bytes (payload + 3, len); - SHA256 (payload + 3, len, m_PathChallenge->first); + size_t payloadSize = 0; + // datetime block + payload[0] = eSSU2BlkDateTime; + htobe16buf (payload + 1, 4); + htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); + payloadSize += 7; + // address block with new address + payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, to); + // path challenge block + payload[payloadSize] = eSSU2BlkPathChallenge; + size_t len = m_Server.GetRng ()() % (m_MaxPayloadSize - payloadSize - 3 - 8) + 8; // 8 bytes min + htobe16buf (payload + payloadSize + 1, len); + payloadSize += 3; + m_PathChallenge = std::make_unique, boost::asio::ip::udp::endpoint> >(); + RAND_bytes (payload + payloadSize, len); + SHA256 (payload + payloadSize, len, m_PathChallenge->first); m_PathChallenge->second = to; - } - len += 3; - if (len < m_MaxPayloadSize) - len += CreatePaddingBlock (payload + len, m_MaxPayloadSize - len, len < 8 ? 8 : 0); + payloadSize += len; + // padding block + if (payloadSize < m_MaxPayloadSize) + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); + // send to new endpoint auto existing = m_RemoteEndpoint; m_RemoteEndpoint = to; // send path challenge to new endpoint - SendData (payload, len); + SendData (payload, payloadSize); m_RemoteEndpoint = existing; // restore endpoint back until path response received } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 6d2bf103..7edc01a5 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -336,7 +336,7 @@ namespace transport virtual void HandleAddress (const uint8_t * buf, size_t len); size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); std::shared_ptr FindLocalAddress () const; - void AdjustMaxPayloadSize (); + void AdjustMaxPayloadSize (size_t maxMtu = SSU2_MAX_PACKET_SIZE); bool GetTestingState () const; void SetTestingState(bool testing) const; std::shared_ptr ExtractRouterInfo (const uint8_t * buf, size_t size); From 567183647e8dab9bde51b4a29ebb2432bf77d43e Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 30 Mar 2025 12:37:40 -0400 Subject: [PATCH 754/787] non-copyable RouterInfo --- libi2pd/RouterInfo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 387906ad..cb3ae499 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -210,8 +210,8 @@ namespace data typedef boost::shared_ptr AddressesPtr; #endif RouterInfo (const std::string& fullPath); - RouterInfo (const RouterInfo& ) = default; - RouterInfo& operator=(const RouterInfo& ) = default; + RouterInfo (const RouterInfo& ) = delete; + RouterInfo& operator=(const RouterInfo& ) = delete; RouterInfo (std::shared_ptr&& buf, size_t len); RouterInfo (const uint8_t * buf, size_t len); virtual ~RouterInfo (); From 00920a049d764db6d21459ad5b28f4bfc7866d85 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 30 Mar 2025 13:28:45 -0400 Subject: [PATCH 755/787] use g++-x86 for 32-bits platform --- Makefile.haiku | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile.haiku b/Makefile.haiku index 5dce7d7f..eb56a207 100644 --- a/Makefile.haiku +++ b/Makefile.haiku @@ -1,4 +1,8 @@ +ifeq ($(shell $(CXX) -dumpmachine | cut -c 1-4), i586) +CXX = g++-x86 +else CXX = g++ +endif CXXFLAGS := -Wall -std=c++20 INCFLAGS = -I/system/develop/headers DEFINES = -D_DEFAULT_SOURCE -D_GNU_SOURCE From ad3b999732ce9d70492d1980295eca300eb3ba65 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 31 Mar 2025 10:29:16 -0400 Subject: [PATCH 756/787] send path challenge of 8 bytes. add Ack block --- libi2pd/SSU2Session.cpp | 21 ++++++++++----------- libi2pd/SSU2Session.h | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index a4a9fa03..94a27877 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1660,9 +1660,7 @@ namespace transport LogPrint (eLogDebug, "SSU2: Path response"); if (m_PathChallenge) { - i2p::data::Tag<32> hash; - SHA256 (buf + offset, size, hash); - if (hash == m_PathChallenge->first) + if (buf64toh (buf + offset) == m_PathChallenge->first) { m_RemoteEndpoint = m_PathChallenge->second; m_PathChallenge.reset (nullptr); @@ -3091,14 +3089,15 @@ namespace transport payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, to); // path challenge block payload[payloadSize] = eSSU2BlkPathChallenge; - size_t len = m_Server.GetRng ()() % (m_MaxPayloadSize - payloadSize - 3 - 8) + 8; // 8 bytes min - htobe16buf (payload + payloadSize + 1, len); - payloadSize += 3; - m_PathChallenge = std::make_unique, boost::asio::ip::udp::endpoint> >(); - RAND_bytes (payload + payloadSize, len); - SHA256 (payload + payloadSize, len, m_PathChallenge->first); - m_PathChallenge->second = to; - payloadSize += len; + uint64_t challenge; + RAND_bytes ((uint8_t *)&challenge, 8); + htobe16buf (payload + payloadSize + 1, 8); // always 8 bytes + htobuf64 (payload + payloadSize + 3, challenge); + payloadSize += 11; + m_PathChallenge = std::make_unique >(challenge, to); + // ack block + if (payloadSize < m_MaxPayloadSize) + payloadSize += CreateAckBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); // padding block if (payloadSize < m_MaxPayloadSize) payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 7edc01a5..ee26255f 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -394,7 +394,7 @@ namespace transport boost::asio::deadline_timer m_ConnectTimer; SSU2TerminationReason m_TerminationReason; size_t m_MaxPayloadSize; - std::unique_ptr, boost::asio::ip::udp::endpoint> > m_PathChallenge; + std::unique_ptr > m_PathChallenge; std::unordered_map m_ReceivedI2NPMsgIDs; // msgID -> timestamp in seconds uint64_t m_LastResendTime, m_LastResendAttemptTime; // in milliseconds int m_NumRanges; From 2280338900695c84e192beb6f4dac5718e02f4aa Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 31 Mar 2025 15:50:16 -0400 Subject: [PATCH 757/787] datetime, address, ack blocks in path response packet --- libi2pd/SSU2Session.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 94a27877..cb10f848 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -3058,18 +3058,31 @@ namespace transport void SSU2Session::SendPathResponse (const uint8_t * data, size_t len) { - if (len > m_MaxPayloadSize - 3) + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + size_t payloadSize = 0; + // datetime block + payload[0] = eSSU2BlkDateTime; + htobe16buf (payload + 1, 4); + htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); + payloadSize += 7; + // address block + payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, m_RemoteEndpoint); + // path response + if (payloadSize + len > m_MaxPayloadSize) { LogPrint (eLogWarning, "SSU2: Incorrect data size for path response ", len); return; - } - uint8_t payload[SSU2_MAX_PACKET_SIZE]; - payload[0] = eSSU2BlkPathResponse; - htobe16buf (payload + 1, len); - memcpy (payload + 3, data, len); - size_t payloadSize = len + 3; + } + payload[payloadSize] = eSSU2BlkPathResponse; + htobe16buf (payload + payloadSize + 1, len); + memcpy (payload + payloadSize + 3, data, len); + payloadSize += len + 3; + // ack block if (payloadSize < m_MaxPayloadSize) - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, payloadSize < 8 ? 8 : 0); + payloadSize += CreateAckBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); + // padding + if (payloadSize < m_MaxPayloadSize) + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); } From 78d97179b8a994ae2509517840ccc70069f41584 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 1 Apr 2025 20:46:41 -0400 Subject: [PATCH 758/787] handle ML-KEM section for new session and create for new session reply --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 86 +++++++++++++++++++---- 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 865fc973..82be0ebd 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -257,27 +257,66 @@ namespace garlic if (!GetOwner ()) return false; // we are Bob // KDF1 - i2p::crypto::InitNoiseIKState (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk - + if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk)) { LogPrint (eLogError, "Garlic: Can't decode elligator"); return false; } buf += 32; len -= 32; - MixHash (m_Aepk, 32); // h = SHA256(h || aepk) + uint64_t n = 0; uint8_t sharedSecret[32]; - if (!GetOwner ()->Decrypt (m_Aepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk) + bool decrypted = false; +#if OPENSSL_PQ + if (GetOwner ()->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)) { - LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key"); - return false; - } - MixKey (sharedSecret); + i2p::crypto::InitNoiseIKStateMLKEM512 (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)); // bpk + MixHash (m_Aepk, 32); // h = SHA256(h || aepk) + + if (GetOwner ()->Decrypt (m_Aepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk) + { + MixKey (sharedSecret); + + uint8_t nonce[12], encapsKey[i2p::crypto::MLKEM512_KEY_LENGTH]; + CreateNonce (n, nonce); + if (i2p::crypto::AEADChaCha20Poly1305 (buf, i2p::crypto::MLKEM512_KEY_LENGTH, + m_H, 32, m_CK + 32, nonce, encapsKey, i2p::crypto::MLKEM512_KEY_LENGTH , false)) // decrypt + { + decrypted = true; // encaps section has right hash + MixHash (buf, i2p::crypto::MLKEM512_KEY_LENGTH); + n++; + + m_PQKeys = std::make_unique(); + m_PQKeys->SetPublicKey (encapsKey); + } + } + } +#endif + if (!decrypted) + { + if (GetOwner ()->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) + { + i2p::crypto::InitNoiseIKState (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk + MixHash (m_Aepk, 32); // h = SHA256(h || aepk) + + if (!GetOwner ()->Decrypt (m_Aepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk) + { + LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key"); + return false; + } + MixKey (sharedSecret); + } + else + { + LogPrint (eLogWarning, "Garlic: No supported encryption type"); + return false; + } + } // decrypt flags/static uint8_t nonce[12], fs[32]; - CreateNonce (0, nonce); + CreateNonce (n, nonce); if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 32, m_H, 32, m_CK + 32, nonce, fs, 32, false)) // decrypt { LogPrint (eLogWarning, "Garlic: Flags/static section AEAD verification failed "); @@ -291,8 +330,13 @@ namespace garlic if (isStatic) { // static key, fs is apk - SetRemoteStaticKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD, fs); // TODO: actual key type - if (!GetOwner ()->Decrypt (fs, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, apk) +#if OPENSSL_PQ + if (m_PQKeys) + SetRemoteStaticKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD, fs); + else +#endif + SetRemoteStaticKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD, fs); + if (!GetOwner ()->Decrypt (fs, sharedSecret, m_RemoteStaticKeyType)) // x25519(bsk, apk) { LogPrint (eLogWarning, "Garlic: Incorrect Alice static key"); return false; @@ -596,7 +640,7 @@ namespace garlic } memcpy (m_NSREncodedKey, out + offset, 32); // for possible next NSR memcpy (m_NSRH, m_H, 32); - offset += 32; + offset += 32; // KDF for Reply Key Section MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag) MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || bepk) @@ -613,8 +657,26 @@ namespace garlic return false; } MixKey (sharedSecret); + uint8_t nonce[12]; CreateNonce (0, nonce); +#if OPENSSL_PQ + if (m_PQKeys) + { + uint8_t kemCiphertext[i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH]; + m_PQKeys->Encaps (kemCiphertext, sharedSecret); + + if (!i2p::crypto::AEADChaCha20Poly1305 (kemCiphertext, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH, + m_H, 32, m_CK + 32, nonce, out + offset, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16, true)) // encrypt + { + LogPrint (eLogWarning, "Garlic: NSR ML-KEM ciphertext section AEAD encryption failed"); + return false; + } + MixHash (out + offset, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16); + MixKey (sharedSecret); + offset += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; + } +#endif // calculate hash for zero length if (!i2p::crypto::AEADChaCha20Poly1305 (nonce /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + offset, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) { From 3be4c7217f29bf837e0591cb1435f856e3f7a0d1 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 3 Apr 2025 18:42:34 -0400 Subject: [PATCH 759/787] move buffer when insert to buffer queue. clean entire queue in one call --- libi2pd/Streaming.cpp | 58 ++++++++++++++++++++++++++--------------- libi2pd/Streaming.h | 4 +-- libi2pd_client/I2CP.cpp | 4 +-- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 0ed6067c..d21cfa62 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2024, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -19,39 +19,55 @@ namespace i2p { namespace stream { - void SendBufferQueue::Add (std::shared_ptr buf) + void SendBufferQueue::Add (std::shared_ptr&& buf) { if (buf) { - m_Buffers.push_back (buf); m_Size += buf->len; + m_Buffers.push_back (std::move (buf)); } } size_t SendBufferQueue::Get (uint8_t * buf, size_t len) { + if (!m_Size) return 0; size_t offset = 0; - while (!m_Buffers.empty () && offset < len) + if (len >= m_Size) { - auto nextBuffer = m_Buffers.front (); - auto rem = nextBuffer->GetRemainingSize (); - if (offset + rem <= len) + for (auto& it: m_Buffers) { - // whole buffer - memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), rem); + auto rem = it->GetRemainingSize (); + memcpy (buf + offset, it->GetRemaningBuffer (), rem); offset += rem; - m_Buffers.pop_front (); // delete it } - else + m_Buffers.clear (); + m_Size = 0; + return offset; + } + else + { + while (!m_Buffers.empty () && offset < len) { - // partially - rem = len - offset; - memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), rem); - nextBuffer->offset += rem; - offset = len; // break + auto nextBuffer = m_Buffers.front (); + auto rem = nextBuffer->GetRemainingSize (); + if (offset + rem <= len) + { + // whole buffer + memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), rem); + offset += rem; + m_Buffers.pop_front (); // delete it + } + else + { + // partially + rem = len - offset; + memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), rem); + nextBuffer->offset += rem; + offset = len; // break + } } - } - m_Size -= offset; + m_Size -= offset; + } return offset; } @@ -59,7 +75,7 @@ namespace stream { if (!m_Buffers.empty ()) { - for (auto it: m_Buffers) + for (auto& it: m_Buffers) it->Cancel (); m_Buffers.clear (); m_Size = 0; @@ -717,10 +733,10 @@ namespace stream else if (handler) handler(boost::system::error_code ()); auto s = shared_from_this (); - boost::asio::post (m_Service, [s, buffer]() + boost::asio::post (m_Service, [s, buffer = std::move(buffer)]() mutable { if (buffer) - s->m_SendBuffer.Add (buffer); + s->m_SendBuffer.Add (std::move(buffer)); s->SendBuffer (); }); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index d75cb6eb..8280477b 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2024, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -150,7 +150,7 @@ namespace stream SendBufferQueue (): m_Size (0) {}; ~SendBufferQueue () { CleanUp (); }; - void Add (std::shared_ptr buf); + void Add (std::shared_ptr&& buf); size_t Get (uint8_t * buf, size_t len); size_t GetSize () const { return m_Size; }; bool IsEmpty () const { return m_Buffers.empty (); }; diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 09fcee71..11278e7a 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -533,7 +533,7 @@ namespace client if (sendBuf) { if (m_SendQueue.GetSize () < I2CP_MAX_SEND_QUEUE_SIZE) - m_SendQueue.Add (sendBuf); + m_SendQueue.Add (std::move(sendBuf)); else { LogPrint (eLogWarning, "I2CP: Send queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); @@ -1079,7 +1079,7 @@ namespace client if (sendBuf) { if (m_SendQueue.GetSize () < I2CP_MAX_SEND_QUEUE_SIZE) - m_SendQueue.Add (sendBuf); + m_SendQueue.Add (std::move(sendBuf)); else { LogPrint (eLogWarning, "I2CP: Send queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); From 8ca74a3e1d9ccd8b835d565fdb6383f0fd4b7840 Mon Sep 17 00:00:00 2001 From: Alexey Chernov Date: Fri, 4 Apr 2025 22:35:56 +0300 Subject: [PATCH 760/787] [systemd] Wait for network-online target when starting service (#2169) --- contrib/i2pd.service | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/i2pd.service b/contrib/i2pd.service index 381ae483..1ab46979 100644 --- a/contrib/i2pd.service +++ b/contrib/i2pd.service @@ -1,7 +1,8 @@ [Unit] Description=I2P Router written in C++ Documentation=man:i2pd(1) https://i2pd.readthedocs.io/en/latest/ -After=network.target +Wants=network.target +After=network.target network-online.target [Service] User=i2pd From bce0ccf161124b752d434bd58b0c3cc7bdc1818a Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 4 Apr 2025 19:52:32 -0400 Subject: [PATCH 761/787] all ratchets types are eligible for ECIESx25519 --- libi2pd/Destination.cpp | 6 ++++++ libi2pd/Destination.h | 2 ++ libi2pd/Garlic.cpp | 4 ++-- libi2pd/Garlic.h | 2 ++ libi2pd_client/I2CP.h | 2 ++ 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index e20249c5..a3f6a8c9 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1533,6 +1533,12 @@ namespace client #endif } + bool ClientDestination::SupportsRatchets () const + { + if (m_EncryptionKeys.empty ()) return false; + return m_EncryptionKeys.rbegin ()->first >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; + } + const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const { auto it = m_EncryptionKeys.find (keyType); diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 802d7780..a76a1be4 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -296,6 +296,8 @@ namespace client protected: + // GarlicDestionation + bool SupportsRatchets () const override; // LeaseSetDestination void CleanupDestination () override; i2p::data::CryptoKeyType GetPreferredCryptoType () const override { return m_PreferredCryptoType; } diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 0098bdcd..5a3e4cae 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -498,7 +498,7 @@ namespace garlic buf += 4; // length bool found = false; - if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) + if (SupportsRatchets ()) // try ECIESx25519 tag found = HandleECIESx25519TagMessage (buf, length); if (!found) @@ -535,7 +535,7 @@ namespace garlic decryption->Decrypt(buf + 514, length - 514, iv, buf + 514); HandleAESBlock (buf + 514, length - 514, decryption, msg->from); } - else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) + else if (SupportsRatchets ()) { // otherwise ECIESx25519 auto ts = i2p::util::GetMillisecondsSinceEpoch (); diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 6283d740..0eef4871 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -279,6 +279,8 @@ namespace garlic void SaveTags (); void LoadTags (); + virtual bool SupportsRatchets () const { return GetIdentity ()->GetCryptoKeyType () >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; } + private: void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr decryption, diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 3a9a7e7f..84243e6f 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -108,6 +108,8 @@ namespace client protected: + // GarlicDestination + bool SupportsRatchets () const override { return (bool)m_ECIESx25519Decryptor; } // LeaseSetDestination void CleanupDestination () override; i2p::data::CryptoKeyType GetPreferredCryptoType () const override; From 2f2ecc32d2ce31530f98a450e869174b8d13d6cf Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 5 Apr 2025 18:12:38 -0400 Subject: [PATCH 762/787] correct key type and message size for ML-KEM-512 --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 31 +++++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 82be0ebd..5e7faefe 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -274,22 +274,24 @@ namespace garlic i2p::crypto::InitNoiseIKStateMLKEM512 (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)); // bpk MixHash (m_Aepk, 32); // h = SHA256(h || aepk) - if (GetOwner ()->Decrypt (m_Aepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk) + if (GetOwner ()->Decrypt (m_Aepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)) // x25519(bsk, aepk) { MixKey (sharedSecret); uint8_t nonce[12], encapsKey[i2p::crypto::MLKEM512_KEY_LENGTH]; CreateNonce (n, nonce); if (i2p::crypto::AEADChaCha20Poly1305 (buf, i2p::crypto::MLKEM512_KEY_LENGTH, - m_H, 32, m_CK + 32, nonce, encapsKey, i2p::crypto::MLKEM512_KEY_LENGTH , false)) // decrypt + m_H, 32, m_CK + 32, nonce, encapsKey, i2p::crypto::MLKEM512_KEY_LENGTH, false)) // decrypt { decrypted = true; // encaps section has right hash - MixHash (buf, i2p::crypto::MLKEM512_KEY_LENGTH); + MixHash (buf, i2p::crypto::MLKEM512_KEY_LENGTH + 16); + buf += i2p::crypto::MLKEM512_KEY_LENGTH + 16; + len -= i2p::crypto::MLKEM512_KEY_LENGTH + 16; n++; m_PQKeys = std::make_unique(); m_PQKeys->SetPublicKey (encapsKey); - } + } } } #endif @@ -579,7 +581,7 @@ namespace garlic CreateNonce (n, nonce); const uint8_t * fs; if (isStatic) - fs = GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); + fs = GetOwner ()->GetEncryptionPublicKey (m_RemoteStaticKeyType); else { memset (out + offset, 0, 32); // all zeros flags section @@ -596,7 +598,7 @@ namespace garlic // KDF2 if (isStatic) { - GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bpk) + GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, m_RemoteStaticKeyType); // x25519 (ask, bpk) MixKey (sharedSecret); } else @@ -665,7 +667,7 @@ namespace garlic { uint8_t kemCiphertext[i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH]; m_PQKeys->Encaps (kemCiphertext, sharedSecret); - + if (!i2p::crypto::AEADChaCha20Poly1305 (kemCiphertext, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH, m_H, 32, m_CK + 32, nonce, out + offset, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16, true)) // encrypt { @@ -761,7 +763,7 @@ namespace garlic return false; } MixKey (sharedSecret); - GetOwner ()->Decrypt (bepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bepk) + GetOwner ()->Decrypt (bepk, sharedSecret, m_RemoteStaticKeyType); // x25519 (ask, bepk) MixKey (sharedSecret); uint8_t nonce[12]; @@ -779,6 +781,7 @@ namespace garlic } MixHash (buf, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16); buf += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; + len -= i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; // decaps m_PQKeys->Decaps (kemCiphertext, sharedSecret); MixKey (sharedSecret); @@ -945,7 +948,11 @@ namespace garlic if (!payload) return nullptr; size_t len = CreatePayload (msg, m_State != eSessionStateEstablished, payload); if (!len) return nullptr; +#if OPENSSL_PQ + auto m = NewI2NPMessage (len + (m_State == eSessionStateEstablished ? 28 : i2p::crypto::MLKEM512_KEY_LENGTH + 116)); +#else auto m = NewI2NPMessage (len + 100); // 96 + 4 +#endif m->Align (12); // in order to get buf aligned to 16 (12 + 4) uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length @@ -960,11 +967,19 @@ namespace garlic if (!NewOutgoingSessionMessage (payload, len, buf, m->maxLen)) return nullptr; len += 96; +#if OPENSSL_PQ + if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) + len += i2p::crypto::MLKEM512_KEY_LENGTH + 16; +#endif break; case eSessionStateNewSessionReceived: if (!NewSessionReplyMessage (payload, len, buf, m->maxLen)) return nullptr; len += 72; +#if OPENSSL_PQ + if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) + len += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; +#endif break; case eSessionStateNewSessionReplySent: if (!NextNewSessionReplyMessage (payload, len, buf, m->maxLen)) From 3afe6455b285329198805a47e8f79d407f402415 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 6 Apr 2025 15:34:01 -0400 Subject: [PATCH 763/787] reset nonce to 0 before payload encrypt/decrypt for ML-KEM-512 --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 5e7faefe..37481d96 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -334,7 +334,10 @@ namespace garlic // static key, fs is apk #if OPENSSL_PQ if (m_PQKeys) + { SetRemoteStaticKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD, fs); + CreateNonce (0, nonce); // reset nonce + } else #endif SetRemoteStaticKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD, fs); @@ -600,6 +603,10 @@ namespace garlic { GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, m_RemoteStaticKeyType); // x25519 (ask, bpk) MixKey (sharedSecret); +#if OPENSSL_PQ + if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) + CreateNonce (0, nonce); // reset nonce +#endif } else CreateNonce (1, nonce); From 6b38085f277b6625c5d1ee470e603db2e475f961 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 7 Apr 2025 18:47:53 -0400 Subject: [PATCH 764/787] Noise state Encrypt/Decrypt operations --- libi2pd/Crypto.cpp | 59 +++++++++++++++++------ libi2pd/Crypto.h | 6 +++ libi2pd/ECIESX25519AEADRatchetSession.cpp | 53 ++++++++------------ 3 files changed, 72 insertions(+), 46 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 9bdfe43f..e8210a27 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -821,6 +821,18 @@ namespace crypto // Noise + void NoiseSymmetricState::Init (const uint8_t * ck, const uint8_t * hh, const uint8_t * pub) + { + // pub is Bob's public static key, hh = SHA256(h) + memcpy (m_CK, ck, 32); + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, hh, 32); + SHA256_Update (&ctx, pub, 32); + SHA256_Final (m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub) + m_N = 0; + } + void NoiseSymmetricState::MixHash (const uint8_t * buf, size_t len) { SHA256_CTX ctx; @@ -844,20 +856,39 @@ namespace crypto { HKDF (m_CK, sharedSecret, 32, "", m_CK); // new ck is m_CK[0:31], key is m_CK[32:63] + m_N = 0; } - static void InitNoiseState (NoiseSymmetricState& state, const uint8_t * ck, - const uint8_t * hh, const uint8_t * pub) + bool NoiseSymmetricState::Encrypt (const uint8_t * in, uint8_t * out, size_t len) { - // pub is Bob's public static key, hh = SHA256(h) - memcpy (state.m_CK, ck, 32); - SHA256_CTX ctx; - SHA256_Init (&ctx); - SHA256_Update (&ctx, hh, 32); - SHA256_Update (&ctx, pub, 32); - SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub) + uint8_t nonce[12]; + if (m_N) + { + memset (nonce, 0, 4); + htole64buf (nonce + 4, m_N); + } + else + memset (nonce, 0, 12); + auto ret = AEADChaCha20Poly1305 (in, len, m_H, 32, m_CK + 32, nonce, out, len + 16, true); + if (ret) m_N++; + return ret; } + bool NoiseSymmetricState::Decrypt (const uint8_t * in, uint8_t * out, size_t len) + { + uint8_t nonce[12]; + if (m_N) + { + memset (nonce, 0, 4); + htole64buf (nonce + 4, m_N); + } + else + memset (nonce, 0, 12); + auto ret = AEADChaCha20Poly1305 (in, len, m_H, 32, m_CK + 32, nonce, out, len, false); + if (ret) m_N++; + return ret; + } + void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub) { static constexpr char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars @@ -866,7 +897,7 @@ namespace crypto 0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1, 0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54 }; // hh = SHA256(protocol_name || 0) - InitNoiseState (state, (const uint8_t *)protocolName, hh, pub); // ck = protocol_name || 0 + state.Init ((const uint8_t *)protocolName, hh, pub); // ck = protocol_name || 0 } void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub) @@ -881,7 +912,7 @@ namespace crypto 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e }; // SHA256 (protocolNameHash) - InitNoiseState (state, protocolNameHash, hh, pub); + state.Init (protocolNameHash, hh, pub); } void InitNoiseXKState1 (NoiseSymmetricState& state, const uint8_t * pub) @@ -896,7 +927,7 @@ namespace crypto 0xdc, 0x85, 0xe6, 0xaf, 0x7b, 0x02, 0x65, 0x0c, 0xf1, 0xf9, 0x0d, 0x71, 0xfb, 0xc6, 0xd4, 0x53, 0xa7, 0xcf, 0x6d, 0xbf, 0xbd, 0x52, 0x5e, 0xa5, 0xb5, 0x79, 0x1c, 0x47, 0xb3, 0x5e, 0xbc, 0x33 }; // SHA256 (protocolNameHash) - InitNoiseState (state, protocolNameHash, hh, pub); + state.Init (protocolNameHash, hh, pub); } void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub) @@ -911,7 +942,7 @@ namespace crypto 0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32, 0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c }; // SHA256 (protocolNameHash) - InitNoiseState (state, protocolNameHash, hh, pub); + state.Init (protocolNameHash, hh, pub); } void InitNoiseIKStateMLKEM512 (NoiseSymmetricState& state, const uint8_t * pub) @@ -926,7 +957,7 @@ namespace crypto 0x95, 0x8d, 0xf6, 0x6c, 0x95, 0xce, 0xa9, 0xf7, 0x42, 0xfc, 0xfa, 0x62, 0x71, 0x36, 0x1e, 0xa7, 0xdc, 0x7a, 0xc0, 0x75, 0x01, 0xcf, 0xf9, 0xfc, 0x9f, 0xdb, 0x4c, 0x68, 0x3a, 0x53, 0x49, 0xeb }; // SHA256 (protocolNameHash) - InitNoiseState (state, protocolNameHash, hh, pub); + state.Init (protocolNameHash, hh, pub); } // init and terminate diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index dcdc27d3..aa6466be 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -255,10 +255,16 @@ namespace crypto struct NoiseSymmetricState { uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/; + uint64_t m_N; + void Init (const uint8_t * ck, const uint8_t * hh, const uint8_t * pub); + void MixHash (const uint8_t * buf, size_t len); void MixHash (const std::vector >& bufs); void MixKey (const uint8_t * sharedSecret); + + bool Encrypt (const uint8_t * in, uint8_t * out, size_t len); // out length = len + 16 + bool Decrypt (const uint8_t * in, uint8_t * out, size_t len); // len without 16 bytes tag }; void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_N (tunnels, router) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 37481d96..467a3752 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -559,29 +559,22 @@ namespace garlic return false; } MixKey (sharedSecret); - uint64_t n = 0; // seqn #if OPENSSL_PQ if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) { uint8_t encapsKey[i2p::crypto::MLKEM512_KEY_LENGTH]; m_PQKeys->GetPublicKey (encapsKey); // encrypt encapsKey - uint8_t nonce[12]; - CreateNonce (n, nonce); - if (!i2p::crypto::AEADChaCha20Poly1305 (encapsKey, i2p::crypto::MLKEM512_KEY_LENGTH, - m_H, 32, m_CK + 32, nonce, out + offset, i2p::crypto::MLKEM512_KEY_LENGTH + 16, true)) // encrypt + if (!Encrypt (encapsKey, out + offset, i2p::crypto::MLKEM512_KEY_LENGTH)) { LogPrint (eLogWarning, "Garlic: ML-KEM encap_key section AEAD encryption failed "); return false; } MixHash (out + offset, i2p::crypto::MLKEM512_KEY_LENGTH + 16); // h = SHA256(h || ciphertext) offset += i2p::crypto::MLKEM512_KEY_LENGTH + 16; - n++; } #endif // encrypt flags/static key section - uint8_t nonce[12]; - CreateNonce (n, nonce); const uint8_t * fs; if (isStatic) fs = GetOwner ()->GetEncryptionPublicKey (m_RemoteStaticKeyType); @@ -590,7 +583,7 @@ namespace garlic memset (out + offset, 0, 32); // all zeros flags section fs = out + offset; } - if (!i2p::crypto::AEADChaCha20Poly1305 (fs, 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt + if (!Encrypt (fs, out + offset, 32)) { LogPrint (eLogWarning, "Garlic: Flags/static section AEAD encryption failed "); return false; @@ -602,16 +595,10 @@ namespace garlic if (isStatic) { GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, m_RemoteStaticKeyType); // x25519 (ask, bpk) - MixKey (sharedSecret); -#if OPENSSL_PQ - if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) - CreateNonce (0, nonce); // reset nonce -#endif + MixKey (sharedSecret); } - else - CreateNonce (1, nonce); // encrypt payload - if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_CK + 32, nonce, out + offset, len + 16, true)) // encrypt + if (!Encrypt (payload, out + offset, len)) { LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); return false; @@ -667,16 +654,13 @@ namespace garlic } MixKey (sharedSecret); - uint8_t nonce[12]; - CreateNonce (0, nonce); #if OPENSSL_PQ if (m_PQKeys) { uint8_t kemCiphertext[i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH]; m_PQKeys->Encaps (kemCiphertext, sharedSecret); - if (!i2p::crypto::AEADChaCha20Poly1305 (kemCiphertext, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH, - m_H, 32, m_CK + 32, nonce, out + offset, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16, true)) // encrypt + if (!Encrypt (kemCiphertext, out + offset, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH)) { LogPrint (eLogWarning, "Garlic: NSR ML-KEM ciphertext section AEAD encryption failed"); return false; @@ -687,7 +671,7 @@ namespace garlic } #endif // calculate hash for zero length - if (!i2p::crypto::AEADChaCha20Poly1305 (nonce /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + offset, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) + if (!Encrypt (sharedSecret /* can be anything */, out + offset, 0)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) { LogPrint (eLogWarning, "Garlic: Reply key section AEAD encryption failed"); return false; @@ -708,6 +692,7 @@ namespace garlic GetOwner ()->GetNumRatchetInboundTags () : ECIESX25519_MIN_NUM_GENERATED_TAGS); i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", m_NSRKey, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) // encrypt payload + uint8_t nonce[12]; memset (nonce, 0, 12); // seqn = 0 if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + offset, len + 16, true)) // encrypt { LogPrint (eLogWarning, "Garlic: NSR payload section AEAD encryption failed"); @@ -729,16 +714,22 @@ namespace garlic memcpy (m_H, m_NSRH, 32); MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag) MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || bepk) - uint8_t nonce[12]; - CreateNonce (0, nonce); - if (!i2p::crypto::AEADChaCha20Poly1305 (nonce /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + 40, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) + m_N = 0; + size_t offset = 40; +#if OPENSSL_PQ + if (m_PQKeys) + // TODO: encrypted ML-KEM section + offset += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; +#endif + if (!Encrypt (m_NSRH /* can be anything */, out + offset, 0)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) { LogPrint (eLogWarning, "Garlic: Reply key section AEAD encryption failed"); return false; } - MixHash (out + 40, 16); // h = SHA256(h || ciphertext) + MixHash (out + offset, 16); // h = SHA256(h || ciphertext) // encrypt payload - if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + 56, len + 16, true)) // encrypt + uint8_t nonce[12]; memset (nonce, 0, 12); + if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + offset + 16, len + 16, true)) // encrypt { LogPrint (eLogWarning, "Garlic: Next NSR payload section AEAD encryption failed"); return false; @@ -773,15 +764,12 @@ namespace garlic GetOwner ()->Decrypt (bepk, sharedSecret, m_RemoteStaticKeyType); // x25519 (ask, bepk) MixKey (sharedSecret); - uint8_t nonce[12]; - CreateNonce (0, nonce); #if OPENSSL_PQ if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) { // decrypt kem_ciphertext section uint8_t kemCiphertext[i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH]; - if (!i2p::crypto::AEADChaCha20Poly1305 (buf, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH, - m_H, 32, m_CK + 32, nonce, kemCiphertext, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH, false)) // decrypt, DECRYPT(k, n, ZEROLEN, ad) verification only + if (!Decrypt (buf, kemCiphertext, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH)) { LogPrint (eLogWarning, "Garlic: Reply ML-KEM ciphertext section AEAD decryption failed"); return false; @@ -795,7 +783,7 @@ namespace garlic } #endif // calculate hash for zero length - if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 0, m_H, 32, m_CK + 32, nonce, sharedSecret/* can be anything */, 0, false)) // decrypt, DECRYPT(k, n, ZEROLEN, ad) verification only + if (!Decrypt (buf, sharedSecret/* can be anything */, 0)) // decrypt, DECRYPT(k, n, ZEROLEN, ad) verification only { LogPrint (eLogWarning, "Garlic: Reply key section AEAD decryption failed"); return false; @@ -820,6 +808,7 @@ namespace garlic } i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) // decrypt payload + uint8_t nonce[12]; memset (nonce, 0, 12); // seqn = 0 if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, keydata, nonce, buf, len - 16, false)) // decrypt { LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed"); From 711f5bcc6210bf2806ae477739d771303dcd6e65 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 7 Apr 2025 20:33:19 -0400 Subject: [PATCH 765/787] store ML-KEM section for possible next NSR --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 21 +++++++++++++++++++-- libi2pd/ECIESX25519AEADRatchetSession.h | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 467a3752..cfcbf5bb 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -665,6 +665,8 @@ namespace garlic LogPrint (eLogWarning, "Garlic: NSR ML-KEM ciphertext section AEAD encryption failed"); return false; } + m_NSREncodedPQKey = std::make_unique >(); + memcpy (m_NSREncodedPQKey->data (), out + offset, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16); MixHash (out + offset, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16); MixKey (sharedSecret); offset += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; @@ -718,8 +720,19 @@ namespace garlic size_t offset = 40; #if OPENSSL_PQ if (m_PQKeys) - // TODO: encrypted ML-KEM section - offset += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; + { + if (m_NSREncodedPQKey) + { + memcpy (out + offset, m_NSREncodedPQKey->data (), i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16); + MixHash (out + offset, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16); + offset += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; + } + else + { + LogPrint (eLogWarning, "Garlic: No stored ML-KEM keys"); + return false; + } + } #endif if (!Encrypt (m_NSRH /* can be anything */, out + offset, 0)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) { @@ -914,6 +927,10 @@ namespace garlic m_State = eSessionStateEstablished; m_NSRSendTagset = nullptr; m_EphemeralKeys = nullptr; +#if OPENSSL_PQ + m_PQKeys = nullptr; + m_NSREncodedPQKey = nullptr; +#endif [[fallthrough]]; case eSessionStateEstablished: if (m_SendReverseKey && receiveTagset->GetTagSetID () == m_NextReceiveRatchet->GetReceiveTagSetID ()) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index cd32cb98..b988263a 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include "Identity.h" @@ -228,6 +229,7 @@ namespace garlic std::shared_ptr m_EphemeralKeys; #if OPENSSL_PQ std::unique_ptr m_PQKeys; + std::unique_ptr > m_NSREncodedPQKey; #endif SessionState m_State = eSessionStateNew; uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0, // incoming (in seconds) From f6abbe59086ed2ca8b32fe63e6f120c4c0258d86 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 8 Apr 2025 14:39:46 -0400 Subject: [PATCH 766/787] Use noise state Encrypt/Decrypt operations --- libi2pd/NTCP2.cpp | 81 ++++++++++++++++++++++++++--------------------- libi2pd/NTCP2.h | 9 +++--- 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 870fcc19..b3a51488 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -145,10 +145,12 @@ namespace transport // 2 bytes reserved htobe32buf (options + 8, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); // tsA, rounded to seconds // 4 bytes reserved - // sign and encrypt options, use m_H as AD - 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 + // encrypt options + if (!Encrypt (options, m_SessionRequestBuffer + 32, 16)) + { + LogPrint (eLogWarning, "NTCP2: SessionRequest failed to encrypt options"); + return false; + } return true; } @@ -167,14 +169,16 @@ namespace transport memset (options, 0, 16); htobe16buf (options + 2, paddingLen); // padLen htobe32buf (options + 8, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); // tsB, rounded to seconds - // sign and encrypt options, use m_H as AD - 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 + // encrypt options + if (!Encrypt (options, m_SessionCreatedBuffer + 32, 16)) + { + LogPrint (eLogWarning, "NTCP2: SessionCreated failed to encrypt options"); + return false; + } return true; } - void NTCP2Establisher::CreateSessionConfirmedMessagePart1 (const uint8_t * nonce) + bool NTCP2Establisher::CreateSessionConfirmedMessagePart1 () { // update AD MixHash (m_SessionCreatedBuffer + 32, 32); // encrypted payload @@ -182,19 +186,28 @@ namespace transport if (paddingLength > 0) MixHash (m_SessionCreatedBuffer + 64, paddingLength); - // part1 48 bytes - i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, GetH (), 32, GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + // part1 48 bytes, n = 1 + if (!Encrypt (i2p::context.GetNTCP2StaticPublicKey (), m_SessionConfirmedBuffer, 32)) + { + LogPrint (eLogWarning, "NTCP2: SessionConfirmed failed to encrypt part1"); + return false; + } + return true; } - bool NTCP2Establisher::CreateSessionConfirmedMessagePart2 (const uint8_t * nonce) + bool NTCP2Establisher::CreateSessionConfirmedMessagePart2 () { // part 2 // update AD again MixHash (m_SessionConfirmedBuffer, 48); // encrypt m3p2, it must be filled in SessionRequest - if (!KDF3Alice ()) return false; + if (!KDF3Alice ()) return false; // MixKey, n = 0 uint8_t * m3p2 = m_SessionConfirmedBuffer + 48; - i2p::crypto::AEADChaCha20Poly1305 (m3p2, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2, m3p2Len, true); // encrypt + if (!Encrypt (m3p2, m3p2, m3p2Len - 16)) + { + LogPrint (eLogWarning, "NTCP2: SessionConfirmed failed to encrypt part2"); + return false; + } // update h again MixHash (m3p2, m3p2Len); //h = SHA256(h || ciphertext) return true; @@ -214,10 +227,9 @@ namespace transport 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 - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, GetH (), 32, GetK (), nonce, options, 16, false)) // decrypt + // verify MAC and decrypt options block (32 bytes) + uint8_t options[16]; + if (Decrypt (m_SessionRequestBuffer + 32, options, 16)) { // options if (options[0] && options[0] != i2p::context.GetNetID ()) @@ -274,9 +286,7 @@ namespace transport } // decrypt and verify MAC uint8_t payload[16]; - uint8_t nonce[12]; - memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, GetH (), 32, GetK (), nonce, payload, 16, false)) // decrypt + if (Decrypt (m_SessionCreatedBuffer + 32, payload, 16)) { // options paddingLen = bufbe16toh(payload + 2); @@ -297,7 +307,7 @@ namespace transport return true; } - bool NTCP2Establisher::ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce) + bool NTCP2Establisher::ProcessSessionConfirmedMessagePart1 () { // update AD MixHash (m_SessionCreatedBuffer + 32, 32); // encrypted payload @@ -305,7 +315,8 @@ namespace transport if (paddingLength > 0) MixHash (m_SessionCreatedBuffer + 64, paddingLength); - if (!i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, GetH (), 32, GetK (), nonce, m_RemoteStaticKey, 32, false)) // decrypt S + // decrypt S, n = 1 + if (!Decrypt (m_SessionConfirmedBuffer, m_RemoteStaticKey, 32)) { LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed "); return false; @@ -313,17 +324,17 @@ namespace transport return true; } - bool NTCP2Establisher::ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf) + bool NTCP2Establisher::ProcessSessionConfirmedMessagePart2 (uint8_t * m3p2Buf) { // update AD again MixHash (m_SessionConfirmedBuffer, 48); - if (!KDF3Bob ()) + if (!KDF3Bob ()) // MixKey, n = 0 { 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 (Decrypt (m_SessionConfirmedBuffer + 48, m3p2Buf, m3p2Len - 16)) // calculate new h again for KDF data MixHash (m_SessionConfirmedBuffer + 48, m3p2Len); // h = SHA256(h || ciphertext) else @@ -657,11 +668,12 @@ namespace transport void NTCP2Session::SendSessionConfirmed () { - uint8_t nonce[12]; - CreateNonce (1, nonce); // set nonce to 1 - m_Establisher->CreateSessionConfirmedMessagePart1 (nonce); - memset (nonce, 0, 12); // set nonce back to 0 - if (!m_Establisher->CreateSessionConfirmedMessagePart2 (nonce)) + if (!m_Establisher->CreateSessionConfirmedMessagePart1 ()) + { + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + return; + } + if (!m_Establisher->CreateSessionConfirmedMessagePart2 ()) { LogPrint (eLogWarning, "NTCP2: Send SessionConfirmed Part2 KDF failed"); boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); @@ -740,14 +752,11 @@ namespace transport // run on establisher thread LogPrint (eLogDebug, "NTCP2: SessionConfirmed received"); // part 1 - uint8_t nonce[12]; - CreateNonce (1, nonce); - if (m_Establisher->ProcessSessionConfirmedMessagePart1 (nonce)) + if (m_Establisher->ProcessSessionConfirmedMessagePart1 ()) { // part 2 auto buf = std::make_shared > (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 + if (m_Establisher->ProcessSessionConfirmedMessagePart2 (buf->data ())) // TODO:handle in establisher thread { // payload // RI block must be first diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 47354f32..5ad5b955 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -91,7 +91,6 @@ namespace transport const uint8_t * GetRemotePub () const { return m_RemoteEphemeralPublicKey; }; // Y for Alice and X for Bob uint8_t * GetRemotePub () { return m_RemoteEphemeralPublicKey; }; // to set - const uint8_t * GetK () const { return m_CK + 32; }; const uint8_t * GetCK () const { return m_CK; }; const uint8_t * GetH () const { return m_H; }; @@ -108,13 +107,13 @@ namespace transport bool CreateSessionRequestMessage (std::mt19937& rng); bool CreateSessionCreatedMessage (std::mt19937& rng); - void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce); - bool CreateSessionConfirmedMessagePart2 (const uint8_t * nonce); + bool CreateSessionConfirmedMessagePart1 (); + bool CreateSessionConfirmedMessagePart2 (); bool ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew); bool ProcessSessionCreatedMessage (uint16_t& paddingLen); - bool ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce); - bool ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf); + bool ProcessSessionConfirmedMessagePart1 (); + bool ProcessSessionConfirmedMessagePart2 (uint8_t * m3p2Buf); std::shared_ptr m_EphemeralKeys; uint8_t m_RemoteEphemeralPublicKey[32]; // x25519 From 9ab1a67f0be9d33dc0984fa284fbab792137bd54 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 13 Apr 2025 18:18:44 -0400 Subject: [PATCH 767/787] common ML-KEM names and key lengths --- libi2pd/Crypto.cpp | 30 ++++++------- libi2pd/Crypto.h | 30 ++++++++++--- libi2pd/CryptoKey.h | 17 +++++++ libi2pd/ECIESX25519AEADRatchetSession.cpp | 55 ++++++++++++----------- libi2pd/ECIESX25519AEADRatchetSession.h | 2 +- 5 files changed, 88 insertions(+), 46 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index e8210a27..cf8303d1 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1011,32 +1011,32 @@ namespace crypto #if OPENSSL_PQ - MLKEM512Keys::MLKEM512Keys (): - m_Pkey (nullptr) + MLKEMKeys::MLKEMKeys (std::string_view name, size_t keyLen, size_t ctLen): + m_Name (name), m_KeyLen (keyLen), m_CTLen (ctLen),m_Pkey (nullptr) { } - MLKEM512Keys::~MLKEM512Keys () + MLKEMKeys::~MLKEMKeys () { if (m_Pkey) EVP_PKEY_free (m_Pkey); } - void MLKEM512Keys::GenerateKeys () + void MLKEMKeys::GenerateKeys () { if (m_Pkey) EVP_PKEY_free (m_Pkey); - m_Pkey = EVP_PKEY_Q_keygen(NULL, NULL, "ML-KEM-512"); + m_Pkey = EVP_PKEY_Q_keygen(NULL, NULL, m_Name.c_str ()); } - void MLKEM512Keys::GetPublicKey (uint8_t * pub) const + void MLKEMKeys::GetPublicKey (uint8_t * pub) const { if (m_Pkey) { - size_t len = MLKEM512_KEY_LENGTH; - EVP_PKEY_get_octet_string_param (m_Pkey, OSSL_PKEY_PARAM_PUB_KEY, pub, MLKEM512_KEY_LENGTH, &len); + size_t len = m_KeyLen; + EVP_PKEY_get_octet_string_param (m_Pkey, OSSL_PKEY_PARAM_PUB_KEY, pub, m_KeyLen, &len); } } - void MLKEM512Keys::SetPublicKey (const uint8_t * pub) + void MLKEMKeys::SetPublicKey (const uint8_t * pub) { if (m_Pkey) { @@ -1045,10 +1045,10 @@ namespace crypto } OSSL_PARAM params[] = { - OSSL_PARAM_octet_string (OSSL_PKEY_PARAM_PUB_KEY, (uint8_t *)pub, MLKEM512_KEY_LENGTH), + OSSL_PARAM_octet_string (OSSL_PKEY_PARAM_PUB_KEY, (uint8_t *)pub, m_KeyLen), OSSL_PARAM_END }; - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "ML-KEM-512", NULL); + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, m_Name.c_str (), NULL); if (ctx) { EVP_PKEY_fromdata_init (ctx); @@ -1059,14 +1059,14 @@ namespace crypto LogPrint (eLogError, "MLKEM512 can't create PKEY context"); } - void MLKEM512Keys::Encaps (uint8_t * ciphertext, uint8_t * shared) + void MLKEMKeys::Encaps (uint8_t * ciphertext, uint8_t * shared) { if (!m_Pkey) return; auto ctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL); if (ctx) { EVP_PKEY_encapsulate_init (ctx, NULL); - size_t len = MLKEM512_CIPHER_TEXT_LENGTH, sharedLen = 32; + size_t len = m_CTLen, sharedLen = 32; EVP_PKEY_encapsulate (ctx, ciphertext, &len, shared, &sharedLen); EVP_PKEY_CTX_free (ctx); } @@ -1074,7 +1074,7 @@ namespace crypto LogPrint (eLogError, "MLKEM512 can't create PKEY context"); } - void MLKEM512Keys::Decaps (const uint8_t * ciphertext, uint8_t * shared) + void MLKEMKeys::Decaps (const uint8_t * ciphertext, uint8_t * shared) { if (!m_Pkey) return; auto ctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL); @@ -1082,7 +1082,7 @@ namespace crypto { EVP_PKEY_decapsulate_init (ctx, NULL); size_t sharedLen = 32; - EVP_PKEY_decapsulate (ctx, shared, &sharedLen, ciphertext, MLKEM512_CIPHER_TEXT_LENGTH); + EVP_PKEY_decapsulate (ctx, shared, &sharedLen, ciphertext, m_CTLen); EVP_PKEY_CTX_free (ctx); } else diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index aa6466be..9b47f806 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -11,7 +11,10 @@ #include #include +#include #include +#include +#include #include #include #include @@ -279,14 +282,13 @@ namespace crypto #if OPENSSL_PQ // Post Quantum - constexpr size_t MLKEM512_KEY_LENGTH = 800; - constexpr size_t MLKEM512_CIPHER_TEXT_LENGTH = 768; - class MLKEM512Keys + + class MLKEMKeys { public: - MLKEM512Keys (); - ~MLKEM512Keys (); + MLKEMKeys (std::string_view name, size_t keyLen, size_t ctLen); + ~MLKEMKeys (); void GenerateKeys (); void GetPublicKey (uint8_t * pub) const; @@ -296,8 +298,26 @@ namespace crypto private: + const std::string m_Name; + const size_t m_KeyLen, m_CTLen; EVP_PKEY * m_Pkey; }; + + constexpr size_t MLKEM512_KEY_LENGTH = 800; + constexpr size_t MLKEM512_CIPHER_TEXT_LENGTH = 768; + + constexpr std::array, 1> MLKEMS = + { + std::make_tuple ("ML-KEM-512", MLKEM512_KEY_LENGTH, MLKEM512_CIPHER_TEXT_LENGTH) + }; + + class MLKEM512Keys: public MLKEMKeys + { + public: + + MLKEM512Keys (): MLKEMKeys (std::get<0>(MLKEMS[0]), std::get<1>(MLKEMS[0]), std::get<2>(MLKEMS[0])) {} + }; + #endif } } diff --git a/libi2pd/CryptoKey.h b/libi2pd/CryptoKey.h index 14ef4fa8..1e0ea3f2 100644 --- a/libi2pd/CryptoKey.h +++ b/libi2pd/CryptoKey.h @@ -183,6 +183,23 @@ namespace crypto }; return 0; } + +#if OPENSSL_PQ + constexpr size_t GetMLKEMPublicKeyLen (i2p::data::CryptoKeyType type) + { + if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || + type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return 0; + return std::get<1>(MLKEMS[type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1]); + } + + constexpr size_t GetMLKEMCipherTextLen (i2p::data::CryptoKeyType type) + { + if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || + type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return 0; + return std::get<2>(MLKEMS[type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1]); + } + +#endif } } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index cfcbf5bb..de95ce00 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -11,6 +11,7 @@ #include "Log.h" #include "util.h" #include "Crypto.h" +#include "CryptoKey.h" #include "Elligator.h" #include "Tag.h" #include "I2PEndian.h" @@ -560,18 +561,19 @@ namespace garlic } MixKey (sharedSecret); #if OPENSSL_PQ - if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) + if (m_RemoteStaticKeyType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) { - uint8_t encapsKey[i2p::crypto::MLKEM512_KEY_LENGTH]; - m_PQKeys->GetPublicKey (encapsKey); + auto keyLen = i2p::crypto::GetMLKEMPublicKeyLen (m_RemoteStaticKeyType); + std::vector encapsKey(keyLen); + m_PQKeys->GetPublicKey (encapsKey.data ()); // encrypt encapsKey - if (!Encrypt (encapsKey, out + offset, i2p::crypto::MLKEM512_KEY_LENGTH)) + if (!Encrypt (encapsKey.data (), out + offset, keyLen)) { LogPrint (eLogWarning, "Garlic: ML-KEM encap_key section AEAD encryption failed "); return false; } - MixHash (out + offset, i2p::crypto::MLKEM512_KEY_LENGTH + 16); // h = SHA256(h || ciphertext) - offset += i2p::crypto::MLKEM512_KEY_LENGTH + 16; + MixHash (out + offset, keyLen + 16); // h = SHA256(h || ciphertext) + offset += keyLen + 16; } #endif // encrypt flags/static key section @@ -657,19 +659,20 @@ namespace garlic #if OPENSSL_PQ if (m_PQKeys) { - uint8_t kemCiphertext[i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH]; - m_PQKeys->Encaps (kemCiphertext, sharedSecret); + size_t cipherTextLen = i2p::crypto::GetMLKEMCipherTextLen (m_RemoteStaticKeyType); + std::vector kemCiphertext(cipherTextLen); + m_PQKeys->Encaps (kemCiphertext.data (), sharedSecret); - if (!Encrypt (kemCiphertext, out + offset, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH)) + if (!Encrypt (kemCiphertext.data (), out + offset, cipherTextLen)) { LogPrint (eLogWarning, "Garlic: NSR ML-KEM ciphertext section AEAD encryption failed"); return false; } - m_NSREncodedPQKey = std::make_unique >(); - memcpy (m_NSREncodedPQKey->data (), out + offset, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16); - MixHash (out + offset, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16); + m_NSREncodedPQKey = std::make_unique > (cipherTextLen + 16); + memcpy (m_NSREncodedPQKey->data (), out + offset, cipherTextLen + 16); + MixHash (out + offset, cipherTextLen + 16); MixKey (sharedSecret); - offset += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; + offset += cipherTextLen + 16; } #endif // calculate hash for zero length @@ -723,9 +726,10 @@ namespace garlic { if (m_NSREncodedPQKey) { - memcpy (out + offset, m_NSREncodedPQKey->data (), i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16); - MixHash (out + offset, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16); - offset += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; + size_t cipherTextLen = i2p::crypto::GetMLKEMCipherTextLen (m_RemoteStaticKeyType); + memcpy (out + offset, m_NSREncodedPQKey->data (), cipherTextLen + 16); + MixHash (out + offset, cipherTextLen + 16); + offset += cipherTextLen + 16; } else { @@ -778,20 +782,21 @@ namespace garlic MixKey (sharedSecret); #if OPENSSL_PQ - if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) + if (m_RemoteStaticKeyType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) { // decrypt kem_ciphertext section - uint8_t kemCiphertext[i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH]; - if (!Decrypt (buf, kemCiphertext, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH)) + size_t cipherTextLen = i2p::crypto::GetMLKEMCipherTextLen (m_RemoteStaticKeyType); + std::vector kemCiphertext(cipherTextLen); + if (!Decrypt (buf, kemCiphertext.data (), cipherTextLen)) { LogPrint (eLogWarning, "Garlic: Reply ML-KEM ciphertext section AEAD decryption failed"); return false; } - MixHash (buf, i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16); - buf += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; - len -= i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; + MixHash (buf, cipherTextLen + 16); + buf += cipherTextLen + 16; + len -= cipherTextLen + 16; // decaps - m_PQKeys->Decaps (kemCiphertext, sharedSecret); + m_PQKeys->Decaps (kemCiphertext.data (), sharedSecret); MixKey (sharedSecret); } #endif @@ -981,8 +986,8 @@ namespace garlic return nullptr; len += 96; #if OPENSSL_PQ - if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) - len += i2p::crypto::MLKEM512_KEY_LENGTH + 16; + if (m_RemoteStaticKeyType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) + len += i2p::crypto::GetMLKEMPublicKeyLen (m_RemoteStaticKeyType) + 16; #endif break; case eSessionStateNewSessionReceived: diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index b988263a..2077219f 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -229,7 +229,7 @@ namespace garlic std::shared_ptr m_EphemeralKeys; #if OPENSSL_PQ std::unique_ptr m_PQKeys; - std::unique_ptr > m_NSREncodedPQKey; + std::unique_ptr > m_NSREncodedPQKey; #endif SessionState m_State = eSessionStateNew; uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0, // incoming (in seconds) From a83cd99f58f7ecd75e335a88cc94aea13381e6a6 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Apr 2025 13:29:53 -0400 Subject: [PATCH 768/787] all ML-KEM crypto types --- libi2pd/Crypto.h | 28 ++++++++++++++++++++++++---- libi2pd/Identity.h | 2 ++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 9b47f806..10f65b32 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -305,10 +305,16 @@ namespace crypto constexpr size_t MLKEM512_KEY_LENGTH = 800; constexpr size_t MLKEM512_CIPHER_TEXT_LENGTH = 768; - - constexpr std::array, 1> MLKEMS = + constexpr size_t MLKEM768_KEY_LENGTH = 1184; + constexpr size_t MLKEM768_CIPHER_TEXT_LENGTH = 1088; + constexpr size_t MLKEM1024_KEY_LENGTH = 1568; + constexpr size_t MLKEM1024_CIPHER_TEXT_LENGTH = 1568; + + constexpr std::array, 3> MLKEMS = { - std::make_tuple ("ML-KEM-512", MLKEM512_KEY_LENGTH, MLKEM512_CIPHER_TEXT_LENGTH) + std::make_tuple ("ML-KEM-512", MLKEM512_KEY_LENGTH, MLKEM512_CIPHER_TEXT_LENGTH), + std::make_tuple ("ML-KEM-768", MLKEM768_KEY_LENGTH, MLKEM768_CIPHER_TEXT_LENGTH), + std::make_tuple ("ML-KEM-1024", MLKEM1024_KEY_LENGTH, MLKEM1024_CIPHER_TEXT_LENGTH) }; class MLKEM512Keys: public MLKEMKeys @@ -317,7 +323,21 @@ namespace crypto MLKEM512Keys (): MLKEMKeys (std::get<0>(MLKEMS[0]), std::get<1>(MLKEMS[0]), std::get<2>(MLKEMS[0])) {} }; - + + class MLKEM768Keys: public MLKEMKeys + { + public: + + MLKEM768Keys (): MLKEMKeys (std::get<0>(MLKEMS[1]), std::get<1>(MLKEMS[1]), std::get<2>(MLKEMS[1])) {} + }; + + class MLKEM1024Keys: public MLKEMKeys + { + public: + + MLKEM1024Keys (): MLKEMKeys (std::get<0>(MLKEMS[2]), std::get<1>(MLKEMS[2]), std::get<2>(MLKEMS[2])) {} + }; + #endif } } diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index ee736441..173559e9 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -71,6 +71,8 @@ namespace data const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 1; const uint16_t CRYPTO_KEY_TYPE_ECIES_X25519_AEAD = 4; const uint16_t CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD = 5; + const uint16_t CRYPTO_KEY_TYPE_ECIES_MLKEM768_X25519_AEAD = 6; + const uint16_t CRYPTO_KEY_TYPE_ECIES_MLKEM1024_X25519_AEAD = 7; const uint16_t SIGNING_KEY_TYPE_DSA_SHA1 = 0; const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA256_P256 = 1; From 459be02d18d8e9b2c7a838a956d5d437a3f1f80a Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Apr 2025 13:31:37 -0400 Subject: [PATCH 769/787] correct sequence of MixKey for ML-KEM NSR --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index de95ce00..d5b7150d 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -649,13 +649,6 @@ namespace garlic return false; } MixKey (sharedSecret); - if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret)) // sharedSecret = x25519(besk, apk) - { - LogPrint (eLogWarning, "Garlic: Incorrect Alice static key"); - return false; - } - MixKey (sharedSecret); - #if OPENSSL_PQ if (m_PQKeys) { @@ -675,6 +668,12 @@ namespace garlic offset += cipherTextLen + 16; } #endif + if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret)) // sharedSecret = x25519(besk, apk) + { + LogPrint (eLogWarning, "Garlic: Incorrect Alice static key"); + return false; + } + MixKey (sharedSecret); // calculate hash for zero length if (!Encrypt (sharedSecret /* can be anything */, out + offset, 0)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) { @@ -778,9 +777,6 @@ namespace garlic return false; } MixKey (sharedSecret); - GetOwner ()->Decrypt (bepk, sharedSecret, m_RemoteStaticKeyType); // x25519 (ask, bepk) - MixKey (sharedSecret); - #if OPENSSL_PQ if (m_RemoteStaticKeyType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) { @@ -799,7 +795,10 @@ namespace garlic m_PQKeys->Decaps (kemCiphertext.data (), sharedSecret); MixKey (sharedSecret); } -#endif +#endif + GetOwner ()->Decrypt (bepk, sharedSecret, m_RemoteStaticKeyType); // x25519 (ask, bepk) + MixKey (sharedSecret); + // calculate hash for zero length if (!Decrypt (buf, sharedSecret/* can be anything */, 0)) // decrypt, DECRYPT(k, n, ZEROLEN, ad) verification only { From 4c5d0116f8891c272b0d150a74dfc779c5efb333 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Apr 2025 18:21:07 -0400 Subject: [PATCH 770/787] moved ML-KEM code to PostQuntum.h/.cpp --- libi2pd/Crypto.cpp | 81 ----------------- libi2pd/Crypto.h | 63 -------------- libi2pd/CryptoKey.h | 17 ---- libi2pd/ECIESX25519AEADRatchetSession.cpp | 2 +- libi2pd/ECIESX25519AEADRatchetSession.h | 3 +- libi2pd/PostQuantum.cpp | 101 ++++++++++++++++++++++ libi2pd/PostQuantum.h | 97 +++++++++++++++++++++ 7 files changed, 201 insertions(+), 163 deletions(-) create mode 100644 libi2pd/PostQuantum.cpp create mode 100644 libi2pd/PostQuantum.h diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index cf8303d1..be2863f4 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1008,86 +1008,5 @@ namespace crypto /* CRYPTO_set_locking_callback (nullptr); m_OpenSSLMutexes.clear ();*/ } - -#if OPENSSL_PQ - - MLKEMKeys::MLKEMKeys (std::string_view name, size_t keyLen, size_t ctLen): - m_Name (name), m_KeyLen (keyLen), m_CTLen (ctLen),m_Pkey (nullptr) - { - } - - MLKEMKeys::~MLKEMKeys () - { - if (m_Pkey) EVP_PKEY_free (m_Pkey); - } - - void MLKEMKeys::GenerateKeys () - { - if (m_Pkey) EVP_PKEY_free (m_Pkey); - m_Pkey = EVP_PKEY_Q_keygen(NULL, NULL, m_Name.c_str ()); - } - - void MLKEMKeys::GetPublicKey (uint8_t * pub) const - { - if (m_Pkey) - { - size_t len = m_KeyLen; - EVP_PKEY_get_octet_string_param (m_Pkey, OSSL_PKEY_PARAM_PUB_KEY, pub, m_KeyLen, &len); - } - } - - void MLKEMKeys::SetPublicKey (const uint8_t * pub) - { - if (m_Pkey) - { - EVP_PKEY_free (m_Pkey); - m_Pkey = nullptr; - } - OSSL_PARAM params[] = - { - OSSL_PARAM_octet_string (OSSL_PKEY_PARAM_PUB_KEY, (uint8_t *)pub, m_KeyLen), - OSSL_PARAM_END - }; - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, m_Name.c_str (), NULL); - if (ctx) - { - EVP_PKEY_fromdata_init (ctx); - EVP_PKEY_fromdata (ctx, &m_Pkey, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, params); - EVP_PKEY_CTX_free (ctx); - } - else - LogPrint (eLogError, "MLKEM512 can't create PKEY context"); - } - - void MLKEMKeys::Encaps (uint8_t * ciphertext, uint8_t * shared) - { - if (!m_Pkey) return; - auto ctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL); - if (ctx) - { - EVP_PKEY_encapsulate_init (ctx, NULL); - size_t len = m_CTLen, sharedLen = 32; - EVP_PKEY_encapsulate (ctx, ciphertext, &len, shared, &sharedLen); - EVP_PKEY_CTX_free (ctx); - } - else - LogPrint (eLogError, "MLKEM512 can't create PKEY context"); - } - - void MLKEMKeys::Decaps (const uint8_t * ciphertext, uint8_t * shared) - { - if (!m_Pkey) return; - auto ctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL); - if (ctx) - { - EVP_PKEY_decapsulate_init (ctx, NULL); - size_t sharedLen = 32; - EVP_PKEY_decapsulate (ctx, shared, &sharedLen, ciphertext, m_CTLen); - EVP_PKEY_CTX_free (ctx); - } - else - LogPrint (eLogError, "MLKEM512 can't create PKEY context"); - } -#endif } } diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 10f65b32..6abbd9b2 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -11,10 +11,7 @@ #include #include -#include #include -#include -#include #include #include #include @@ -279,66 +276,6 @@ namespace crypto // init and terminate void InitCrypto (bool precomputation); void TerminateCrypto (); - -#if OPENSSL_PQ -// Post Quantum - - class MLKEMKeys - { - public: - - MLKEMKeys (std::string_view name, size_t keyLen, size_t ctLen); - ~MLKEMKeys (); - - void GenerateKeys (); - void GetPublicKey (uint8_t * pub) const; - void SetPublicKey (const uint8_t * pub); - void Encaps (uint8_t * ciphertext, uint8_t * shared); - void Decaps (const uint8_t * ciphertext, uint8_t * shared); - - private: - - const std::string m_Name; - const size_t m_KeyLen, m_CTLen; - EVP_PKEY * m_Pkey; - }; - - constexpr size_t MLKEM512_KEY_LENGTH = 800; - constexpr size_t MLKEM512_CIPHER_TEXT_LENGTH = 768; - constexpr size_t MLKEM768_KEY_LENGTH = 1184; - constexpr size_t MLKEM768_CIPHER_TEXT_LENGTH = 1088; - constexpr size_t MLKEM1024_KEY_LENGTH = 1568; - constexpr size_t MLKEM1024_CIPHER_TEXT_LENGTH = 1568; - - constexpr std::array, 3> MLKEMS = - { - std::make_tuple ("ML-KEM-512", MLKEM512_KEY_LENGTH, MLKEM512_CIPHER_TEXT_LENGTH), - std::make_tuple ("ML-KEM-768", MLKEM768_KEY_LENGTH, MLKEM768_CIPHER_TEXT_LENGTH), - std::make_tuple ("ML-KEM-1024", MLKEM1024_KEY_LENGTH, MLKEM1024_CIPHER_TEXT_LENGTH) - }; - - class MLKEM512Keys: public MLKEMKeys - { - public: - - MLKEM512Keys (): MLKEMKeys (std::get<0>(MLKEMS[0]), std::get<1>(MLKEMS[0]), std::get<2>(MLKEMS[0])) {} - }; - - class MLKEM768Keys: public MLKEMKeys - { - public: - - MLKEM768Keys (): MLKEMKeys (std::get<0>(MLKEMS[1]), std::get<1>(MLKEMS[1]), std::get<2>(MLKEMS[1])) {} - }; - - class MLKEM1024Keys: public MLKEMKeys - { - public: - - MLKEM1024Keys (): MLKEMKeys (std::get<0>(MLKEMS[2]), std::get<1>(MLKEMS[2]), std::get<2>(MLKEMS[2])) {} - }; - -#endif } } diff --git a/libi2pd/CryptoKey.h b/libi2pd/CryptoKey.h index 1e0ea3f2..14ef4fa8 100644 --- a/libi2pd/CryptoKey.h +++ b/libi2pd/CryptoKey.h @@ -183,23 +183,6 @@ namespace crypto }; return 0; } - -#if OPENSSL_PQ - constexpr size_t GetMLKEMPublicKeyLen (i2p::data::CryptoKeyType type) - { - if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || - type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return 0; - return std::get<1>(MLKEMS[type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1]); - } - - constexpr size_t GetMLKEMCipherTextLen (i2p::data::CryptoKeyType type) - { - if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || - type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return 0; - return std::get<2>(MLKEMS[type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1]); - } - -#endif } } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index d5b7150d..5d563d97 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -11,7 +11,7 @@ #include "Log.h" #include "util.h" #include "Crypto.h" -#include "CryptoKey.h" +#include "PostQuantum.h" #include "Elligator.h" #include "Tag.h" #include "I2PEndian.h" diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 2077219f..b7704534 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -19,6 +19,7 @@ #include #include "Identity.h" #include "Crypto.h" +#include "PostQuantum.h" #include "Garlic.h" #include "Tag.h" @@ -228,7 +229,7 @@ namespace garlic uint8_t m_NSREncodedKey[32], m_NSRH[32], m_NSRKey[32]; // new session reply, for incoming only std::shared_ptr m_EphemeralKeys; #if OPENSSL_PQ - std::unique_ptr m_PQKeys; + std::unique_ptr m_PQKeys; std::unique_ptr > m_NSREncodedPQKey; #endif SessionState m_State = eSessionStateNew; diff --git a/libi2pd/PostQuantum.cpp b/libi2pd/PostQuantum.cpp new file mode 100644 index 00000000..abe207d2 --- /dev/null +++ b/libi2pd/PostQuantum.cpp @@ -0,0 +1,101 @@ +/* +* Copyright (c) 2025, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include "Log.h" +#include "PostQuantum.h" + +#if OPENSSL_PQ + +#include +#include + +namespace i2p +{ +namespace crypto +{ + MLKEMKeys::MLKEMKeys (std::string_view name, size_t keyLen, size_t ctLen): + m_Name (name), m_KeyLen (keyLen), m_CTLen (ctLen),m_Pkey (nullptr) + { + } + + MLKEMKeys::~MLKEMKeys () + { + if (m_Pkey) EVP_PKEY_free (m_Pkey); + } + + void MLKEMKeys::GenerateKeys () + { + if (m_Pkey) EVP_PKEY_free (m_Pkey); + m_Pkey = EVP_PKEY_Q_keygen(NULL, NULL, m_Name.c_str ()); + } + + void MLKEMKeys::GetPublicKey (uint8_t * pub) const + { + if (m_Pkey) + { + size_t len = m_KeyLen; + EVP_PKEY_get_octet_string_param (m_Pkey, OSSL_PKEY_PARAM_PUB_KEY, pub, m_KeyLen, &len); + } + } + + void MLKEMKeys::SetPublicKey (const uint8_t * pub) + { + if (m_Pkey) + { + EVP_PKEY_free (m_Pkey); + m_Pkey = nullptr; + } + OSSL_PARAM params[] = + { + OSSL_PARAM_octet_string (OSSL_PKEY_PARAM_PUB_KEY, (uint8_t *)pub, m_KeyLen), + OSSL_PARAM_END + }; + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, m_Name.c_str (), NULL); + if (ctx) + { + EVP_PKEY_fromdata_init (ctx); + EVP_PKEY_fromdata (ctx, &m_Pkey, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, params); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "MLKEM512 can't create PKEY context"); + } + + void MLKEMKeys::Encaps (uint8_t * ciphertext, uint8_t * shared) + { + if (!m_Pkey) return; + auto ctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL); + if (ctx) + { + EVP_PKEY_encapsulate_init (ctx, NULL); + size_t len = m_CTLen, sharedLen = 32; + EVP_PKEY_encapsulate (ctx, ciphertext, &len, shared, &sharedLen); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "MLKEM512 can't create PKEY context"); + } + + void MLKEMKeys::Decaps (const uint8_t * ciphertext, uint8_t * shared) + { + if (!m_Pkey) return; + auto ctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL); + if (ctx) + { + EVP_PKEY_decapsulate_init (ctx, NULL); + size_t sharedLen = 32; + EVP_PKEY_decapsulate (ctx, shared, &sharedLen, ciphertext, m_CTLen); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "MLKEM512 can't create PKEY context"); + } +} +} + +#endif \ No newline at end of file diff --git a/libi2pd/PostQuantum.h b/libi2pd/PostQuantum.h new file mode 100644 index 00000000..6081f653 --- /dev/null +++ b/libi2pd/PostQuantum.h @@ -0,0 +1,97 @@ +/* +* Copyright (c) 2025, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#ifndef POST_QUANTUM_H__ +#define POST_QUANTUM_H__ + +#include +#include +#include +#include "Crypto.h" +#include "Identity.h" + +#if OPENSSL_PQ + +namespace i2p +{ +namespace crypto +{ + class MLKEMKeys + { + public: + + MLKEMKeys (std::string_view name, size_t keyLen, size_t ctLen); + ~MLKEMKeys (); + + void GenerateKeys (); + void GetPublicKey (uint8_t * pub) const; + void SetPublicKey (const uint8_t * pub); + void Encaps (uint8_t * ciphertext, uint8_t * shared); + void Decaps (const uint8_t * ciphertext, uint8_t * shared); + + private: + + const std::string m_Name; + const size_t m_KeyLen, m_CTLen; + EVP_PKEY * m_Pkey; + }; + + constexpr size_t MLKEM512_KEY_LENGTH = 800; + constexpr size_t MLKEM512_CIPHER_TEXT_LENGTH = 768; + constexpr size_t MLKEM768_KEY_LENGTH = 1184; + constexpr size_t MLKEM768_CIPHER_TEXT_LENGTH = 1088; + constexpr size_t MLKEM1024_KEY_LENGTH = 1568; + constexpr size_t MLKEM1024_CIPHER_TEXT_LENGTH = 1568; + + constexpr std::array, 3> MLKEMS = + { + std::make_tuple ("ML-KEM-512", MLKEM512_KEY_LENGTH, MLKEM512_CIPHER_TEXT_LENGTH), + std::make_tuple ("ML-KEM-768", MLKEM768_KEY_LENGTH, MLKEM768_CIPHER_TEXT_LENGTH), + std::make_tuple ("ML-KEM-1024", MLKEM1024_KEY_LENGTH, MLKEM1024_CIPHER_TEXT_LENGTH) + }; + + class MLKEM512Keys: public MLKEMKeys + { + public: + + MLKEM512Keys (): MLKEMKeys (std::get<0>(MLKEMS[0]), std::get<1>(MLKEMS[0]), std::get<2>(MLKEMS[0])) {} + }; + + class MLKEM768Keys: public MLKEMKeys + { + public: + + MLKEM768Keys (): MLKEMKeys (std::get<0>(MLKEMS[1]), std::get<1>(MLKEMS[1]), std::get<2>(MLKEMS[1])) {} + }; + + class MLKEM1024Keys: public MLKEMKeys + { + public: + + MLKEM1024Keys (): MLKEMKeys (std::get<0>(MLKEMS[2]), std::get<1>(MLKEMS[2]), std::get<2>(MLKEMS[2])) {} + }; + + constexpr size_t GetMLKEMPublicKeyLen (i2p::data::CryptoKeyType type) + { + if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || + type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return 0; + return std::get<1>(MLKEMS[type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1]); + } + + constexpr size_t GetMLKEMCipherTextLen (i2p::data::CryptoKeyType type) + { + if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || + type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return 0; + return std::get<2>(MLKEMS[type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1]); + } +} +} + +#endif + +#endif From 828cd9d07b4f90e39a16bec4adb36bcdb78bd48c Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Apr 2025 19:38:43 -0400 Subject: [PATCH 771/787] common MLKEMKeys for all types --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 4 +- libi2pd/PostQuantum.cpp | 12 +++- libi2pd/PostQuantum.h | 87 ++++++++++------------- 3 files changed, 50 insertions(+), 53 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 5d563d97..fbea786f 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -290,7 +290,7 @@ namespace garlic len -= i2p::crypto::MLKEM512_KEY_LENGTH + 16; n++; - m_PQKeys = std::make_unique(); + m_PQKeys = i2p::crypto::CreateMLKEMKeys (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD); m_PQKeys->SetPublicKey (encapsKey); } } @@ -546,7 +546,7 @@ namespace garlic if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) { i2p::crypto::InitNoiseIKStateMLKEM512 (GetNoiseState (), m_RemoteStaticKey); // bpk - m_PQKeys = std::make_unique(); + m_PQKeys = i2p::crypto::CreateMLKEMKeys (m_RemoteStaticKeyType); m_PQKeys->GenerateKeys (); } else diff --git a/libi2pd/PostQuantum.cpp b/libi2pd/PostQuantum.cpp index abe207d2..16823c19 100644 --- a/libi2pd/PostQuantum.cpp +++ b/libi2pd/PostQuantum.cpp @@ -18,8 +18,9 @@ namespace i2p { namespace crypto { - MLKEMKeys::MLKEMKeys (std::string_view name, size_t keyLen, size_t ctLen): - m_Name (name), m_KeyLen (keyLen), m_CTLen (ctLen),m_Pkey (nullptr) + MLKEMKeys::MLKEMKeys (MLKEMTypes type): + m_Name (std::get<0>(MLKEMS[type])), m_KeyLen (std::get<1>(MLKEMS[type])), + m_CTLen (std::get<2>(MLKEMS[type])), m_Pkey (nullptr) { } @@ -95,6 +96,13 @@ namespace crypto else LogPrint (eLogError, "MLKEM512 can't create PKEY context"); } + + std::unique_ptr CreateMLKEMKeys (i2p::data::CryptoKeyType type) + { + if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || + type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return nullptr; + return std::make_unique((MLKEMTypes)(type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1)); + } } } diff --git a/libi2pd/PostQuantum.h b/libi2pd/PostQuantum.h index 6081f653..6bf2f238 100644 --- a/libi2pd/PostQuantum.h +++ b/libi2pd/PostQuantum.h @@ -9,6 +9,7 @@ #ifndef POST_QUANTUM_H__ #define POST_QUANTUM_H__ +#include #include #include #include @@ -21,11 +22,46 @@ namespace i2p { namespace crypto { + enum MLKEMTypes + { + eMLKEM512 = 0, + eMLKEM768, + eMLKEM1024 + }; + + constexpr size_t MLKEM512_KEY_LENGTH = 800; + constexpr size_t MLKEM512_CIPHER_TEXT_LENGTH = 768; + constexpr size_t MLKEM768_KEY_LENGTH = 1184; + constexpr size_t MLKEM768_CIPHER_TEXT_LENGTH = 1088; + constexpr size_t MLKEM1024_KEY_LENGTH = 1568; + constexpr size_t MLKEM1024_CIPHER_TEXT_LENGTH = 1568; + + constexpr std::array, 3> MLKEMS = + { + std::make_tuple ("ML-KEM-512", MLKEM512_KEY_LENGTH, MLKEM512_CIPHER_TEXT_LENGTH), + std::make_tuple ("ML-KEM-768", MLKEM768_KEY_LENGTH, MLKEM768_CIPHER_TEXT_LENGTH), + std::make_tuple ("ML-KEM-1024", MLKEM1024_KEY_LENGTH, MLKEM1024_CIPHER_TEXT_LENGTH) + }; + + constexpr size_t GetMLKEMPublicKeyLen (i2p::data::CryptoKeyType type) + { + if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || + type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return 0; + return std::get<1>(MLKEMS[type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1]); + } + + constexpr size_t GetMLKEMCipherTextLen (i2p::data::CryptoKeyType type) + { + if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || + type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return 0; + return std::get<2>(MLKEMS[type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1]); + } + class MLKEMKeys { public: - MLKEMKeys (std::string_view name, size_t keyLen, size_t ctLen); + MLKEMKeys (MLKEMTypes type); ~MLKEMKeys (); void GenerateKeys (); @@ -41,54 +77,7 @@ namespace crypto EVP_PKEY * m_Pkey; }; - constexpr size_t MLKEM512_KEY_LENGTH = 800; - constexpr size_t MLKEM512_CIPHER_TEXT_LENGTH = 768; - constexpr size_t MLKEM768_KEY_LENGTH = 1184; - constexpr size_t MLKEM768_CIPHER_TEXT_LENGTH = 1088; - constexpr size_t MLKEM1024_KEY_LENGTH = 1568; - constexpr size_t MLKEM1024_CIPHER_TEXT_LENGTH = 1568; - - constexpr std::array, 3> MLKEMS = - { - std::make_tuple ("ML-KEM-512", MLKEM512_KEY_LENGTH, MLKEM512_CIPHER_TEXT_LENGTH), - std::make_tuple ("ML-KEM-768", MLKEM768_KEY_LENGTH, MLKEM768_CIPHER_TEXT_LENGTH), - std::make_tuple ("ML-KEM-1024", MLKEM1024_KEY_LENGTH, MLKEM1024_CIPHER_TEXT_LENGTH) - }; - - class MLKEM512Keys: public MLKEMKeys - { - public: - - MLKEM512Keys (): MLKEMKeys (std::get<0>(MLKEMS[0]), std::get<1>(MLKEMS[0]), std::get<2>(MLKEMS[0])) {} - }; - - class MLKEM768Keys: public MLKEMKeys - { - public: - - MLKEM768Keys (): MLKEMKeys (std::get<0>(MLKEMS[1]), std::get<1>(MLKEMS[1]), std::get<2>(MLKEMS[1])) {} - }; - - class MLKEM1024Keys: public MLKEMKeys - { - public: - - MLKEM1024Keys (): MLKEMKeys (std::get<0>(MLKEMS[2]), std::get<1>(MLKEMS[2]), std::get<2>(MLKEMS[2])) {} - }; - - constexpr size_t GetMLKEMPublicKeyLen (i2p::data::CryptoKeyType type) - { - if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || - type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return 0; - return std::get<1>(MLKEMS[type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1]); - } - - constexpr size_t GetMLKEMCipherTextLen (i2p::data::CryptoKeyType type) - { - if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || - type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return 0; - return std::get<2>(MLKEMS[type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1]); - } + std::unique_ptr CreateMLKEMKeys (i2p::data::CryptoKeyType type); } } From 1a04b5958557be826a86058cfd7b8dcc12aee82c Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Apr 2025 21:45:53 -0400 Subject: [PATCH 772/787] common InitNoiseIKState for all ML-KEM crypto --- libi2pd/Crypto.cpp | 15 -------------- libi2pd/Crypto.h | 3 +-- libi2pd/ECIESX25519AEADRatchetSession.cpp | 14 ++++++------- libi2pd/PostQuantum.cpp | 25 +++++++++++++++++++++++ libi2pd/PostQuantum.h | 2 ++ 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index be2863f4..c41b4c10 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -944,21 +944,6 @@ namespace crypto }; // SHA256 (protocolNameHash) state.Init (protocolNameHash, hh, pub); } - - void InitNoiseIKStateMLKEM512 (NoiseSymmetricState& state, const uint8_t * pub) - { - static constexpr uint8_t protocolNameHash[32] = - { - 0xb0, 0x8f, 0xb1, 0x73, 0x92, 0x66, 0xc9, 0x90, 0x45, 0x7f, 0xdd, 0xc6, 0x4e, 0x55, 0x40, 0xd8, - 0x0a, 0x37, 0x99, 0x06, 0x92, 0x2a, 0x78, 0xc4, 0xb1, 0xef, 0x86, 0x06, 0xd0, 0x15, 0x9f, 0x4d - }; // SHA256("Noise_IKhfselg2_25519+MLKEM512_ChaChaPoly_SHA256") - static constexpr uint8_t hh[32] = - { - 0x95, 0x8d, 0xf6, 0x6c, 0x95, 0xce, 0xa9, 0xf7, 0x42, 0xfc, 0xfa, 0x62, 0x71, 0x36, 0x1e, 0xa7, - 0xdc, 0x7a, 0xc0, 0x75, 0x01, 0xcf, 0xf9, 0xfc, 0x9f, 0xdb, 0x4c, 0x68, 0x3a, 0x53, 0x49, 0xeb - }; // SHA256 (protocolNameHash) - state.Init (protocolNameHash, hh, pub); - } // init and terminate diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 6abbd9b2..125a217c 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -271,8 +271,7 @@ namespace crypto void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (NTCP2) void InitNoiseXKState1 (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (SSU2) void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets) - void InitNoiseIKStateMLKEM512 (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets) PQ ML-KEM512 - + // init and terminate void InitCrypto (bool precomputation); void TerminateCrypto (); diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index fbea786f..d38abd13 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -272,7 +272,8 @@ namespace garlic #if OPENSSL_PQ if (GetOwner ()->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)) { - i2p::crypto::InitNoiseIKStateMLKEM512 (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)); // bpk + i2p::crypto::InitNoiseIKStateMLKEM (GetNoiseState (), i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD, + GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)); // bpk MixHash (m_Aepk, 32); // h = SHA256(h || aepk) if (GetOwner ()->Decrypt (m_Aepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)) // x25519(bsk, aepk) @@ -281,8 +282,7 @@ namespace garlic uint8_t nonce[12], encapsKey[i2p::crypto::MLKEM512_KEY_LENGTH]; CreateNonce (n, nonce); - if (i2p::crypto::AEADChaCha20Poly1305 (buf, i2p::crypto::MLKEM512_KEY_LENGTH, - m_H, 32, m_CK + 32, nonce, encapsKey, i2p::crypto::MLKEM512_KEY_LENGTH, false)) // decrypt + if (Decrypt (buf, encapsKey, i2p::crypto::MLKEM512_KEY_LENGTH)) { decrypted = true; // encaps section has right hash MixHash (buf, i2p::crypto::MLKEM512_KEY_LENGTH + 16); @@ -320,7 +320,7 @@ namespace garlic // decrypt flags/static uint8_t nonce[12], fs[32]; CreateNonce (n, nonce); - if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 32, m_H, 32, m_CK + 32, nonce, fs, 32, false)) // decrypt + if (!Decrypt (buf, fs, 32)) { LogPrint (eLogWarning, "Garlic: Flags/static section AEAD verification failed "); return false; @@ -354,7 +354,7 @@ namespace garlic // decrypt payload std::vector payload (len - 16); // we must save original ciphertext - if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt + if (!Decrypt (buf, payload.data (), len - 16)) { LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed"); return false; @@ -543,9 +543,9 @@ namespace garlic // KDF1 #if OPENSSL_PQ - if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) + if (m_RemoteStaticKeyType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) { - i2p::crypto::InitNoiseIKStateMLKEM512 (GetNoiseState (), m_RemoteStaticKey); // bpk + i2p::crypto::InitNoiseIKStateMLKEM (GetNoiseState (), m_RemoteStaticKeyType, m_RemoteStaticKey); // bpk m_PQKeys = i2p::crypto::CreateMLKEMKeys (m_RemoteStaticKeyType); m_PQKeys->GenerateKeys (); } diff --git a/libi2pd/PostQuantum.cpp b/libi2pd/PostQuantum.cpp index 16823c19..0a55ca4d 100644 --- a/libi2pd/PostQuantum.cpp +++ b/libi2pd/PostQuantum.cpp @@ -103,6 +103,31 @@ namespace crypto type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return nullptr; return std::make_unique((MLKEMTypes)(type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1)); } + + static constexpr std::array, std::array >, 1> NoiseIKInitMLKEMKeys = + { + std::make_pair + ( + std::array + { + 0xb0, 0x8f, 0xb1, 0x73, 0x92, 0x66, 0xc9, 0x90, 0x45, 0x7f, 0xdd, 0xc6, 0x4e, 0x55, 0x40, 0xd8, + 0x0a, 0x37, 0x99, 0x06, 0x92, 0x2a, 0x78, 0xc4, 0xb1, 0xef, 0x86, 0x06, 0xd0, 0x15, 0x9f, 0x4d + }, // SHA256("Noise_IKhfselg2_25519+MLKEM512_ChaChaPoly_SHA256") + std::array + { + 0x95, 0x8d, 0xf6, 0x6c, 0x95, 0xce, 0xa9, 0xf7, 0x42, 0xfc, 0xfa, 0x62, 0x71, 0x36, 0x1e, 0xa7, + 0xdc, 0x7a, 0xc0, 0x75, 0x01, 0xcf, 0xf9, 0xfc, 0x9f, 0xdb, 0x4c, 0x68, 0x3a, 0x53, 0x49, 0xeb + } // SHA256 (first) + ) + }; + + void InitNoiseIKStateMLKEM (NoiseSymmetricState& state, i2p::data::CryptoKeyType type, const uint8_t * pub) + { + if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || + type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)NoiseIKInitMLKEMKeys.size ()) return; + auto ind = type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1; + state.Init (NoiseIKInitMLKEMKeys[ind].first.data(), NoiseIKInitMLKEMKeys[ind].second.data(), pub); + } } } diff --git a/libi2pd/PostQuantum.h b/libi2pd/PostQuantum.h index 6bf2f238..f426d661 100644 --- a/libi2pd/PostQuantum.h +++ b/libi2pd/PostQuantum.h @@ -78,6 +78,8 @@ namespace crypto }; std::unique_ptr CreateMLKEMKeys (i2p::data::CryptoKeyType type); + + void InitNoiseIKStateMLKEM (NoiseSymmetricState& state, i2p::data::CryptoKeyType type, const uint8_t * pub); // Noise_IK (ratchets) PQ ML-KEM5 } } From 9c46ff244991d7f80d01a17875a41d018d04927e Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 15 Apr 2025 13:26:19 -0400 Subject: [PATCH 773/787] Initial Noise states and encryptors/decryptors for ML-KEM-768 and ML-KEM-1024 --- libi2pd/CryptoKey.h | 12 ++++++++++-- libi2pd/Identity.cpp | 12 +++++++++--- libi2pd/PostQuantum.cpp | 36 +++++++++++++++++++++++++++++++----- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/libi2pd/CryptoKey.h b/libi2pd/CryptoKey.h index 14ef4fa8..657a6a91 100644 --- a/libi2pd/CryptoKey.h +++ b/libi2pd/CryptoKey.h @@ -167,7 +167,11 @@ namespace crypto case i2p::data::CRYPTO_KEY_TYPE_ELGAMAL: return 256; case i2p::data::CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: return 32; case i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: return 32; - case i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: return 32; + // ML-KEM hybrid + case i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: + case i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM768_X25519_AEAD: + case i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM1024_X25519_AEAD: + return 32; }; return 0; } @@ -179,7 +183,11 @@ namespace crypto case i2p::data::CRYPTO_KEY_TYPE_ELGAMAL: return 256; case i2p::data::CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: return 32; case i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: return 32; - case i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: return 32; + // ML-KEM hybrid + case i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: + case i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM768_X25519_AEAD: + case i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM1024_X25519_AEAD: + return 32; }; return 0; } diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 3b2f5b97..798d9505 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -419,7 +419,9 @@ namespace data return std::make_shared(key); break; case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: - case CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: + case CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: + case CRYPTO_KEY_TYPE_ECIES_MLKEM768_X25519_AEAD: + case CRYPTO_KEY_TYPE_ECIES_MLKEM1024_X25519_AEAD: return std::make_shared(key); break; case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: @@ -686,7 +688,9 @@ namespace data return std::make_shared(key); break; case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: - case CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: + case CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: + case CRYPTO_KEY_TYPE_ECIES_MLKEM768_X25519_AEAD: + case CRYPTO_KEY_TYPE_ECIES_MLKEM1024_X25519_AEAD: return std::make_shared(key); break; case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: @@ -774,7 +778,9 @@ namespace data i2p::crypto::CreateECIESP256RandomKeys (priv, pub); break; case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: - case CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: + case CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: + case CRYPTO_KEY_TYPE_ECIES_MLKEM768_X25519_AEAD: + case CRYPTO_KEY_TYPE_ECIES_MLKEM1024_X25519_AEAD: i2p::crypto::CreateECIESX25519AEADRatchetRandomKeys (priv, pub); break; default: diff --git a/libi2pd/PostQuantum.cpp b/libi2pd/PostQuantum.cpp index 0a55ca4d..fa268828 100644 --- a/libi2pd/PostQuantum.cpp +++ b/libi2pd/PostQuantum.cpp @@ -64,7 +64,7 @@ namespace crypto EVP_PKEY_CTX_free (ctx); } else - LogPrint (eLogError, "MLKEM512 can't create PKEY context"); + LogPrint (eLogError, "MLKEM can't create PKEY context"); } void MLKEMKeys::Encaps (uint8_t * ciphertext, uint8_t * shared) @@ -79,7 +79,7 @@ namespace crypto EVP_PKEY_CTX_free (ctx); } else - LogPrint (eLogError, "MLKEM512 can't create PKEY context"); + LogPrint (eLogError, "MLKEM can't create PKEY context"); } void MLKEMKeys::Decaps (const uint8_t * ciphertext, uint8_t * shared) @@ -94,7 +94,7 @@ namespace crypto EVP_PKEY_CTX_free (ctx); } else - LogPrint (eLogError, "MLKEM512 can't create PKEY context"); + LogPrint (eLogError, "MLKEM can't create PKEY context"); } std::unique_ptr CreateMLKEMKeys (i2p::data::CryptoKeyType type) @@ -104,7 +104,7 @@ namespace crypto return std::make_unique((MLKEMTypes)(type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1)); } - static constexpr std::array, std::array >, 1> NoiseIKInitMLKEMKeys = + static constexpr std::array, std::array >, 3> NoiseIKInitMLKEMKeys = { std::make_pair ( @@ -118,7 +118,33 @@ namespace crypto 0x95, 0x8d, 0xf6, 0x6c, 0x95, 0xce, 0xa9, 0xf7, 0x42, 0xfc, 0xfa, 0x62, 0x71, 0x36, 0x1e, 0xa7, 0xdc, 0x7a, 0xc0, 0x75, 0x01, 0xcf, 0xf9, 0xfc, 0x9f, 0xdb, 0x4c, 0x68, 0x3a, 0x53, 0x49, 0xeb } // SHA256 (first) - ) + ), + std::make_pair + ( + std::array + { + 0x36, 0x03, 0x90, 0x2d, 0xf9, 0xa2, 0x2a, 0x5e, 0xc9, 0x3d, 0xdb, 0x8f, 0xa8, 0x1b, 0xdb, 0x4b, + 0xae, 0x9d, 0x93, 0x9c, 0xdf, 0xaf, 0xde, 0x55, 0x49, 0x13, 0xfe, 0x98, 0xf8, 0x4a, 0xd4, 0xbd + }, // SHA256("Noise_IKhfselg2_25519+MLKEM768_ChaChaPoly_SHA256") + std::array + { + 0x15, 0x44, 0x89, 0xbf, 0x30, 0xf0, 0xc9, 0x77, 0x66, 0x10, 0xcb, 0xb1, 0x57, 0x3f, 0xab, 0x68, + 0x79, 0x57, 0x39, 0x57, 0x0a, 0xe7, 0xc0, 0x31, 0x8a, 0xa2, 0x96, 0xef, 0xbf, 0xa9, 0x6a, 0xbb + } // SHA256 (first) + ), + std::make_pair + ( + std::array + { + 0x86, 0xa5, 0x36, 0x44, 0xc6, 0x12, 0xd5, 0x71, 0xa1, 0x2d, 0xd8, 0xb6, 0x0a, 0x00, 0x9f, 0x2c, + 0x1a, 0xa8, 0x7d, 0x22, 0xa4, 0xff, 0x2b, 0xcd, 0x61, 0x34, 0x97, 0x6d, 0xa1, 0x49, 0xeb, 0x4a + }, // SHA256("Noise_IKhfselg2_25519+MLKEM1024_ChaChaPoly_SHA256") + std::array + { + 0x42, 0x0d, 0xc2, 0x1c, 0x7b, 0x18, 0x61, 0xb7, 0x4a, 0x04, 0x3d, 0xae, 0x0f, 0xdc, 0xf2, 0x71, + 0xb9, 0xba, 0x19, 0xbb, 0xbd, 0x5f, 0xd4, 0x9c, 0x3f, 0x4b, 0x01, 0xed, 0x6d, 0x13, 0x1d, 0xa2 + } // SHA256 (first) + ) }; void InitNoiseIKStateMLKEM (NoiseSymmetricState& state, i2p::data::CryptoKeyType type, const uint8_t * pub) From f6c93f734569e778ab1873ce47de4498dea28611 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Apr 2025 15:40:09 -0400 Subject: [PATCH 774/787] common LocalEncryptionKey to pass to loacl LeaseSet --- libi2pd/CryptoKey.cpp | 16 ++++++++++++++++ libi2pd/CryptoKey.h | 11 +++++++++++ libi2pd/Destination.cpp | 10 +++++----- libi2pd/Destination.h | 19 ++----------------- libi2pd/LeaseSet.cpp | 10 +++++----- libi2pd/LeaseSet.h | 11 ++++------- 6 files changed, 43 insertions(+), 34 deletions(-) diff --git a/libi2pd/CryptoKey.cpp b/libi2pd/CryptoKey.cpp index bac5d740..e37d4039 100644 --- a/libi2pd/CryptoKey.cpp +++ b/libi2pd/CryptoKey.cpp @@ -181,5 +181,21 @@ namespace crypto k.GetPrivateKey (priv); memcpy (pub, k.GetPublicKey (), 32); } + + LocalEncryptionKey::LocalEncryptionKey (i2p::data::CryptoKeyType t): keyType(t) + { + pub.resize (GetCryptoPublicKeyLen (keyType)); + priv.resize (GetCryptoPrivateKeyLen (keyType)); + } + + void LocalEncryptionKey::GenerateKeys () + { + i2p::data::PrivateKeys::GenerateCryptoKeyPair (keyType, priv.data (), pub.data ()); + } + + void LocalEncryptionKey::CreateDecryptor () + { + decryptor = i2p::data::PrivateKeys::CreateDecryptor (keyType, priv.data ()); + } } } diff --git a/libi2pd/CryptoKey.h b/libi2pd/CryptoKey.h index 657a6a91..b6c37ddf 100644 --- a/libi2pd/CryptoKey.h +++ b/libi2pd/CryptoKey.h @@ -191,6 +191,17 @@ namespace crypto }; return 0; } + + struct LocalEncryptionKey + { + std::vector pub, priv; + i2p::data::CryptoKeyType keyType; + std::shared_ptr decryptor; + + LocalEncryptionKey (i2p::data::CryptoKeyType t); + void GenerateKeys (); + void CreateDecryptor (); + }; } } diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index a3f6a8c9..b23d31ed 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1047,7 +1047,7 @@ namespace client for (auto& it: encryptionKeyTypes) { - auto encryptionKey = std::make_shared (it); + auto encryptionKey = std::make_shared (it); if (IsPublic ()) PersistTemporaryKeys (encryptionKey); else @@ -1405,7 +1405,7 @@ namespace client return ret; } - void ClientDestination::PersistTemporaryKeys (std::shared_ptr keys) + void ClientDestination::PersistTemporaryKeys (std::shared_ptr keys) { if (!keys) return; std::string ident = GetIdentHash().ToBase32(); @@ -1475,9 +1475,9 @@ namespace client else { // standard LS2 (type 3) first - i2p::data::LocalLeaseSet2::KeySections keySections; + i2p::data::LocalLeaseSet2::EncryptionKeys keySections; for (const auto& it: m_EncryptionKeys) - keySections.push_back ({it.first, (uint16_t)it.second->pub.size (), it.second->pub.data ()} ); + keySections.push_back (it.second); auto publishedTimestamp = i2p::util::GetSecondsSinceEpoch (); if (publishedTimestamp <= m_LastPublishedTimestamp) @@ -1503,7 +1503,7 @@ namespace client bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const { - std::shared_ptr encryptionKey; + std::shared_ptr encryptionKey; if (!m_EncryptionKeys.empty ()) { if (m_EncryptionKeys.rbegin ()->first == preferredCrypto) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index a76a1be4..33e8bf08 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -230,21 +230,6 @@ namespace client class ClientDestination: public LeaseSetDestination { - struct EncryptionKey - { - std::vector pub, priv; - i2p::data::CryptoKeyType keyType; - std::shared_ptr decryptor; - - EncryptionKey (i2p::data::CryptoKeyType t): keyType(t) - { - pub.resize (i2p::crypto::GetCryptoPublicKeyLen (keyType)); - priv.resize (i2p::crypto::GetCryptoPrivateKeyLen (keyType)); - } - void GenerateKeys () { i2p::data::PrivateKeys::GenerateCryptoKeyPair (keyType, priv.data (), pub.data ()); }; - void CreateDecryptor () { decryptor = i2p::data::PrivateKeys::CreateDecryptor (keyType, priv.data ()); }; - }; - public: ClientDestination (boost::asio::io_context& service, const i2p::data::PrivateKeys& keys, @@ -310,7 +295,7 @@ namespace client std::shared_ptr GetSharedFromThis () { return std::static_pointer_cast(shared_from_this ()); } - void PersistTemporaryKeys (std::shared_ptr keys); + void PersistTemporaryKeys (std::shared_ptr keys); void ReadAuthKey (const std::string& group, const std::map * params); template @@ -319,7 +304,7 @@ namespace client private: i2p::data::PrivateKeys m_Keys; - std::map > m_EncryptionKeys; // last is most preferable + std::map > m_EncryptionKeys; // last is most preferable i2p::data::CryptoKeyType m_PreferredCryptoType; int m_StreamingAckDelay,m_StreamingOutboundSpeed, m_StreamingInboundSpeed, m_StreamingMaxConcurrentStreams; diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index db8c1aad..fc0e722d 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -848,7 +848,7 @@ namespace data } LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, - const KeySections& encryptionKeys, const std::vector >& tunnels, + const EncryptionKeys& encryptionKeys, const std::vector >& tunnels, bool isPublic, uint64_t publishedTimestamp, bool isPublishedEncrypted): LocalLeaseSet (keys.GetPublic (), nullptr, 0) { @@ -858,7 +858,7 @@ namespace data if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES; size_t keySectionsLen = 0; for (const auto& it: encryptionKeys) - keySectionsLen += 2/*key type*/ + 2/*key len*/ + it.keyLen/*key*/; + keySectionsLen += 2/*key type*/ + 2/*key len*/ + it->pub.size()/*key*/; m_BufferLen = identity->GetFullLen () + 4/*published*/ + 2/*expires*/ + 2/*flag*/ + 2/*properties len*/ + 1/*num keys*/ + keySectionsLen + 1/*num leases*/ + num*LEASE2_SIZE + keys.GetSignatureLen (); uint16_t flags = 0; @@ -893,9 +893,9 @@ namespace data m_Buffer[offset] = encryptionKeys.size (); offset++; // 1 key for (const auto& it: encryptionKeys) { - htobe16buf (m_Buffer + offset, it.keyType); offset += 2; // key type - htobe16buf (m_Buffer + offset, it.keyLen); offset += 2; // key len - memcpy (m_Buffer + offset, it.encryptionPublicKey, it.keyLen); offset += it.keyLen; // key + htobe16buf (m_Buffer + offset, it->keyType); offset += 2; // key type + htobe16buf (m_Buffer + offset, it->pub.size()); offset += 2; // key len + memcpy (m_Buffer + offset, it->pub.data(), it->pub.size()); offset += it->pub.size(); // key } // leases uint32_t expirationTime = 0; // in seconds diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index 1a89229a..3594083c 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -12,12 +12,14 @@ #include #include #include +#include #include #include #include "Identity.h" #include "Timestamp.h" #include "I2PEndian.h" #include "Blinding.h" +#include "CryptoKey.h" namespace i2p { @@ -247,15 +249,10 @@ namespace data { public: - struct KeySection - { - uint16_t keyType, keyLen; - const uint8_t * encryptionPublicKey; - }; - typedef std::vector KeySections; + typedef std::list > EncryptionKeys; LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, - const KeySections& encryptionKeys, + const EncryptionKeys& encryptionKeys, const std::vector >& tunnels, bool isPublic, uint64_t publishedTimestamp, bool isPublishedEncrypted = false); From e69b56c4e37bfc5df155b54c912660363a6649b1 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Apr 2025 16:44:01 -0400 Subject: [PATCH 775/787] publish preferred key first --- libi2pd/Destination.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index b23d31ed..3d910e54 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1475,10 +1475,27 @@ namespace client else { // standard LS2 (type 3) first + if (m_EncryptionKeys.empty ()) + { + LogPrint (eLogError, "Destinations: No encryption keys"); + return; + } + i2p::data::LocalLeaseSet2::EncryptionKeys keySections; - for (const auto& it: m_EncryptionKeys) - keySections.push_back (it.second); - + std::shared_ptr preferredSection; + if (m_EncryptionKeys.size () == 1) + preferredSection = m_EncryptionKeys.begin ()->second; // only key + else + { + for (const auto& it: m_EncryptionKeys) + if (it.first == m_PreferredCryptoType) + preferredSection = it.second; + else + keySections.push_back (it.second); + } + if (preferredSection) + keySections.push_front (preferredSection); // make preferred first + auto publishedTimestamp = i2p::util::GetSecondsSinceEpoch (); if (publishedTimestamp <= m_LastPublishedTimestamp) { From 1c162f9fd5b0507feb12f2d9cf0f8cada522597b Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Apr 2025 21:59:10 -0400 Subject: [PATCH 776/787] get preferred crypto key type from ratchets session --- libi2pd/Destination.cpp | 18 ++++++++++++------ libi2pd/Destination.h | 5 +++-- libi2pd/ECIESX25519AEADRatchetSession.cpp | 4 ++-- libi2pd/ECIESX25519AEADRatchetSession.h | 1 + libi2pd/Garlic.cpp | 5 +++-- libi2pd/Garlic.h | 5 +++-- 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 3d910e54..f89fc0f0 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -13,6 +13,7 @@ #include #include #include "Crypto.h" +#include "ECIESX25519AEADRatchetSession.h" #include "Log.h" #include "FS.h" #include "Timestamp.h" @@ -377,10 +378,12 @@ namespace client { I2NPMessageType typeID = (I2NPMessageType)(buf[I2NP_HEADER_TYPEID_OFFSET]); uint32_t msgID = bufbe32toh (buf + I2NP_HEADER_MSGID_OFFSET); - LeaseSetDestination::HandleCloveI2NPMessage (typeID, buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE, msgID); + LeaseSetDestination::HandleCloveI2NPMessage (typeID, buf + I2NP_HEADER_SIZE, + GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE, msgID, nullptr); } - bool LeaseSetDestination::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) + bool LeaseSetDestination::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, + size_t len, uint32_t msgID, i2p::garlic::ECIESX25519AEADRatchetSession * from) { switch (typeID) { @@ -395,7 +398,7 @@ namespace client m_Pool->ProcessTunnelTest (bufbe32toh (payload + TUNNEL_TEST_MSGID_OFFSET), bufbe64toh (payload + TUNNEL_TEST_TIMESTAMP_OFFSET)); break; case eI2NPDatabaseStore: - HandleDatabaseStoreMessage (payload, len); + HandleDatabaseStoreMessage (payload, len, from); break; case eI2NPDatabaseSearchReply: HandleDatabaseSearchReplyMessage (payload, len); @@ -410,7 +413,8 @@ namespace client return true; } - void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len) + void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len, + i2p::garlic::ECIESX25519AEADRatchetSession * from) { if (len < DATABASE_STORE_HEADER_SIZE) { @@ -465,7 +469,8 @@ namespace client if (buf[DATABASE_STORE_TYPE_OFFSET] == i2p::data::NETDB_STORE_TYPE_LEASESET) leaseSet = std::make_shared (buf + offset, len - offset); // LeaseSet else - leaseSet = std::make_shared (buf[DATABASE_STORE_TYPE_OFFSET], buf + offset, len - offset, true, GetPreferredCryptoType () ); // LeaseSet2 + leaseSet = std::make_shared (buf[DATABASE_STORE_TYPE_OFFSET], + buf + offset, len - offset, true, from ? from->GetRemoteStaticKeyType () : GetPreferredCryptoType () ); // LeaseSet2 if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key && !leaseSet->IsExpired ()) { if (leaseSet->GetIdentHash () != GetIdentHash ()) @@ -494,7 +499,8 @@ namespace client if (request->requestedBlindedKey) { auto ls2 = std::make_shared (buf + offset, len - offset, - request->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr , GetPreferredCryptoType ()); + request->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr, + from ? from->GetRemoteStaticKeyType () : GetPreferredCryptoType ()); if (ls2->IsValid () && !ls2->IsExpired ()) { leaseSet = ls2; diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 33e8bf08..abb63af2 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -164,7 +164,8 @@ namespace client // implements GarlicDestination void HandleI2NPMessage (const uint8_t * buf, size_t len) override; - bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) override; + bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, + size_t len, uint32_t msgID, i2p::garlic::ECIESX25519AEADRatchetSession * from) override; void SetLeaseSet (std::shared_ptr newLeaseSet); int GetLeaseSetType () const { return m_LeaseSetType; }; @@ -184,7 +185,7 @@ namespace client void HandlePublishConfirmationTimer (const boost::system::error_code& ecode); void HandlePublishVerificationTimer (const boost::system::error_code& ecode); void HandlePublishDelayTimer (const boost::system::error_code& ecode); - void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len); + void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from); void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len); void HandleDeliveryStatusMessage (uint32_t msgID); diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index d38abd13..266caeaa 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -163,7 +163,7 @@ namespace garlic return false; } if (m_Destination) - m_Destination->HandleECIESx25519GarlicClove (buf + offset, size); + m_Destination->HandleECIESx25519GarlicClove (buf + offset, size, nullptr); return true; } @@ -390,7 +390,7 @@ namespace garlic { case eECIESx25519BlkGalicClove: if (GetOwner ()) - GetOwner ()->HandleECIESx25519GarlicClove (buf + offset, size); + GetOwner ()->HandleECIESx25519GarlicClove (buf + offset, size, this); break; case eECIESx25519BlkNextKey: LogPrint (eLogDebug, "Garlic: Next key"); diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index b7704534..1b810cd0 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -170,6 +170,7 @@ namespace garlic std::shared_ptr WrapOneTimeMessage (std::shared_ptr msg); const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } + i2p::data::CryptoKeyType GetRemoteStaticKeyType () const { return m_RemoteStaticKeyType; } void SetRemoteStaticKey (i2p::data::CryptoKeyType keyType, const uint8_t * key) { m_RemoteStaticKeyType = keyType; diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 5a3e4cae..3675b0b0 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -1003,7 +1003,8 @@ namespace garlic i2p::fs::Remove (it); } - void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len) + void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len, + ECIESX25519AEADRatchetSession * from) { const uint8_t * buf1 = buf; uint8_t flag = buf[0]; buf++; // flag @@ -1023,7 +1024,7 @@ namespace garlic buf += 4; // expiration ptrdiff_t offset = buf - buf1; if (offset <= (int)len) - HandleCloveI2NPMessage (typeID, buf, len - offset, msgID); + HandleCloveI2NPMessage (typeID, buf, len - offset, msgID, from); else LogPrint (eLogError, "Garlic: Clove is too long"); break; diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 0eef4871..dc6b9bba 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -257,7 +257,7 @@ namespace garlic uint64_t AddECIESx25519SessionNextTag (ReceiveRatchetTagSetPtr tagset); void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session); void RemoveECIESx25519Session (const uint8_t * staticKey); - void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len); + void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len, ECIESX25519AEADRatchetSession * from); uint8_t * GetPayloadBuffer (); virtual void ProcessGarlicMessage (std::shared_ptr msg); @@ -272,7 +272,8 @@ namespace garlic void AddECIESx25519Key (const uint8_t * key, const uint8_t * tag); // one tag bool HandleECIESx25519TagMessage (uint8_t * buf, size_t len); // return true if found virtual void HandleI2NPMessage (const uint8_t * buf, size_t len) = 0; // called from clove only - virtual bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) = 0; + virtual bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, + size_t len, uint32_t msgID, ECIESX25519AEADRatchetSession * from) = 0; void HandleGarlicMessage (std::shared_ptr msg); void HandleDeliveryStatusMessage (uint32_t msgID); From 67fe6faf2d3f1bf54a10129dde60ae0eab33e726 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Apr 2025 22:08:16 -0400 Subject: [PATCH 777/787] get preferred crypto key type from ratchets session --- libi2pd/RouterContext.cpp | 3 ++- libi2pd/RouterContext.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index af90a46a..33fb5487 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -1194,7 +1194,8 @@ namespace i2p i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len))); } - bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) + bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, + size_t len, uint32_t msgID, i2p::garlic::ECIESX25519AEADRatchetSession * from) { if (typeID == eI2NPTunnelTest) { diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index c3336336..754c49da 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -204,7 +204,8 @@ namespace garlic // implements GarlicDestination void HandleI2NPMessage (const uint8_t * buf, size_t len) override; - bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) override; + bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, + size_t len, uint32_t msgID, i2p::garlic::ECIESX25519AEADRatchetSession * from) override; private: From bbfe81cb795da01d8011e94ea814f0349cd7c601 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 17 Apr 2025 22:15:17 -0400 Subject: [PATCH 778/787] handle any incoming post quantum crypto type --- libi2pd/Destination.cpp | 9 ++-- libi2pd/Destination.h | 2 +- libi2pd/ECIESX25519AEADRatchetSession.cpp | 56 ++++++++++------------- libi2pd/Garlic.cpp | 5 +- libi2pd/Garlic.h | 7 ++- libi2pd_client/I2CP.h | 5 +- 6 files changed, 41 insertions(+), 43 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index f89fc0f0..b88865b6 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1556,11 +1556,12 @@ namespace client #endif } - bool ClientDestination::SupportsRatchets () const + i2p::data::CryptoKeyType ClientDestination::GetRatchetsHighestCryptoType () const { - if (m_EncryptionKeys.empty ()) return false; - return m_EncryptionKeys.rbegin ()->first >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; - } + if (m_EncryptionKeys.empty ()) return 0; + auto cryptoType = m_EncryptionKeys.rbegin ()->first; + return cryptoType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? cryptoType : 0; + } const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const { diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index abb63af2..35557859 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -283,7 +283,7 @@ namespace client protected: // GarlicDestionation - bool SupportsRatchets () const override; + i2p::data::CryptoKeyType GetRatchetsHighestCryptoType () const override; // LeaseSetDestination void CleanupDestination () override; i2p::data::CryptoKeyType GetPreferredCryptoType () const override { return m_PreferredCryptoType; } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 266caeaa..7436e775 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -266,40 +266,40 @@ namespace garlic } buf += 32; len -= 32; - uint64_t n = 0; uint8_t sharedSecret[32]; bool decrypted = false; + auto cryptoType = GetOwner ()->GetRatchetsHighestCryptoType (); #if OPENSSL_PQ - if (GetOwner ()->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)) + if (cryptoType > i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // we support post quantum { - i2p::crypto::InitNoiseIKStateMLKEM (GetNoiseState (), i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD, - GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)); // bpk + i2p::crypto::InitNoiseIKStateMLKEM (GetNoiseState (), cryptoType, GetOwner ()->GetEncryptionPublicKey (cryptoType)); // bpk MixHash (m_Aepk, 32); // h = SHA256(h || aepk) - if (GetOwner ()->Decrypt (m_Aepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)) // x25519(bsk, aepk) + if (GetOwner ()->Decrypt (m_Aepk, sharedSecret, cryptoType)) // x25519(bsk, aepk) { MixKey (sharedSecret); - - uint8_t nonce[12], encapsKey[i2p::crypto::MLKEM512_KEY_LENGTH]; - CreateNonce (n, nonce); - if (Decrypt (buf, encapsKey, i2p::crypto::MLKEM512_KEY_LENGTH)) + + auto keyLen = i2p::crypto::GetMLKEMPublicKeyLen (cryptoType); + std::vector encapsKey(keyLen); + if (Decrypt (buf, encapsKey.data (), keyLen)) { decrypted = true; // encaps section has right hash - MixHash (buf, i2p::crypto::MLKEM512_KEY_LENGTH + 16); - buf += i2p::crypto::MLKEM512_KEY_LENGTH + 16; - len -= i2p::crypto::MLKEM512_KEY_LENGTH + 16; - n++; + MixHash (buf, keyLen + 16); + buf += keyLen + 16; + len -= keyLen + 16; - m_PQKeys = i2p::crypto::CreateMLKEMKeys (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD); - m_PQKeys->SetPublicKey (encapsKey); + m_PQKeys = i2p::crypto::CreateMLKEMKeys (cryptoType); + m_PQKeys->SetPublicKey (encapsKey.data ()); } } } #endif if (!decrypted) { - if (GetOwner ()->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) + if (cryptoType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD || + GetOwner ()->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) { + cryptoType = i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; i2p::crypto::InitNoiseIKState (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk MixHash (m_Aepk, 32); // h = SHA256(h || aepk) @@ -318,8 +318,7 @@ namespace garlic } // decrypt flags/static - uint8_t nonce[12], fs[32]; - CreateNonce (n, nonce); + uint8_t fs[32]; if (!Decrypt (buf, fs, 32)) { LogPrint (eLogWarning, "Garlic: Flags/static section AEAD verification failed "); @@ -332,16 +331,8 @@ namespace garlic bool isStatic = !i2p::data::Tag<32> (fs).IsZero (); if (isStatic) { - // static key, fs is apk -#if OPENSSL_PQ - if (m_PQKeys) - { - SetRemoteStaticKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD, fs); - CreateNonce (0, nonce); // reset nonce - } - else -#endif - SetRemoteStaticKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD, fs); + // static key, fs is apk + SetRemoteStaticKey (cryptoType, fs); if (!GetOwner ()->Decrypt (fs, sharedSecret, m_RemoteStaticKeyType)) // x25519(bsk, apk) { LogPrint (eLogWarning, "Garlic: Incorrect Alice static key"); @@ -349,8 +340,6 @@ namespace garlic } MixKey (sharedSecret); } - else // all zeros flags - CreateNonce (1, nonce); // decrypt payload std::vector payload (len - 16); // we must save original ciphertext @@ -966,7 +955,8 @@ namespace garlic size_t len = CreatePayload (msg, m_State != eSessionStateEstablished, payload); if (!len) return nullptr; #if OPENSSL_PQ - auto m = NewI2NPMessage (len + (m_State == eSessionStateEstablished ? 28 : i2p::crypto::MLKEM512_KEY_LENGTH + 116)); + auto m = NewI2NPMessage (len + (m_State == eSessionStateEstablished ? 28 : + i2p::crypto::GetMLKEMPublicKeyLen (m_RemoteStaticKeyType) + 116)); #else auto m = NewI2NPMessage (len + 100); // 96 + 4 #endif @@ -994,8 +984,8 @@ namespace garlic return nullptr; len += 72; #if OPENSSL_PQ - if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) - len += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; + if (m_RemoteStaticKeyType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) + len += i2p::crypto::GetMLKEMPublicKeyLen (m_RemoteStaticKeyType) + 16; #endif break; case eSessionStateNewSessionReplySent: diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 3675b0b0..8c8602e8 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -498,7 +498,8 @@ namespace garlic buf += 4; // length bool found = false; - if (SupportsRatchets ()) + bool supportsRatchets = SupportsRatchets (); + if (supportsRatchets) // try ECIESx25519 tag found = HandleECIESx25519TagMessage (buf, length); if (!found) @@ -535,7 +536,7 @@ namespace garlic decryption->Decrypt(buf + 514, length - 514, iv, buf + 514); HandleAESBlock (buf + 514, length - 514, decryption, msg->from); } - else if (SupportsRatchets ()) + else if (supportsRatchets) { // otherwise ECIESx25519 auto ts = i2p::util::GetMillisecondsSinceEpoch (); diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index dc6b9bba..25106c45 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -266,6 +266,10 @@ namespace garlic virtual std::shared_ptr GetLeaseSet () = 0; // TODO virtual std::shared_ptr GetTunnelPool () const = 0; + virtual i2p::data::CryptoKeyType GetRatchetsHighestCryptoType () const + { + return GetIdentity ()->GetCryptoKeyType () >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? GetIdentity ()->GetCryptoKeyType () : 0; + } protected: @@ -279,11 +283,10 @@ namespace garlic void SaveTags (); void LoadTags (); - - virtual bool SupportsRatchets () const { return GetIdentity ()->GetCryptoKeyType () >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; } private: + bool SupportsRatchets () const { return GetRatchetsHighestCryptoType () > 0; } void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr decryption, std::shared_ptr from); void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr from); diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 84243e6f..37c14dbb 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -109,7 +109,10 @@ namespace client protected: // GarlicDestination - bool SupportsRatchets () const override { return (bool)m_ECIESx25519Decryptor; } + i2p::data::CryptoKeyType GetRatchetsHighestCryptoType () const override + { + return m_ECIESx25519Decryptor ? i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD : 0; + } // LeaseSetDestination void CleanupDestination () override; i2p::data::CryptoKeyType GetPreferredCryptoType () const override; From 58818514e783d76654dab4d5a6aa171912a03fab Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 17 Apr 2025 22:34:39 -0400 Subject: [PATCH 779/787] correct NSR size --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 7436e775..87c99d51 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -985,13 +985,17 @@ namespace garlic len += 72; #if OPENSSL_PQ if (m_RemoteStaticKeyType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) - len += i2p::crypto::GetMLKEMPublicKeyLen (m_RemoteStaticKeyType) + 16; + len += i2p::crypto::GetMLKEMCipherTextLen (m_RemoteStaticKeyType) + 16; #endif break; case eSessionStateNewSessionReplySent: if (!NextNewSessionReplyMessage (payload, len, buf, m->maxLen)) return nullptr; len += 72; +#if OPENSSL_PQ + if (m_RemoteStaticKeyType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) + len += i2p::crypto::GetMLKEMCipherTextLen (m_RemoteStaticKeyType) + 16; +#endif break; case eSessionStateOneTime: if (!NewOutgoingSessionMessage (payload, len, buf, m->maxLen, false)) From 9b967059ada5c1acfd49d75466bd99c58085135d Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 18 Apr 2025 21:52:44 +0300 Subject: [PATCH 780/787] [gha] Update docker containers build --- .github/workflows/docker.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 34923f31..c6d55664 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -108,7 +108,7 @@ jobs: uses: Noelware/docker-manifest-action@master with: inputs: purplei2p/i2pd:latest - images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7 + tags: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7 push: true - name: Create and push latest manifest image to GHCR @@ -116,7 +116,7 @@ jobs: uses: Noelware/docker-manifest-action@master with: inputs: ghcr.io/purplei2p/i2pd:latest - images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7 + tags: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7 push: true - name: Store release version to env @@ -128,7 +128,7 @@ jobs: uses: Noelware/docker-manifest-action@master with: inputs: purplei2p/i2pd:latest,purplei2p/i2pd:latest-release,purplei2p/i2pd:release-${{ env.RELEASE_VERSION }} - images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7 + tags: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7 push: true - name: Create and push release manifest to GHCR @@ -136,5 +136,5 @@ jobs: uses: Noelware/docker-manifest-action@master with: inputs: ghcr.io/purplei2p/i2pd:latest,ghcr.io/purplei2p/i2pd:latest-release,ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }} - images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7 + tags: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7 push: true From 2afdd5b723ca55151aad7a71ffc817bacaf8381b Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 19 Apr 2025 12:33:09 -0400 Subject: [PATCH 781/787] cleanup NSR keys --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 25 +++++++++++++++++++---- libi2pd/ECIESX25519AEADRatchetSession.h | 7 ++++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 87c99d51..08af4be3 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -95,6 +95,17 @@ namespace garlic m_ItermediateSymmKeys.erase (index); } + ReceiveRatchetTagSet::ReceiveRatchetTagSet (std::shared_ptr session, bool isNS): + m_Session (session), m_IsNS (isNS) + { + } + + ReceiveRatchetTagSet::~ReceiveRatchetTagSet () + { + if (m_IsNS && m_Session) + m_Session->CleanupReceiveNSRKeys (); + } + void ReceiveRatchetTagSet::Expire () { if (!m_ExpirationTimestamp) @@ -252,6 +263,14 @@ namespace garlic } return false; } + + void ECIESX25519AEADRatchetSession::CleanupReceiveNSRKeys () + { + m_EphemeralKeys = nullptr; +#if OPENSSL_PQ + m_PQKeys = nullptr; +#endif + } bool ECIESX25519AEADRatchetSession::HandleNewIncomingSession (const uint8_t * buf, size_t len) { @@ -824,10 +843,8 @@ namespace garlic if (m_State == eSessionStateNewSessionSent) { m_State = eSessionStateEstablished; - //m_EphemeralKeys = nullptr; // TODO: delete after a while -#if OPENSSL_PQ - // m_PQKeys = nullptr; // TODO: delete after a while -#endif + // don't delete m_EpehemralKey and m_PQKeys because delayd NSR's migth come + // done in CleanupReceiveNSRKeys called from NSR tagset destructor m_SessionCreatedTimestamp = i2p::util::GetSecondsSinceEpoch (); GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 1b810cd0..fd9cc45d 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -81,8 +81,8 @@ namespace garlic { public: - ReceiveRatchetTagSet (std::shared_ptr session, bool isNS = false): - m_Session (session), m_IsNS (isNS) {}; + ReceiveRatchetTagSet (std::shared_ptr session, bool isNS = false); + ~ReceiveRatchetTagSet () override; bool IsNS () const { return m_IsNS; }; std::shared_ptr GetSession () { return m_Session; }; @@ -184,7 +184,8 @@ namespace garlic bool CheckExpired (uint64_t ts); // true is expired bool CanBeRestarted (uint64_t ts) const { return ts > m_SessionCreatedTimestamp + ECIESX25519_RESTART_TIMEOUT; } bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); } - + void CleanupReceiveNSRKeys (); // called from ReceiveRatchetTagSet at Alice's side + bool IsRatchets () const override { return true; }; bool IsReadyToSend () const override { return m_State != eSessionStateNewSessionSent; }; bool IsTerminated () const override { return m_IsTerminated; } From 9bd2b8df761c36c59361d0946d6b190e78dee57b Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 20 Apr 2025 18:53:21 -0400 Subject: [PATCH 782/787] create and handle ML-DSA identities and signatures --- libi2pd/Identity.cpp | 109 +++++++++++++++++++++++++++++++------------ libi2pd/Identity.h | 10 ++-- libi2pd/LeaseSet.h | 2 +- 3 files changed, 88 insertions(+), 33 deletions(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 798d9505..de84b53b 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -127,6 +127,7 @@ namespace data excessLen = i2p::crypto::MLDSA44_PUBLIC_KEY_LENGTH - 384; excessBuf = new uint8_t[excessLen]; memcpy (excessBuf, signingKey + 384, excessLen); + cryptoType = 0xFF; // crypto key is not used break; } #endif @@ -142,12 +143,15 @@ namespace data htobe16buf (m_ExtendedBuffer + 2, cryptoType); if (excessLen && excessBuf) { - if (excessLen > MAX_EXTENDED_BUFFER_SIZE - 4) + if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) { - LogPrint (eLogError, "Identity: Unexpected excessive signing key len ", excessLen); - excessLen = MAX_EXTENDED_BUFFER_SIZE - 4; + auto newBuf = new uint8_t[m_ExtendedLen]; + memcpy (newBuf, m_ExtendedBuffer, 4); + memcpy (newBuf + 4, excessBuf, excessLen); + m_ExtendedBufferPtr = newBuf; } - memcpy (m_ExtendedBuffer + 4, excessBuf, excessLen); + else + memcpy (m_ExtendedBuffer + 4, excessBuf, excessLen); delete[] excessBuf; } // calculate ident hash @@ -195,6 +199,8 @@ namespace data IdentityEx::~IdentityEx () { + if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) + delete[] m_ExtendedBufferPtr; } IdentityEx& IdentityEx::operator=(const IdentityEx& other) @@ -202,11 +208,29 @@ namespace data memcpy (&m_StandardIdentity, &other.m_StandardIdentity, DEFAULT_IDENTITY_SIZE); m_IdentHash = other.m_IdentHash; + size_t oldLen = m_ExtendedLen; m_ExtendedLen = other.m_ExtendedLen; if (m_ExtendedLen > 0) { - if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE; - memcpy (m_ExtendedBuffer, other.m_ExtendedBuffer, m_ExtendedLen); + if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) + { + if (oldLen > MAX_EXTENDED_BUFFER_SIZE) + { + if (m_ExtendedLen > oldLen) + { + delete[] m_ExtendedBufferPtr; + m_ExtendedBufferPtr = new uint8_t[m_ExtendedLen]; + } + } + else + m_ExtendedBufferPtr = new uint8_t[m_ExtendedLen]; + memcpy (m_ExtendedBufferPtr, other.m_ExtendedBufferPtr, m_ExtendedLen); + } + else + { + if (oldLen > MAX_EXTENDED_BUFFER_SIZE) delete[] m_ExtendedBufferPtr; + memcpy (m_ExtendedBuffer, other.m_ExtendedBuffer, m_ExtendedLen); + } } m_Verifier = nullptr; CreateVerifier (); @@ -235,13 +259,28 @@ namespace data } memcpy (&m_StandardIdentity, buf, DEFAULT_IDENTITY_SIZE); + size_t oldLen = m_ExtendedLen; m_ExtendedLen = bufbe16toh (m_StandardIdentity.certificate + 1); if (m_ExtendedLen) { if (m_ExtendedLen + DEFAULT_IDENTITY_SIZE <= len) { - if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE; - memcpy (m_ExtendedBuffer, buf + DEFAULT_IDENTITY_SIZE, m_ExtendedLen); + if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) + { + if (oldLen > MAX_EXTENDED_BUFFER_SIZE) + { + if (m_ExtendedLen > oldLen) + { + delete[] m_ExtendedBufferPtr; + m_ExtendedBufferPtr = new uint8_t[m_ExtendedLen]; + } + } + else + m_ExtendedBufferPtr = new uint8_t[m_ExtendedLen]; + memcpy (m_ExtendedBufferPtr, buf + DEFAULT_IDENTITY_SIZE, m_ExtendedLen); + } + else + memcpy (m_ExtendedBuffer, buf + DEFAULT_IDENTITY_SIZE, m_ExtendedLen); } else { @@ -266,7 +305,12 @@ namespace data if (fullLen > len) return 0; // buffer is too small and may overflow somewhere else memcpy (buf, &m_StandardIdentity, DEFAULT_IDENTITY_SIZE); if (m_ExtendedLen > 0) - memcpy (buf + DEFAULT_IDENTITY_SIZE, m_ExtendedBuffer, m_ExtendedLen); + { + if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) + memcpy (buf + DEFAULT_IDENTITY_SIZE, m_ExtendedBufferPtr, m_ExtendedLen); + else + memcpy (buf + DEFAULT_IDENTITY_SIZE, m_ExtendedBuffer, m_ExtendedLen); + } return fullLen; } @@ -295,7 +339,7 @@ namespace data const uint8_t * IdentityEx::GetSigningPublicKeyBuffer () const { auto keyLen = GetSigningPublicKeyLen (); - if (keyLen > 128) return nullptr; // P521 + if (keyLen > 128) return nullptr; // P521 or PQ return m_StandardIdentity.signingKey + 128 - keyLen; } @@ -322,7 +366,7 @@ namespace data SigningKeyType IdentityEx::GetSigningKeyType () const { if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedLen >= 2) - return bufbe16toh (m_ExtendedBuffer); // signing key + return bufbe16toh (m_ExtendedLen <= MAX_EXTENDED_BUFFER_SIZE ? m_ExtendedBuffer : m_ExtendedBufferPtr); // signing key return SIGNING_KEY_TYPE_DSA_SHA1; } @@ -335,7 +379,7 @@ namespace data CryptoKeyType IdentityEx::GetCryptoKeyType () const { if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedLen >= 4) - return bufbe16toh (m_ExtendedBuffer + 2); // crypto key + return bufbe16toh (m_ExtendedLen <= MAX_EXTENDED_BUFFER_SIZE ? m_ExtendedBuffer + 2 : m_ExtendedBufferPtr + 2); // crypto key return CRYPTO_KEY_TYPE_ELGAMAL; } @@ -359,7 +403,7 @@ namespace data return new i2p::crypto::GOSTR3410_512_Verifier (i2p::crypto::eGOSTR3410TC26A512); case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: return new i2p::crypto::RedDSA25519Verifier (); -#if OPENSSL_PQ +#if OPENSSL_PQ case SIGNING_KEY_TYPE_MLDSA44: return new i2p::crypto::MLDSA44Verifier (); #endif @@ -391,7 +435,7 @@ namespace data uint8_t * signingKey = new uint8_t[keyLen]; memcpy (signingKey, m_StandardIdentity.signingKey, 384); size_t excessLen = keyLen - 384; - memcpy (signingKey + 384, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types + memcpy (signingKey + 384, m_ExtendedBufferPtr + 4, excessLen); // right after signing and crypto key types verifier->SetPublicKey (signingKey); delete[] signingKey; } @@ -451,7 +495,9 @@ namespace data { m_Public = std::make_shared(Identity (keys)); memcpy (m_PrivateKey, keys.privateKey, 256); // 256 - memcpy (m_SigningPrivateKey, keys.signingPrivateKey, m_Public->GetSigningPrivateKeyLen ()); + size_t keyLen = m_Public->GetSigningPrivateKeyLen (); + if (keyLen > 128) m_SigningPrivateKey.resize (keyLen); + memcpy (m_SigningPrivateKey.data (), keys.signingPrivateKey, keyLen); m_OfflineSignature.resize (0); m_TransientSignatureLen = 0; m_TransientSigningPrivateKeyLen = 0; @@ -467,7 +513,7 @@ namespace data m_OfflineSignature = other.m_OfflineSignature; m_TransientSignatureLen = other.m_TransientSignatureLen; m_TransientSigningPrivateKeyLen = other.m_TransientSigningPrivateKeyLen; - memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, m_TransientSigningPrivateKeyLen > 0 ? m_TransientSigningPrivateKeyLen : m_Public->GetSigningPrivateKeyLen ()); + m_SigningPrivateKey = other.m_SigningPrivateKey; m_Signer = nullptr; CreateSigner (); return *this; @@ -490,8 +536,9 @@ namespace data memcpy (m_PrivateKey, buf + ret, cryptoKeyLen); ret += cryptoKeyLen; size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen (); - if(signingPrivateKeySize + ret > len || signingPrivateKeySize > 128) return 0; // overflow - memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize); + if (signingPrivateKeySize + ret > len) return 0; // overflow + m_SigningPrivateKey.resize (signingPrivateKeySize); + memcpy (m_SigningPrivateKey.data (), buf + ret, signingPrivateKeySize); ret += signingPrivateKeySize; m_Signer = nullptr; // check if signing private key is all zeros @@ -532,8 +579,9 @@ namespace data memcpy (m_OfflineSignature.data (), offlineInfo, offlineInfoLen); // override signing private key m_TransientSigningPrivateKeyLen = transientVerifier->GetPrivateKeyLen (); - if (m_TransientSigningPrivateKeyLen + ret > len || m_TransientSigningPrivateKeyLen > 128) return 0; - memcpy (m_SigningPrivateKey, buf + ret, m_TransientSigningPrivateKeyLen); + if (m_TransientSigningPrivateKeyLen + ret > len) return 0; + if (m_TransientSigningPrivateKeyLen > 128) m_SigningPrivateKey.resize (m_TransientSigningPrivateKeyLen); + memcpy (m_SigningPrivateKey.data (), buf + ret, m_TransientSigningPrivateKeyLen); ret += m_TransientSigningPrivateKeyLen; CreateSigner (keyType); } @@ -553,7 +601,7 @@ namespace data if (IsOfflineSignature ()) memset (buf + ret, 0, signingPrivateKeySize); else - memcpy (buf + ret, m_SigningPrivateKey, signingPrivateKeySize); + memcpy (buf + ret, m_SigningPrivateKey.data (), signingPrivateKeySize); ret += signingPrivateKeySize; if (IsOfflineSignature ()) { @@ -564,7 +612,7 @@ namespace data ret += offlineSignatureLen; // transient private key if (ret + m_TransientSigningPrivateKeyLen > len) return 0; - memcpy (buf + ret, m_SigningPrivateKey, m_TransientSigningPrivateKeyLen); + memcpy (buf + ret, m_SigningPrivateKey.data (), m_TransientSigningPrivateKeyLen); ret += m_TransientSigningPrivateKeyLen; } return ret; @@ -603,13 +651,13 @@ namespace data { if (m_Signer) return; if (keyType == SIGNING_KEY_TYPE_DSA_SHA1) - m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey)); + m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey.data (), m_Public->GetStandardIdentity ().signingKey)); else if (keyType == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 && !IsOfflineSignature ()) - m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey + (sizeof(Identity::signingKey) - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH))); // TODO: remove public key check + m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey.data (), m_Public->GetStandardIdentity ().signingKey + (sizeof(Identity::signingKey) - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH))); // TODO: remove public key check else { // public key is not required - auto signer = CreateSigner (keyType, m_SigningPrivateKey); + auto signer = CreateSigner (keyType, m_SigningPrivateKey.data ()); if (signer) m_Signer.reset (signer); } } @@ -708,8 +756,10 @@ namespace data { PrivateKeys keys; // signature - uint8_t signingPublicKey[512]; // signing public key is 512 bytes max - GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, signingPublicKey); + std::unique_ptr verifier (IdentityEx::CreateVerifier (type)); + std::vector signingPublicKey(verifier->GetPublicKeyLen ()); + keys.m_SigningPrivateKey.resize (verifier->GetPrivateKeyLen ()); + GenerateSigningKeyPair (type, keys.m_SigningPrivateKey.data (), signingPublicKey.data ()); // encryption uint8_t publicKey[256]; if (isDestination) @@ -717,7 +767,7 @@ namespace data else GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey); // identity - keys.m_Public = std::make_shared (isDestination ? nullptr : publicKey, signingPublicKey, type, cryptoType); + keys.m_Public = std::make_shared (isDestination ? nullptr : publicKey, signingPublicKey.data (), type, cryptoType); keys.CreateSigner (); return keys; @@ -798,9 +848,10 @@ namespace data keys.m_TransientSigningPrivateKeyLen = verifier->GetPrivateKeyLen (); keys.m_TransientSignatureLen = verifier->GetSignatureLen (); keys.m_OfflineSignature.resize (pubKeyLen + m_Public->GetSignatureLen () + 6); + keys.m_SigningPrivateKey.resize (verifier->GetPrivateKeyLen ()); htobe32buf (keys.m_OfflineSignature.data (), expires); // expires htobe16buf (keys.m_OfflineSignature.data () + 4, type); // type - GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, keys.m_OfflineSignature.data () + 6); // public key + GenerateSigningKeyPair (type, keys.m_SigningPrivateKey.data (), keys.m_OfflineSignature.data () + 6); // public key Sign (keys.m_OfflineSignature.data (), pubKeyLen + 6, keys.m_OfflineSignature.data () + 6 + pubKeyLen); // signature // recreate signer keys.m_Signer = nullptr; diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index 173559e9..c95ce000 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -142,7 +142,11 @@ namespace data IdentHash m_IdentHash; std::unique_ptr m_Verifier; size_t m_ExtendedLen; - uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE]; // TODO: support PQ keys + union + { + uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE]; + uint8_t * m_ExtendedBufferPtr; + }; }; size_t GetIdentityBufferLen (const uint8_t * buf, size_t len); // return actual identity length in buffer @@ -160,7 +164,7 @@ namespace data std::shared_ptr GetPublic () const { return m_Public; }; const uint8_t * GetPrivateKey () const { return m_PrivateKey; }; - const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; }; + const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey.data (); }; size_t GetSignatureLen () const; // might not match identity bool IsOfflineSignature () const { return m_TransientSignatureLen > 0; }; uint8_t * GetPadding(); @@ -196,7 +200,7 @@ namespace data std::shared_ptr m_Public; uint8_t m_PrivateKey[256]; - uint8_t m_SigningPrivateKey[128]; // assume private key doesn't exceed 128 bytes + std::vector m_SigningPrivateKey; mutable std::unique_ptr m_Signer; std::vector m_OfflineSignature; // non zero length, if applicable size_t m_TransientSignatureLen = 0; diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index 3594083c..c24c8696 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -60,7 +60,7 @@ namespace data typedef std::function LeaseInspectFunc; - const size_t MAX_LS_BUFFER_SIZE = 3072; + const size_t MAX_LS_BUFFER_SIZE = 4096; const size_t LEASE_SIZE = 44; // 32 + 4 + 8 const size_t LEASE2_SIZE = 40; // 32 + 4 + 4 const uint8_t MAX_NUM_LEASES = 16; From 724d8bde4edf58a2f9a6fc0b32aa6a5839b5ba6d Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 21 Apr 2025 21:25:51 -0400 Subject: [PATCH 783/787] handle incoming packets with ML-DSA signature --- libi2pd/Identity.cpp | 2 +- libi2pd/LeaseSet.h | 5 ++++- libi2pd/Streaming.cpp | 49 +++++++++++++++++++++++++++---------------- libi2pd/Streaming.h | 4 ++++ 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index de84b53b..865beeb8 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -433,7 +433,7 @@ namespace data { // for post-quantum uint8_t * signingKey = new uint8_t[keyLen]; - memcpy (signingKey, m_StandardIdentity.signingKey, 384); + memcpy (signingKey, m_StandardIdentity, 384); size_t excessLen = keyLen - 384; memcpy (signingKey + 384, m_ExtendedBufferPtr + 4, excessLen); // right after signing and crypto key types verifier->SetPublicKey (signingKey); diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index c24c8696..f5197eb5 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -59,8 +59,11 @@ namespace data }; typedef std::function LeaseInspectFunc; - +#if OPENSSL_PQ + const size_t MAX_LS_BUFFER_SIZE = 8192; +#else const size_t MAX_LS_BUFFER_SIZE = 4096; +#endif const size_t LEASE_SIZE = 44; // 32 + 4 + 8 const size_t LEASE2_SIZE = 40; // 32 + 4 + 4 const uint8_t MAX_NUM_LEASES = 16; diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index d21cfa62..99da5fd2 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -450,29 +450,42 @@ namespace stream if (flags & PACKET_FLAG_SIGNATURE_INCLUDED) { - uint8_t signature[256]; + bool verified = false; auto signatureLen = m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : m_RemoteIdentity->GetSignatureLen (); - if(signatureLen <= sizeof(signature)) - { - memcpy (signature, optionData, signatureLen); - memset (const_cast(optionData), 0, signatureLen); - bool verified = m_TransientVerifier ? - m_TransientVerifier->Verify (packet->GetBuffer (), packet->GetLength (), signature) : - m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature); - if (!verified) - { - LogPrint (eLogError, "Streaming: Signature verification failed, sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); - Close (); - flags |= PACKET_FLAG_CLOSE; - } - memcpy (const_cast(optionData), signature, signatureLen); - optionData += signatureLen; - } - else + if (signatureLen > packet->GetLength ()) { LogPrint (eLogError, "Streaming: Signature too big, ", signatureLen, " bytes"); return false; + } + if(signatureLen <= 256) + { + // standard + uint8_t signature[256]; + memcpy (signature, optionData, signatureLen); + memset (const_cast(optionData), 0, signatureLen); + verified = m_TransientVerifier ? + m_TransientVerifier->Verify (packet->GetBuffer (), packet->GetLength (), signature) : + m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature); + if (verified) + memcpy (const_cast(optionData), signature, signatureLen); } + else + { + // post quantum + std::vector signature(signatureLen); + memcpy (signature.data (), optionData, signatureLen); + memset (const_cast(optionData), 0, signatureLen); + verified = m_TransientVerifier ? + m_TransientVerifier->Verify (packet->GetBuffer (), packet->GetLength (), signature.data ()) : + m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature.data ()); + } + if (verified) + optionData += signatureLen; + else + { + LogPrint (eLogError, "Streaming: Signature verification failed, sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); + return false; + } } if (immediateAckRequested) SendQuickAck (); diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 8280477b..8a5c355c 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -51,7 +51,11 @@ namespace stream const size_t STREAMING_MTU = 1730; const size_t STREAMING_MTU_RATCHETS = 1812; +#if OPENSSL_PQ + const size_t MAX_PACKET_SIZE = 8192; +#else const size_t MAX_PACKET_SIZE = 4096; +#endif const size_t COMPRESSION_THRESHOLD_SIZE = 66; const int MAX_NUM_RESEND_ATTEMPTS = 10; const int INITIAL_WINDOW_SIZE = 10; From a5fa4ddb4cb5f0362ab7d763bf20f462e7a7b68b Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 22 Apr 2025 21:21:51 -0400 Subject: [PATCH 784/787] compare LeaseSet's static keys with ratchets session it was received from --- libi2pd/Destination.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index b88865b6..91cc8380 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -469,9 +469,21 @@ namespace client if (buf[DATABASE_STORE_TYPE_OFFSET] == i2p::data::NETDB_STORE_TYPE_LEASESET) leaseSet = std::make_shared (buf + offset, len - offset); // LeaseSet else + { leaseSet = std::make_shared (buf[DATABASE_STORE_TYPE_OFFSET], buf + offset, len - offset, true, from ? from->GetRemoteStaticKeyType () : GetPreferredCryptoType () ); // LeaseSet2 - if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key && !leaseSet->IsExpired ()) + if (from) + { + uint8_t pub[32]; + leaseSet->Encrypt (nullptr, pub); + if (memcmp (from->GetRemoteStaticKey (), pub, 32)) + { + LogPrint (eLogError, "Destination: Remote LeaseSet static key mismatch"); + leaseSet = nullptr; + } + } + } + if (leaseSet && leaseSet->IsValid () && leaseSet->GetIdentHash () == key && !leaseSet->IsExpired ()) { if (leaseSet->GetIdentHash () != GetIdentHash ()) { From 9d44a32e4cf63f2b34f66e428b2911c6a8e3f036 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 24 Apr 2025 16:37:50 -0400 Subject: [PATCH 785/787] fixed #2183. Give more time to close streams after session disconnect if needed --- libi2pd/Streaming.h | 1 + libi2pd_client/SAM.cpp | 50 +++++++++++++++++++++++++++++------------- libi2pd_client/SAM.h | 6 ++++- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 8a5c355c..570fdd1d 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -326,6 +326,7 @@ namespace stream void SendPing (std::shared_ptr remote); void DeleteStream (std::shared_ptr stream); bool DeleteStream (uint32_t recvStreamID); + size_t GetNumStreams () const { return m_Streams.size (); }; void SetAcceptor (const Acceptor& acceptor); void ResetAcceptor (); bool IsAcceptorSet () const { return m_Acceptor != nullptr; }; diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 3114bb5a..2c0f8d92 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -43,23 +43,21 @@ namespace client m_Stream->AsyncClose (); m_Stream = nullptr; } - auto Session = m_Owner.FindSession(m_ID); switch (m_SocketType) { case eSAMSocketTypeSession: m_Owner.CloseSession (m_ID); break; case eSAMSocketTypeStream: - { - break; - } + break; case eSAMSocketTypeAcceptor: case eSAMSocketTypeForward: { - if (Session) + auto session = m_Owner.FindSession(m_ID); + if (session) { - if (m_IsAccepting && Session->GetLocalDestination ()) - Session->GetLocalDestination ()->StopAcceptingStreams (); + if (m_IsAccepting && session->GetLocalDestination ()) + session->GetLocalDestination ()->StopAcceptingStreams (); } break; } @@ -1479,17 +1477,39 @@ namespace client session->StopLocalDestination (); session->Close (); if (m_IsSingleThread) - { - auto timer = std::make_shared(GetService ()); - timer->expires_from_now (boost::posix_time::seconds(5)); // postpone destination clean for 5 seconds - timer->async_wait ([timer, session](const boost::system::error_code& ecode) - { - // session's destructor is called here - }); - } + ScheduleSessionCleanupTimer (session); // let all session's streams close } } + void SAMBridge::ScheduleSessionCleanupTimer (std::shared_ptr session) + { + auto timer = std::make_shared(GetService ()); + timer->expires_from_now (boost::posix_time::seconds(5)); // postpone destination clean for 5 seconds + timer->async_wait (std::bind (&SAMBridge::HandleSessionCleanupTimer, this, std::placeholders::_1, session, timer)); + } + + void SAMBridge::HandleSessionCleanupTimer (const boost::system::error_code& ecode, + std::shared_ptr session, std::shared_ptr timer) + { + if (ecode != boost::asio::error::operation_aborted && session) + { + auto dest = session->GetLocalDestination (); + if (dest) + { + auto streamingDest = dest->GetStreamingDestination (); + auto numStreams = streamingDest->GetNumStreams (); + if (numStreams > 0) + { + LogPrint (eLogInfo, "SAM: Session ", session->Name, " still has ", numStreams, " streams"); + ScheduleSessionCleanupTimer (session); + } + else + LogPrint (eLogDebug, "SAM: Session ", session->Name, " terminated"); + } + } + // session's destructor is called here unless rescheduled + } + std::shared_ptr SAMBridge::FindSession (const std::string& id) const { std::unique_lock l(m_SessionsMutex); diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 10ef4957..1886324a 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2024, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -271,6 +271,10 @@ namespace client void ReceiveDatagram (); void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void ScheduleSessionCleanupTimer (std::shared_ptr session); + void HandleSessionCleanupTimer (const boost::system::error_code& ecode, + std::shared_ptr session, std::shared_ptr timer); + private: bool m_IsSingleThread; From 929ff6e3587332f24deeb89f566f8ae58ac79916 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 26 Apr 2025 08:39:11 -0400 Subject: [PATCH 786/787] encrypted LeaseSet never comes through a session --- libi2pd/Destination.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 91cc8380..fd23e228 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -512,7 +512,7 @@ namespace client { auto ls2 = std::make_shared (buf + offset, len - offset, request->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr, - from ? from->GetRemoteStaticKeyType () : GetPreferredCryptoType ()); + GetPreferredCryptoType ()); if (ls2->IsValid () && !ls2->IsExpired ()) { leaseSet = ls2; From f164b420b19d2a1497611f717ff307d891dacd38 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 26 Apr 2025 08:43:32 -0400 Subject: [PATCH 787/787] cubicchaos.net reseed added --- .../reseed/unixeno_at_cubicchaos.net.crt | 34 +++++++++++++++++++ libi2pd/Config.cpp | 3 +- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 contrib/certificates/reseed/unixeno_at_cubicchaos.net.crt diff --git a/contrib/certificates/reseed/unixeno_at_cubicchaos.net.crt b/contrib/certificates/reseed/unixeno_at_cubicchaos.net.crt new file mode 100644 index 00000000..c94d319e --- /dev/null +++ b/contrib/certificates/reseed/unixeno_at_cubicchaos.net.crt @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQVpTNnJZlUTDqmZiHRU4wCjANBgkqhkiG9w0BAQsFADB2 +MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK +ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEfMB0GA1UEAwwW +dW5peGVub0BjdWJpY2NoYW9zLm5ldDAeFw0yNTAzMDQxODU5NDZaFw0zNTAzMDQx +ODU5NDZaMHYxCzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgx +HjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMR8w +HQYDVQQDDBZ1bml4ZW5vQGN1YmljY2hhb3MubmV0MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEAr/JoAzLDtHXoAc7QcP4IxO+xNTeiYs78Wlg/Sl/sa6qz +gJoGaKH/X++z4Xe9lBSZalXCamnO4QMTgsWOIeoMy6XVbGzNTXPl8JUcblTIXwkP +pv848b1nxLfgLHzPRz1mJMpMikBugJ3Iz1sQzDVlUdye2fgbGChWliz9P4ClEODv +A/4+7i6uvJgEZ7A+jx3vBCXhiJppE3wTuz5D9BQqG8NuEwwjwBTBByoCC4oxOe0h +Qu1k7kEr+n4qpSEg/1eJ/RYSm+I8BftK1RUfykTwxlfmyEmKsfLBQWczE8Ca9nUB +5V34UH2bRy1cvavJYcNW3EPsGNf4naRs+Gy8XIFrb315GgWC1Z6+tzk+QFli9YeF +0DgtYEZciqu/407o8ZEURTnPjB7GhLDDp1LAQ7CQRhzaraXjHj0hyO+6rFpFdD0D +mXhvI/Eph3QIldsgnQc7nPhU2csN8Vi6bNDgm0HZ8cdmIBpI2Uxn/acZX/9G40oj +czrhsCBEecu/BluLJsfaWCYg90rvONP8Fc4edHAMonzYZR4r0q4hbv7AM8GmDRDN +J9/DZFi+Qs9NAe06jJC3jSsj7IdIs8TMhw8FX3xWOlXwjmVETAgY/dta/MpLJ6tJ +i+E+TH/Ndntj/D6WUwdQq+LyCR6gqHUWR6rl6EDQz+08DWb7j/72JSLb/DaXrDUC +AwEAAaNjMGEwDgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr +BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB8GA1UdDgQYBBZ1bml4ZW5vQGN1Ymlj +Y2hhb3MubmV0MA0GCSqGSIb3DQEBCwUAA4ICAQBBVoPeuOkmJDUdzIrzmxTmjMyz +gpfrZnjirTQKWhbv53sAWNeJ3kZ9l9m+0YpqEtFDrZPL5LTBXcSci5gGuxPkp+i/ +f/axsdcFMKbI9B/M53fyXLLJY0EM4mdhNAWtph1kTowFPhhReefCdqxYIy9uk2pL +gfb6NYJf+w9//fKYFZXb9SsiRchfv81+lbN+PIprnCpV3cTZWmpLRi2hN86pMW20 +3rh7rqJ4dPnA/NoyM+JstL10IU/4StqInweEvoo4W44+cC0zYGvfkkrKL4LB8w5S +6DKebtk7NQDtzuw2QnA9Ms4bmqWQpbL6/7uGaauS0+nmF+2gkqi9hcv0W5ZoBb/D +IVRauySnCtp9PbYM7pIJP9a1U6naLj7L1VixqsJGfPQ8V9TCOOi5bDc3RTetI/DX +bXHhAqHYzboakptylCp+Ao5h2hu0+w4rqnG63HwsHDJWcETbdVFQfzlzUmbx53yV +GnBsUxDgMOiHTZdKLkEnH4Q/XI76uc0ntTRlK9ktKWZPSISUlHrFnFl6I5UdeBMy +6vpB9sJO5L5RPRi4945K5Xdennywdi508mNXtMMmNCqrk1SMYbwaY6ZtIvXEGam9 +uHQTiTEX9LED/VXzFGqzdyDbG43HgS0PksgzedelHWfVAEnc06U3JX2lqUyihYHa +N4jAXWQ7s5p4GYaf4Q== +-----END CERTIFICATE----- diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 3da74da0..bd9329a1 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -243,7 +243,8 @@ namespace config { "https://www2.mk16.de/," "https://i2p.ghativega.in/," "https://i2p.novg.net/," - "https://reseed.stormycloud.org/" + "https://reseed.stormycloud.org/," + "https://cubicchaos.net:8443/" ), "Reseed URLs, separated by comma") ("reseed.yggurls", value()->default_value( "http://[324:71e:281a:9ed3::ace]:7070/,"