From efd754eb93542a098dcaaaa0201f406c37f9f2b7 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 31 Jul 2024 07:56:40 -0400 Subject: [PATCH 001/527] set min pacing time to 250 microseconds --- libi2pd/Streaming.cpp | 14 ++++++++++---- libi2pd/Streaming.h | 3 ++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 8e2f466e..7fa3d96b 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -76,14 +76,17 @@ namespace stream m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_RTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), - m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), + m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (MIN_PACING_TIME), m_PacingTime (INITIAL_PACING_TIME), m_NumResendAttempts (0), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); m_RemoteIdentity = remote->GetIdentity (); auto outboundSpeed = local.GetOwner ()->GetStreamingOutboundSpeed (); if (outboundSpeed) - m_MinPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed; + { + auto minPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed; + if (minPacingTime > m_MinPacingTime) m_MinPacingTime = minPacingTime; + } } Stream::Stream (boost::asio::io_service& service, StreamingDestination& local): @@ -94,13 +97,16 @@ namespace stream m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), - m_PrevRTTSample (INITIAL_RTT), m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), + m_PrevRTTSample (INITIAL_RTT), m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (MIN_PACING_TIME), m_PacingTime (INITIAL_PACING_TIME), m_NumResendAttempts (0), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); auto outboundSpeed = local.GetOwner ()->GetStreamingOutboundSpeed (); if (outboundSpeed) - m_MinPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed; + { + auto minPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed; + if (minPacingTime > m_MinPacingTime) m_MinPacingTime = minPacingTime; + } } Stream::~Stream () diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 309ad6ff..21bdf11b 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -67,6 +67,7 @@ namespace stream const int PENDING_INCOMING_TIMEOUT = 10; // in seconds const int MAX_RECEIVE_TIMEOUT = 20; // in seconds const uint16_t DELAY_CHOKING = 60000; // in milliseconds + const uint64_t MIN_PACING_TIME = 250; // in microseconds. TODO: depends on OS struct Packet { @@ -271,7 +272,7 @@ namespace stream SendBufferQueue m_SendBuffer; double m_RTT; int m_WindowSize, m_RTO, m_AckDelay, m_PrevRTTSample, m_PrevRTT, m_Jitter; - uint64_t m_MinPacingTime, m_PacingTime; + uint64_t m_MinPacingTime, m_PacingTime; // miscroseconds int m_NumResendAttempts; size_t m_MTU; }; From 42782944fb8debe13af06b41cdad1b72779e366b Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 1 Aug 2024 13:49:32 -0400 Subject: [PATCH 002/527] Streaming congestion control improvements. Patch by onon --- libi2pd/Streaming.cpp | 173 +++++++++++++++++++++++++++++------------- libi2pd/Streaming.h | 20 +++-- 2 files changed, 132 insertions(+), 61 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 7fa3d96b..d71e5d4b 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -70,43 +70,40 @@ namespace stream std::shared_ptr remote, int port): m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), - m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsSendTime (true), m_IsWinDropped (true), + m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), + m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (true), m_IsTimeOutResend (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), - m_RTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_RTO (INITIAL_RTO), + m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), - m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (MIN_PACING_TIME), - m_PacingTime (INITIAL_PACING_TIME), m_NumResendAttempts (0), m_MTU (STREAMING_MTU) + m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), m_NumResendAttempts (0), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); m_RemoteIdentity = remote->GetIdentity (); auto outboundSpeed = local.GetOwner ()->GetStreamingOutboundSpeed (); if (outboundSpeed) - { - auto minPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed; - if (minPacingTime > m_MinPacingTime) m_MinPacingTime = minPacingTime; - } + m_MinPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed; } Stream::Stream (boost::asio::io_service& service, StreamingDestination& local): m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), - m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsSendTime (true), m_IsWinDropped (true), + m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), + m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (true), m_IsTimeOutResend (false), m_LocalDestination (local), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), - m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), - m_WindowSize (INITIAL_WINDOW_SIZE), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), - m_PrevRTTSample (INITIAL_RTT), m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (MIN_PACING_TIME), - m_PacingTime (INITIAL_PACING_TIME), m_NumResendAttempts (0), m_MTU (STREAMING_MTU) + m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), + m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowIncCounter (0), + m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), + m_PrevRTTSample (INITIAL_RTT), m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), m_NumResendAttempts (0), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); auto outboundSpeed = local.GetOwner ()->GetStreamingOutboundSpeed (); if (outboundSpeed) - { - auto minPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed; - if (minPacingTime > m_MinPacingTime) m_MinPacingTime = minPacingTime; - } + m_MinPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed; } Stream::~Stream () @@ -313,7 +310,10 @@ namespace stream shared_from_this (), std::placeholders::_1)); } if (delayRequested >= DELAY_CHOKING) + { m_WindowSize = 1; + m_WindowIncCounter = 0; + } } optionData += 2; } @@ -432,8 +432,8 @@ namespace stream return; } int rttSample = INT_MAX; - bool firstRttSample = false; m_IsNAcked = false; + m_IsResendNeeded = false; int nackCount = packet->GetNACKCount (); for (auto it = m_SentPackets.begin (); it != m_SentPackets.end ();) { @@ -463,7 +463,7 @@ namespace stream LogPrint (eLogError, "Streaming: Packet ", seqn, "sent from the future, sendTime=", sentPacket->sendTime); if (!seqn) { - firstRttSample = true; + m_IsFirstRttSample = true; rttSample = rtt < 0 ? 1 : rtt; } else if (!sentPacket->resent && seqn > m_TunnelsChangeSequenceNumber && rtt >= 0) @@ -472,21 +472,27 @@ namespace stream m_SentPackets.erase (it++); m_LocalDestination.DeletePacket (sentPacket); acknowledged = true; - if (m_WindowSize < MAX_WINDOW_SIZE) - m_WindowSize++; + if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK) + m_WindowIncCounter++; } else break; } if (rttSample != INT_MAX) { - if (firstRttSample) + if (m_IsFirstRttSample) { m_RTT = rttSample; + m_SlowRTT = rttSample; m_PrevRTTSample = rttSample; + if (m_RoutingSession) + m_RoutingSession->SetSharedRoutingPath ( + std::make_shared ( + i2p::garlic::GarlicRoutingPath{m_CurrentOutboundTunnel, m_CurrentRemoteLease, (int)m_RTT, 0})); + m_IsFirstRttSample = false; } else - m_RTT = RTT_EWMA_ALPHA * rttSample + (1.0 - RTT_EWMA_ALPHA) * m_RTT; + m_RTT = RTT_EWMA_ALPHA * m_RTT + (1.0 - RTT_EWMA_ALPHA) * rttSample; // calculate jitter int jitter = 0; if (rttSample > m_PrevRTTSample) @@ -495,18 +501,30 @@ namespace stream jitter = m_PrevRTTSample - rttSample; else jitter = std::round (rttSample / 10); // 10% - m_Jitter = std::round (RTT_EWMA_ALPHA * m_Jitter + (1.0 - RTT_EWMA_ALPHA) * jitter); + jitter += 5; // for low-latency connections + m_Jitter = std::round (RTT_EWMA_ALPHA * jitter + (1.0 - RTT_EWMA_ALPHA) * m_Jitter); m_PrevRTTSample = rttSample; // // delay-based CC - if ((m_RTT > m_PrevRTT) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection + if ((m_PrevRTT > m_SlowRTT + m_Jitter) && (m_RTT > m_SlowRTT + m_Jitter) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection { - m_WindowSize >>= 1; // /2 + if (m_LastWindowDropSize) + m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2; + else + m_LastWindowDropSize = m_WindowSize; + m_WindowSize = m_WindowSize / 2; // /2 + if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; + m_WindowIncCounter = 0; + m_DropWindowDelayTime = ts + m_SlowRTT; + m_IsFirstACK = true; m_IsWinDropped = true; // don't drop window twice } - if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; UpdatePacingTime (); - m_PrevRTT = m_RTT * 1.1 + m_Jitter; + if (rttSample < m_RTT) // need for delay-based CC + m_SlowRTT = RTT_EWMA_ALPHA * rttSample + (1.0 - RTT_EWMA_ALPHA) * m_SlowRTT; + else + m_SlowRTT = RTT_EWMA_ALPHA * m_RTT + (1.0 - RTT_EWMA_ALPHA) * m_SlowRTT; + m_PrevRTT = m_RTT; bool wasInitial = m_RTO == INITIAL_RTO; m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter)); // TODO: implement it better @@ -514,7 +532,7 @@ namespace stream if (wasInitial) ScheduleResend (); } - if (m_WindowSize > int(m_SentPackets.size ())) + if ( ts > m_DropWindowDelayTime) m_IsWinDropped = false; if (acknowledged || m_IsNAcked) { @@ -522,11 +540,9 @@ namespace stream } if ((m_SendBuffer.IsEmpty () && m_SentPackets.size () > 0) // tail loss || int(m_SentPackets.size ()) > m_WindowSize) // or we drop window - m_IsNAcked = true; - if (firstRttSample && m_RoutingSession) - m_RoutingSession->SetSharedRoutingPath ( - std::make_shared ( - i2p::garlic::GarlicRoutingPath{m_CurrentOutboundTunnel, m_CurrentRemoteLease, (int)m_RTT, 0})); + { + m_IsResendNeeded = true; + } if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ()) { m_ResendTimer.cancel (); @@ -535,6 +551,7 @@ namespace stream if (acknowledged) { m_NumResendAttempts = 0; + m_IsFirstACK = false; SendBuffer (); } if (m_Status == eStreamStatusClosed) @@ -610,9 +627,15 @@ namespace stream void Stream::SendBuffer () { ScheduleSend (); + auto ts = i2p::util::GetMillisecondsSinceEpoch (); int numMsgs = m_WindowSize - m_SentPackets.size (); - if (numMsgs <= 0 || !m_IsSendTime) return; // window is full - else numMsgs = 1; + if (numMsgs <= 0 || !m_IsSendTime) // window is full + { + m_LastSendTime = ts; + return; + } + else if (numMsgs > m_NumPacketsToSend) + numMsgs = m_NumPacketsToSend; bool isNoAck = m_LastReceivedSequenceNumber < 0; // first packet std::vector packets; while ((m_Status == eStreamStatusNew) || (IsEstablished () && !m_SendBuffer.IsEmpty () && numMsgs > 0)) @@ -706,13 +729,14 @@ namespace stream m_AckSendTimer.cancel (); } bool isEmpty = m_SentPackets.empty (); - auto ts = i2p::util::GetMillisecondsSinceEpoch (); +// auto ts = i2p::util::GetMillisecondsSinceEpoch (); for (auto& it: packets) { it->sendTime = ts; m_SentPackets.insert (it); } SendPackets (packets); + m_LastSendTime = ts; m_IsSendTime = false; if (m_Status == eStreamStatusClosing && m_SendBuffer.IsEmpty ()) SendClose (); @@ -1048,7 +1072,7 @@ namespace stream if (m_Status != eStreamStatusTerminated) { m_SendTimer.cancel (); - m_SendTimer.expires_from_now (boost::posix_time::microseconds(m_PacingTime)); + m_SendTimer.expires_from_now (boost::posix_time::microseconds(SEND_INTERVAL)); m_SendTimer.async_wait (std::bind (&Stream::HandleSendTimer, shared_from_this (), std::placeholders::_1)); } @@ -1058,19 +1082,48 @@ namespace stream { if (ecode != boost::asio::error::operation_aborted) { - m_IsSendTime = true; - if (m_IsNAcked) // || m_WindowSize < int(m_SentPackets.size ())) // resend one packet - ResendPacket (); - // delay-based CC - else if (!m_IsWinDropped && int(m_SentPackets.size ()) == m_WindowSize) // we sending packets too fast, early detection + if (m_WindowIncCounter && m_WindowSize < MAX_WINDOW_SIZE) { - m_WindowSize >>= 1; // /2 - m_IsWinDropped = true; // don't drop window twice - if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; + if (m_LastWindowDropSize && (m_LastWindowDropSize > m_WindowSize)) + { + m_WindowSize += 2.001-(2/((m_LastWindowDropSize+(1/m_WindowSize))/m_WindowSize)); // some magic here + m_WindowIncCounter --; + } + else + { + m_WindowSize += 1; + m_WindowIncCounter --; + } + if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; UpdatePacingTime (); } - else if (m_WindowSize > int(m_SentPackets.size ())) // send one packet - SendBuffer (); + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + if (m_LastSendTime && ts*1000 > m_LastSendTime*1000 + m_PacingTime) + { + m_NumPacketsToSend = ((ts*1000 - m_LastSendTime*1000) + m_PacingTimeRem) / m_PacingTime; + m_PacingTimeRem = ((ts*1000 - m_LastSendTime*1000) + m_PacingTimeRem) - (m_NumPacketsToSend * m_PacingTime); + m_IsSendTime = true; + if (m_IsNAcked || m_IsResendNeeded) // resend packets + ResendPacket (); + // delay-based CC + else if (!m_IsWinDropped && int(m_SentPackets.size ()) == m_WindowSize) // we sending packets too fast, early detection + { + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + if (m_LastWindowDropSize) + m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2; + else + m_LastWindowDropSize = m_WindowSize; + m_WindowSize = m_WindowSize / 2; // /2 + if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; + m_WindowIncCounter = 0; + m_DropWindowDelayTime = ts + m_SlowRTT; + m_IsFirstACK = true; + m_IsWinDropped = true; // don't drop window twice + UpdatePacingTime (); + } + else if (m_WindowSize > int(m_SentPackets.size ())) // send packets + SendBuffer (); + } else // pass ScheduleSend (); } @@ -1098,6 +1151,7 @@ namespace stream m_SendTimer.cancel (); // if no ack's in RTO, disable fast retransmit m_IsTimeOutResend = true; m_IsNAcked = false; + m_IsResendNeeded = false; ResendPacket (); // send one packet per RTO, waiting for ack } } @@ -1126,7 +1180,7 @@ namespace stream it->resent = false; it->sendTime = ts; packets.push_back (it); - if (packets.size () >= 1) break; + if (int(packets.size ()) >= m_NumPacketsToSend) break; } } @@ -1140,9 +1194,16 @@ namespace stream // loss-based CC if (!m_IsWinDropped) { - m_WindowSize >>= 1; // /2 - m_IsWinDropped = true; // don't drop window twice + if (m_LastWindowDropSize) + m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2; + else + m_LastWindowDropSize = m_WindowSize; + m_WindowSize = m_WindowSize / 2; // /2 if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; + m_WindowIncCounter = 0; + m_IsWinDropped = true; // don't drop window twice + m_DropWindowDelayTime = ts + m_SlowRTT; + m_IsFirstACK = true; UpdatePacingTime (); } } @@ -1151,7 +1212,12 @@ namespace stream m_IsTimeOutResend = false; m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change m_WindowSize = INITIAL_WINDOW_SIZE; + m_LastWindowDropSize = 0; + m_WindowIncCounter = 0; m_IsWinDropped = true; + m_IsFirstRttSample = true; + m_DropWindowDelayTime = 0; + m_IsFirstACK = true; UpdatePacingTime (); if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); if (m_NumResendAttempts & 1) @@ -1169,12 +1235,13 @@ namespace stream } } SendPackets (packets); + m_LastSendTime = ts; m_IsSendTime = false; - if (m_IsNAcked) ScheduleSend (); + if (m_IsNAcked || m_IsResendNeeded) ScheduleSend (); } else SendBuffer (); - if (!m_IsNAcked) ScheduleResend (); + if (!m_IsNAcked && !m_IsResendNeeded) ScheduleResend (); } void Stream::ScheduleAck (int timeout) diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 21bdf11b..415f3df4 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -55,19 +55,19 @@ namespace stream const int MAX_NUM_RESEND_ATTEMPTS = 10; const int INITIAL_WINDOW_SIZE = 10; const int MIN_WINDOW_SIZE = 1; - const int MAX_WINDOW_SIZE = 128; - const double RTT_EWMA_ALPHA = 0.8; + const int MAX_WINDOW_SIZE = 1024; + const double RTT_EWMA_ALPHA = 0.125; const int MIN_RTO = 20; // in milliseconds const int INITIAL_RTT = 8000; // in milliseconds const int INITIAL_RTO = 9000; // in milliseconds const int INITIAL_PACING_TIME = 1000 * INITIAL_RTT / INITIAL_WINDOW_SIZE; // in microseconds const int MIN_SEND_ACK_TIMEOUT = 2; // in milliseconds const int SYN_TIMEOUT = 200; // how long we wait for SYN after follow-on, in milliseconds - const size_t MAX_PENDING_INCOMING_BACKLOG = 128; + const size_t MAX_PENDING_INCOMING_BACKLOG = 1024; const int PENDING_INCOMING_TIMEOUT = 10; // in seconds const int MAX_RECEIVE_TIMEOUT = 20; // in seconds const uint16_t DELAY_CHOKING = 60000; // in milliseconds - const uint64_t MIN_PACING_TIME = 250; // in microseconds. TODO: depends on OS + const uint64_t SEND_INTERVAL = 1000; // in microseconds struct Packet { @@ -252,6 +252,9 @@ namespace stream StreamStatus m_Status; bool m_IsAckSendScheduled; bool m_IsNAcked; + bool m_IsFirstACK; + bool m_IsResendNeeded; + bool m_IsFirstRttSample; bool m_IsSendTime; bool m_IsWinDropped; bool m_IsTimeOutResend; @@ -270,10 +273,11 @@ namespace stream uint16_t m_Port; SendBufferQueue m_SendBuffer; - double m_RTT; - int m_WindowSize, m_RTO, m_AckDelay, m_PrevRTTSample, m_PrevRTT, m_Jitter; - uint64_t m_MinPacingTime, m_PacingTime; // miscroseconds - int m_NumResendAttempts; + double m_RTT, m_SlowRTT; + float m_WindowSize, m_LastWindowDropSize; + int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample, m_PrevRTT, m_Jitter; + uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, m_DropWindowDelayTime, m_LastSendTime; // microseconds + int m_NumResendAttempts, m_NumPacketsToSend; size_t m_MTU; }; From 8e1fb8ca9fd79654a2d3f0c274b08b84265be952 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 2 Aug 2024 14:39:04 -0400 Subject: [PATCH 003/527] send status failure and drop shared routing path if message was not sent --- libi2pd_client/I2CP.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 55da9924..519f4ed6 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -295,7 +295,9 @@ namespace client auto garlic = remoteSession->WrapSingleMessage (msg); // send bool sent = SendMsg (garlic, outboundTunnel, remoteLease); - m_Owner->SendMessageStatusMessage (nonce, eI2CPMessageStatusGuaranteedSuccess); + m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure); + if (!sent) + remoteSession->SetSharedRoutingPath (nullptr); return sent; } From 3c69e0b2afd4b85d03e1327ef57ec9b571671ead Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 5 Aug 2024 14:44:10 -0400 Subject: [PATCH 004/527] keep sending reverse key until tag received on new tagset --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 749ec8d1..1aca5ed8 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -398,7 +398,6 @@ namespace garlic { uint16_t keyID = bufbe16toh (buf); buf += 2; // keyID bool newKey = flag & ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG; - m_SendReverseKey = true; if (!m_NextReceiveRatchet) m_NextReceiveRatchet.reset (new DHRatchet ()); else @@ -410,6 +409,7 @@ namespace garlic } m_NextReceiveRatchet->keyID = keyID; } + m_SendReverseKey = true; int tagsetID = 2*keyID; if (newKey) { @@ -781,6 +781,8 @@ namespace garlic [[fallthrough]]; #endif case eSessionStateEstablished: + if (m_SendReverseKey && receiveTagset->GetTagSetID () == 2*m_NextReceiveRatchet->keyID) + m_SendReverseKey = false; // tag received on new tagset if (receiveTagset->IsNS ()) { // our of sequence NSR @@ -978,7 +980,6 @@ namespace garlic memcpy (payload + offset, m_NextReceiveRatchet->key->GetPublicKey (), 32); offset += 32; // public key } - m_SendReverseKey = false; } if (m_SendForwardKey) { From 349c4e30b677436e73dca6e280468cdc1cbda5a9 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 6 Aug 2024 13:58:21 -0400 Subject: [PATCH 005/527] correct receive ratchet tagsetid calculation --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 8 ++++---- libi2pd/ECIESX25519AEADRatchetSession.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 1aca5ed8..528762fd 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -409,16 +409,14 @@ namespace garlic } m_NextReceiveRatchet->keyID = keyID; } - m_SendReverseKey = true; - int tagsetID = 2*keyID; if (newKey) { m_NextReceiveRatchet->key = i2p::transport::transports.GetNextX25519KeysPair (); m_NextReceiveRatchet->newKey = true; - tagsetID++; } else m_NextReceiveRatchet->newKey = false; + auto tagsetID = m_NextReceiveRatchet->GetReceiveTagSetID (); if (flag & ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG) memcpy (m_NextReceiveRatchet->remote, buf, 32); @@ -432,7 +430,9 @@ namespace garlic GenerateMoreReceiveTags (newTagset, (GetOwner () && GetOwner ()->GetNumRatchetInboundTags () > 0) ? GetOwner ()->GetNumRatchetInboundTags () : ECIESX25519_MAX_NUM_GENERATED_TAGS); receiveTagset->Expire (); + LogPrint (eLogDebug, "Garlic: Next receive tagset ", tagsetID, " created"); + m_SendReverseKey = true; } } @@ -781,7 +781,7 @@ namespace garlic [[fallthrough]]; #endif case eSessionStateEstablished: - if (m_SendReverseKey && receiveTagset->GetTagSetID () == 2*m_NextReceiveRatchet->keyID) + if (m_SendReverseKey && receiveTagset->GetTagSetID () == m_NextReceiveRatchet->GetReceiveTagSetID ()) m_SendReverseKey = false; // tag received on new tagset if (receiveTagset->IsNS ()) { diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index e6deb2bc..18cac434 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -149,6 +149,7 @@ namespace garlic std::shared_ptr key; uint8_t remote[32]; // last remote public key bool newKey = true; + int GetReceiveTagSetID () const { return newKey ? (2*keyID + 1) : 2*keyID; } }; public: From b306bf2db96c6615d0176c6619f690564bcaf8d0 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 9 Aug 2024 08:14:39 -0400 Subject: [PATCH 006/527] don't handle connect timer for already terminated session --- libi2pd/SSU2Session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index bce78044..21f651d8 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -144,7 +144,7 @@ namespace transport void SSU2Session::HandleConnectTimer (const boost::system::error_code& ecode) { - if (!ecode) + if (!ecode && m_State != eSSU2SessionStateTerminated) { // timeout expired if (m_State == eSSU2SessionStateIntroduced) // WaitForIntroducer From d75f15104ea43fd28aad98f89978562be31edc01 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 10 Aug 2024 14:43:29 -0400 Subject: [PATCH 007/527] select only established sessions for peer tests --- libi2pd/SSU2.cpp | 10 ++++------ libi2pd/SSU2.h | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 7cd6854e..36c85615 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -501,17 +501,15 @@ namespace transport } std::shared_ptr SSU2Server::GetRandomPeerTestSession ( - i2p::data::RouterInfo::CompatibleTransports remoteTransports, const i2p::data::IdentHash& excluded) const + i2p::data::RouterInfo::CompatibleTransports remoteTransports, const i2p::data::IdentHash& excluded) { if (m_Sessions.empty ()) return nullptr; - uint16_t ind; - RAND_bytes ((uint8_t *)&ind, sizeof (ind)); - ind %= m_Sessions.size (); + int ind = m_Rng () % m_Sessions.size (); auto it = m_Sessions.begin (); std::advance (it, ind); while (it != m_Sessions.end ()) { - if ((it->second->GetRemotePeerTestTransports () & remoteTransports) && + if (it->second->IsEstablished () && (it->second->GetRemotePeerTestTransports () & remoteTransports) && it->second->GetRemoteIdentity ()->GetIdentHash () != excluded) return it->second; it++; @@ -520,7 +518,7 @@ namespace transport it = m_Sessions.begin (); while (it != m_Sessions.end () && ind) { - if ((it->second->GetRemotePeerTestTransports () & remoteTransports) && + if (it->second->IsEstablished () && (it->second->GetRemotePeerTestTransports () & remoteTransports) && it->second->GetRemoteIdentity ()->GetIdentHash () != excluded) return it->second; it++; ind--; diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index aacdc076..55746c0f 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -84,7 +84,7 @@ namespace transport std::shared_ptr FindSession (const i2p::data::IdentHash& ident) const; std::shared_ptr FindPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) const; std::shared_ptr GetRandomPeerTestSession (i2p::data::RouterInfo::CompatibleTransports remoteTransports, - const i2p::data::IdentHash& excluded) const; + const i2p::data::IdentHash& excluded); void AddRelay (uint32_t tag, std::shared_ptr relay); void RemoveRelay (uint32_t tag); From 52a313bb6540b2cbf39a6bc4438d09467835c24b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 12 Aug 2024 21:29:05 -0400 Subject: [PATCH 008/527] force LeaseSet timestamp update if published at the same second --- libi2pd/Destination.cpp | 13 ++++++++++--- libi2pd/Destination.h | 1 + libi2pd/LeaseSet.cpp | 11 +++++------ libi2pd/LeaseSet.h | 5 +++-- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 43cd21f0..6f95525e 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -981,7 +981,7 @@ namespace client m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_StreamingOutboundSpeed (DEFAULT_MAX_OUTBOUND_SPEED), m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0), - m_DatagramDestination (nullptr), m_RefCounter (0), + m_DatagramDestination (nullptr), m_RefCounter (0), m_LastPublishedTimestamp (0), m_ReadyChecker(service) { if (keys.IsOfflineSignature () && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) @@ -1101,7 +1101,6 @@ namespace client void ClientDestination::Stop () { LogPrint(eLogDebug, "Destination: Stopping destination ", GetIdentHash().ToBase32(), ".b32.i2p"); - LeaseSetDestination::Stop (); m_ReadyChecker.cancel(); LogPrint(eLogDebug, "Destination: -> Stopping Streaming Destination"); m_StreamingDestination->Stop (); @@ -1123,6 +1122,7 @@ namespace client delete m_DatagramDestination; m_DatagramDestination = nullptr; } + LeaseSetDestination::Stop (); LogPrint(eLogDebug, "Destination: -> Stopping done"); } @@ -1430,12 +1430,19 @@ namespace client if (m_StandardEncryptionKey) keySections.push_back ({m_StandardEncryptionKey->keyType, (uint16_t)m_StandardEncryptionKey->decryptor->GetPublicKeyLen (), m_StandardEncryptionKey->pub} ); + auto publishedTimestamp = i2p::util::GetSecondsSinceEpoch (); + if (publishedTimestamp <= m_LastPublishedTimestamp) + { + LogPrint (eLogDebug, "Destination: LeaseSet update at the same second"); + publishedTimestamp++; // force newer timestamp + } bool isPublishedEncrypted = GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; auto ls2 = std::make_shared (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2, - m_Keys, keySections, tunnels, IsPublic (), isPublishedEncrypted); + m_Keys, keySections, tunnels, IsPublic (), publishedTimestamp, isPublishedEncrypted); if (isPublishedEncrypted) // encrypt if type 5 ls2 = std::make_shared (ls2, m_Keys, GetAuthType (), m_AuthKeys); leaseSet = ls2; + m_LastPublishedTimestamp = publishedTimestamp; } SetLeaseSet (leaseSet); } diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 40c97ee8..43c9ed81 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -306,6 +306,7 @@ namespace client std::shared_ptr m_LastStreamingDestination; uint16_t m_LastPort; // for server tunnels i2p::datagram::DatagramDestination * m_DatagramDestination; int m_RefCounter; // how many clients(tunnels) use this destination + uint64_t m_LastPublishedTimestamp; boost::asio::deadline_timer m_ReadyChecker; diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 675f6503..7834b6b9 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.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 * @@ -808,7 +808,7 @@ namespace data LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, const KeySections& encryptionKeys, const std::vector >& tunnels, - bool isPublic, bool isPublishedEncrypted): + bool isPublic, uint64_t publishedTimestamp, bool isPublishedEncrypted): LocalLeaseSet (keys.GetPublic (), nullptr, 0) { auto identity = keys.GetPublic (); @@ -837,8 +837,7 @@ namespace data m_Buffer[0] = storeType; // LS2 header auto offset = identity->ToBuffer (m_Buffer + 1, m_BufferLen) + 1; - auto timestamp = i2p::util::GetSecondsSinceEpoch (); - htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds) + htobe32buf (m_Buffer + offset, publishedTimestamp); offset += 4; // published timestamp (seconds) uint8_t * expiresBuf = m_Buffer + offset; offset += 2; // expires, fill later htobe16buf (m_Buffer + offset, flags); offset += 2; // flags if (keys.IsOfflineSignature ()) @@ -875,13 +874,13 @@ namespace data if (expirationTime) { SetExpirationTime (expirationTime*1000LL); - auto expires = (int)expirationTime - timestamp; + auto expires = (int)expirationTime - publishedTimestamp; htobe16buf (expiresBuf, expires > 0 ? expires : 0); } else { // no tunnels or withdraw - SetExpirationTime (timestamp*1000LL); + SetExpirationTime (publishedTimestamp*1000LL); memset (expiresBuf, 0, 2); // expires immeditely } // sign diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index 4b1311a5..7eea3aed 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.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 * @@ -256,7 +256,8 @@ namespace data LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, const KeySections& encryptionKeys, const std::vector >& tunnels, - bool isPublic, bool isPublishedEncrypted = false); + bool isPublic, uint64_t publishedTimestamp, + bool isPublishedEncrypted = false); LocalLeaseSet2 (uint8_t storeType, std::shared_ptr identity, const uint8_t * buf, size_t len); // from I2CP From 0c924836cf9ae04cd12e2647e6edd5c0f896ff7b Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 13 Aug 2024 15:36:13 -0400 Subject: [PATCH 009/527] fixed AEAD verification for LibreSSL --- libi2pd/Crypto.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 960c400c..2f9677c1 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -997,6 +997,15 @@ namespace crypto } else { +#if defined(LIBRESSL_VERSION_NUMBER) + std::vector m(msgLen + 16); + if (msg == buf) + { + // we have to use different buffers otherwise verification fails + memcpy (m.data (), msg, msgLen + 16); + msg = m.data (); + } +#endif EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0); EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, (uint8_t *)(msg + msgLen)); From 11328a429d65b7e86025218dcd502b9437b341a1 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 14 Aug 2024 10:13:35 -0400 Subject: [PATCH 010/527] set minimal resend interval. Resend attempt after only Ack --- libi2pd/SSU2Session.cpp | 6 +++++- libi2pd/SSU2Session.h | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 21f651d8..92fe2d46 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -91,7 +91,7 @@ namespace transport m_RTO (SSU2_INITIAL_RTO), m_RelayTag (0),m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose), m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32), // min size - m_LastResendTime (0) + m_LastResendTime (0), m_LastResendAttemptTime (0) { m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState); if (in_RemoteRouter && m_Address) @@ -548,6 +548,8 @@ namespace transport size_t SSU2Session::Resend (uint64_t ts) { + if (ts + SSU2_RESEND_ATTEMPT_MIN_INTERVAL < m_LastResendAttemptTime) return 0; + m_LastResendAttemptTime = ts; // resend handshake packet if (m_SentHandshakePacket && ts >= m_SentHandshakePacket->sendTime + SSU2_HANDSHAKE_RESEND_INTERVAL) { @@ -3131,6 +3133,8 @@ namespace transport m_Handler.Flush (); m_IsDataReceived = false; } + else if (!sent && !m_SentPackets.empty ()) // if only acks received, nothing sent and we still have something to resend + Resend (i2p::util::GetMillisecondsSinceEpoch ()); // than right time to resend } } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 587f74b6..cd6793d3 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -37,6 +37,7 @@ namespace transport const size_t SSU2_MIN_PACKET_SIZE = 1280; const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1000; // in milliseconds const int SSU2_MAX_NUM_RESENDS = 5; + const int SSU2_RESEND_ATTEMPT_MIN_INTERVAL = 3; // in milliseconds const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds const int SSU2_MAX_NUM_RECEIVED_I2NP_MSGIDS = 5000; // how many msgID we store for duplicates check const int SSU2_RECEIVED_I2NP_MSGIDS_CLEANUP_TIMEOUT = 10; // in seconds @@ -373,7 +374,7 @@ namespace transport size_t m_MaxPayloadSize; std::unique_ptr m_PathChallenge; std::unordered_map m_ReceivedI2NPMsgIDs; // msgID -> timestamp in seconds - uint64_t m_LastResendTime; // in milliseconds + uint64_t m_LastResendTime, m_LastResendAttemptTime; // in milliseconds }; inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) From 09dbe9fc036f2a573c288fd229287a214a83c134 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 14 Aug 2024 13:43:24 -0400 Subject: [PATCH 011/527] check option and packet length --- libi2pd/Streaming.cpp | 5 +++++ libi2pd/Streaming.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index d71e5d4b..917d0d80 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -297,6 +297,11 @@ namespace stream { const uint8_t * optionData = packet->GetOptionData (); size_t optionSize = packet->GetOptionSize (); + if (optionSize > packet->len) + { + LogPrint (eLogInfo, "Streaming: Invalid option size ", optionSize, " Discarded"); + return false; + } if (flags & PACKET_FLAG_DELAY_REQUESTED) { if (!m_IsAckSendScheduled) diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 415f3df4..22dad0e3 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -78,7 +78,7 @@ namespace stream Packet (): len (0), offset (0), sendTime (0), resent (false) {}; uint8_t * GetBuffer () { return buf + offset; }; - size_t GetLength () const { return len - offset; }; + size_t GetLength () const { return len > offset ? len - offset : 0; }; uint32_t GetSendStreamID () const { return bufbe32toh (buf); }; uint32_t GetReceiveStreamID () const { return bufbe32toh (buf + 4); }; From d47ae3012a80867996a289deae703925dc3763d5 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 15 Aug 2024 13:35:51 -0400 Subject: [PATCH 012/527] periodic sending ack requests in ECEISX25519 session and dead path detection in I2CP --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 64 ++++++++++++++++++----- libi2pd/ECIESX25519AEADRatchetSession.h | 18 +++++-- libi2pd/Garlic.h | 2 +- 3 files changed, 66 insertions(+), 18 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 528762fd..a143a931 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -229,6 +229,29 @@ namespace garlic tagsetNsr->NextSessionTagRatchet (); } + bool ECIESX25519AEADRatchetSession::MessageConfirmed (uint32_t msgID) + { + auto ret = GarlicRoutingSession::MessageConfirmed (msgID); // LeaseSet + if (m_AckRequestMsgID && m_AckRequestMsgID == msgID) + { + m_AckRequestMsgID = 0; + m_AckRequestNumAttempts = 0; + ret = true; + } + return ret; + } + + bool ECIESX25519AEADRatchetSession::CleanupUnconfirmedTags () + { + if (m_AckRequestMsgID && m_AckRequestNumAttempts > ECIESX25519_ACK_REQUEST_MAX_NUM_ATTEMPTS) + { + m_AckRequestMsgID = 0; + m_AckRequestNumAttempts = 0; + return true; + } + return false; + } + bool ECIESX25519AEADRatchetSession::HandleNewIncomingSession (const uint8_t * buf, size_t len) { if (!GetOwner ()) return false; @@ -335,7 +358,7 @@ namespace garlic { uint32_t tagsetid = bufbe16toh (buf + offset1); offset1 += 2; // tagsetid uint16_t n = bufbe16toh (buf + offset1); offset1 += 2; // N - MessageConfirmed ((tagsetid << 16) + n); // msgid + MessageConfirmed ((tagsetid << 16) + n); // msgid = (tagsetid << 16) + N } break; } @@ -860,6 +883,7 @@ namespace garlic { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); size_t payloadLen = 0; + bool sendAckRequest = false; if (first) payloadLen += 7;// datatime if (msg) { @@ -878,13 +902,28 @@ namespace garlic payloadLen += leaseSet->GetBufferLen () + DATABASE_STORE_HEADER_SIZE + 13; if (!first) { - // ack request + // ack request for LeaseSet + m_AckRequestMsgID = m_SendTagset->GetMsgID (); + sendAckRequest = true; + // update LeaseSet status SetLeaseSetUpdateStatus (eLeaseSetSubmitted); - SetLeaseSetUpdateMsgID ((m_SendTagset->GetTagSetID () << 16) + m_SendTagset->GetNextIndex ()); // (tagsetid << 16) + N + SetLeaseSetUpdateMsgID (m_AckRequestMsgID); SetLeaseSetSubmissionTime (ts); - payloadLen += 4; } } + if (!sendAckRequest && !first && + ((!m_AckRequestMsgID && ts > m_LastAckRequestSendTime + ECIESX25519_ACK_REQUEST_INTERVAL) || // regular request + (m_AckRequestMsgID && ts > m_LastAckRequestSendTime + LEASESET_CONFIRMATION_TIMEOUT))) // previous request failed. try again + { + // not LeaseSet + m_AckRequestMsgID = m_SendTagset->GetMsgID (); + if (m_AckRequestMsgID) + { + m_AckRequestNumAttempts++; + sendAckRequest = true; + } + } + if (sendAckRequest) payloadLen += 4; if (m_AckRequests.size () > 0) payloadLen += m_AckRequests.size ()*4 + 3; if (m_SendReverseKey) @@ -936,16 +975,15 @@ namespace garlic } // LeaseSet if (leaseSet) - { offset += CreateLeaseSetClove (leaseSet, ts, payload + offset, payloadLen - offset); - if (!first) - { - // ack request - payload[offset] = eECIESx25519BlkAckRequest; offset++; - htobe16buf (payload + offset, 1); offset += 2; - payload[offset] = 0; offset++; // flags - } - } + // ack request + if (sendAckRequest) + { + payload[offset] = eECIESx25519BlkAckRequest; offset++; + htobe16buf (payload + offset, 1); offset += 2; + payload[offset] = 0; offset++; // flags + m_LastAckRequestSendTime = ts; + } // msg if (msg) offset += CreateGarlicClove (msg, payload + offset, payloadLen - offset); diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 18cac434..10645251 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -30,7 +30,9 @@ namespace garlic const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds - const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180 + const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // in seconds + const int ECIESX25519_ACK_REQUEST_INTERVAL = 33000; // in milliseconds + const int ECIESX25519_ACK_REQUEST_MAX_NUM_ATTEMPTS = 3; const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 8192; // number of tags we request new tagset after const int ECIESX25519_MIN_NUM_GENERATED_TAGS = 24; const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 320; @@ -57,6 +59,8 @@ namespace garlic int GetTagSetID () const { return m_TagSetID; }; void SetTagSetID (int tagsetID) { m_TagSetID = tagsetID; }; + uint32_t GetMsgID () const { return (m_TagSetID << 16) + m_NextIndex; }; // (tagsetid << 16) + N + private: i2p::data::Tag<64> m_SessionTagKeyData; @@ -178,14 +182,16 @@ namespace garlic bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; }; bool IsTerminated () const { return m_IsTerminated; } uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; }; - + bool CleanupUnconfirmedTags (); // return true if unaswered Ack requests, called from I2CP + protected: i2p::crypto::NoiseSymmetricState& GetNoiseState () { return *this; }; void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; }; void CreateNonce (uint64_t seqn, uint8_t * nonce); void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr& receiveTagset, int index); - + bool MessageConfirmed (uint32_t msgID); + private: bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes @@ -219,11 +225,15 @@ namespace garlic m_LastSentTimestamp = 0; // in milliseconds std::shared_ptr m_SendTagset, m_NSRSendTagset; std::unique_ptr m_Destination;// TODO: might not need it - std::list > m_AckRequests; // (tagsetid, index) + std::list > m_AckRequests; // incoming (tagsetid, index) bool m_SendReverseKey = false, m_SendForwardKey = false, m_IsTerminated = false; std::unique_ptr m_NextReceiveRatchet, m_NextSendRatchet; uint8_t m_PaddingSizes[32], m_NextPaddingSize; + uint64_t m_LastAckRequestSendTime = 0; // milliseconds + uint32_t m_AckRequestMsgID = 0; + int m_AckRequestNumAttempts = 0; + public: // for HTTP only diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 5541e0f1..d1b97ade 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -109,7 +109,7 @@ namespace garlic GarlicRoutingSession (); virtual ~GarlicRoutingSession (); virtual std::shared_ptr WrapSingleMessage (std::shared_ptr msg) = 0; - virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession + virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession and ECIESX25519AEADRatchetSession virtual bool MessageConfirmed (uint32_t msgID); virtual bool IsRatchets () const { return false; }; virtual bool IsReadyToSend () const { return true; }; From 7376f7c399958b2718fccb0fe879cd7b095ffade Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 17 Aug 2024 08:13:17 -0400 Subject: [PATCH 013/527] generate max number of tags for follow on tagsets --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index a143a931..9f23482b 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -777,7 +777,8 @@ namespace garlic } else { - moreTags = ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 2); // N/4 + moreTags = (receiveTagset->GetTagSetID () > 0) ? ECIESX25519_MAX_NUM_GENERATED_TAGS : // for non first tagset + (ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 1)); // N/2 if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS; moreTags -= (receiveTagset->GetNextIndex () - index); index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind From 41dd8b527d93d6001960652de2b2f06299346c11 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 17 Aug 2024 08:30:16 -0400 Subject: [PATCH 014/527] reduce number of acks being sent --- libi2pd/Streaming.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 917d0d80..e010ac83 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -236,7 +236,8 @@ namespace stream if (!m_IsAckSendScheduled) { // send NACKs for missing messages - int ackTimeout = MIN_SEND_ACK_TIMEOUT*m_SavedPackets.size (); + SendQuickAck (); + auto ackTimeout = m_RTT/10; if (ackTimeout > m_AckDelay) ackTimeout = m_AckDelay; ScheduleAck (ackTimeout); } From fb8e0e1b5b485197c217ec8236eef859e056c05d Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 17 Aug 2024 17:11:28 -0400 Subject: [PATCH 015/527] limit stream's inbound speed --- libi2pd/Destination.cpp | 4 +++ libi2pd/Destination.h | 4 +++ libi2pd/Streaming.cpp | 47 ++++++++++++++++++++++++++++---- libi2pd/Streaming.h | 2 ++ libi2pd_client/ClientContext.cpp | 1 + 5 files changed, 53 insertions(+), 5 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 6f95525e..9285b05d 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -980,6 +980,7 @@ namespace client LeaseSetDestination (service, isPublic, params), m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_StreamingOutboundSpeed (DEFAULT_MAX_OUTBOUND_SPEED), + m_StreamingInboundSpeed (DEFAULT_MAX_INBOUND_SPEED), m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0), m_DatagramDestination (nullptr), m_RefCounter (0), m_LastPublishedTimestamp (0), m_ReadyChecker(service) @@ -1051,6 +1052,9 @@ namespace client it = params->find (I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED); if (it != params->end ()) m_StreamingOutboundSpeed = std::stoi(it->second); + it = params->find (I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED); + if (it != params->end ()) + m_StreamingInboundSpeed = std::stoi(it->second); it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS); if (it != params->end ()) m_IsStreamingAnswerPings = std::stoi (it->second); // 1 for true diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 43c9ed81..9dcc64c6 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -86,6 +86,8 @@ namespace client const int DEFAULT_INITIAL_ACK_DELAY = 200; // milliseconds const char I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED[] = "i2p.streaming.maxOutboundSpeed"; // bytes/sec const int DEFAULT_MAX_OUTBOUND_SPEED = 1730000000; // no more than 1.73 Gbytes/s + const char I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED[] = "i2p.streaming.maxInboundSpeed"; // bytes/sec + const int DEFAULT_MAX_INBOUND_SPEED = 1730000000; // no more than 1.73 Gbytes/s const char I2CP_PARAM_STREAMING_ANSWER_PINGS[] = "i2p.streaming.answerPings"; const int DEFAULT_ANSWER_PINGS = true; @@ -262,6 +264,7 @@ namespace client void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor); int GetStreamingAckDelay () const { return m_StreamingAckDelay; } int GetStreamingOutboundSpeed () const { return m_StreamingOutboundSpeed; } + int GetStreamingInboundSpeed () const { return m_StreamingInboundSpeed; } bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; } // datagram @@ -300,6 +303,7 @@ namespace client int m_StreamingAckDelay; int m_StreamingOutboundSpeed; + int m_StreamingInboundSpeed; bool m_IsStreamingAnswerPings; std::shared_ptr m_StreamingDestination; // default std::map > m_StreamingDestinationsByPorts; diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index e010ac83..bbb9d511 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -70,6 +70,7 @@ namespace stream std::shared_ptr remote, int port): m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), + m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (true), m_IsTimeOutResend (false), m_LocalDestination (local), @@ -78,18 +79,25 @@ namespace stream m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), m_NumResendAttempts (0), m_MTU (STREAMING_MTU) + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), + m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed + m_NumResendAttempts (0), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); m_RemoteIdentity = remote->GetIdentity (); auto outboundSpeed = local.GetOwner ()->GetStreamingOutboundSpeed (); if (outboundSpeed) m_MinPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed; + + auto inboundSpeed = local.GetOwner ()->GetStreamingInboundSpeed (); // for limit inbound speed + if (inboundSpeed) + m_PacketACKInterval = (1000000LL*STREAMING_MTU)/inboundSpeed; } Stream::Stream (boost::asio::io_service& service, StreamingDestination& local): m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), + m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (true), m_IsTimeOutResend (false), m_LocalDestination (local), @@ -98,12 +106,18 @@ namespace stream m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), m_NumResendAttempts (0), m_MTU (STREAMING_MTU) + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), + m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed + m_NumResendAttempts (0), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); auto outboundSpeed = local.GetOwner ()->GetStreamingOutboundSpeed (); if (outboundSpeed) - m_MinPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed; + m_MinPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed; + + auto inboundSpeed = local.GetOwner ()->GetStreamingInboundSpeed (); // for limit inbound speed + if (inboundSpeed) + m_PacketACKInterval = (1000000LL*STREAMING_MTU)/inboundSpeed; } Stream::~Stream () @@ -754,10 +768,26 @@ namespace stream void Stream::SendQuickAck () { int32_t lastReceivedSeqn = m_LastReceivedSequenceNumber; + // for limit inbound speed + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + int numPackets = 0; + int64_t passedTime = m_PacketACKInterval * INITIAL_WINDOW_SIZE; // in microseconds // while m_LastACKSendTime == 0 + if (m_LastACKSendTime) + passedTime = (ts - m_LastACKSendTime)*1000; // in microseconds + numPackets = (passedTime + m_PacketACKIntervalRem) / m_PacketACKInterval; + m_PacketACKIntervalRem = (passedTime + m_PacketACKIntervalRem) - (numPackets * m_PacketACKInterval); + if (m_LastConfirmedReceivedSequenceNumber + numPackets < m_LastReceivedSequenceNumber) + lastReceivedSeqn = m_LastConfirmedReceivedSequenceNumber + numPackets; + if (numPackets == 0) return; + // for limit inbound speed if (!m_SavedPackets.empty ()) { - int32_t seqn = (*m_SavedPackets.rbegin ())->GetSeqn (); - if (seqn > lastReceivedSeqn) lastReceivedSeqn = seqn; + for (auto it: m_SavedPackets) + { + auto seqn = it->GetSeqn (); + if (m_LastConfirmedReceivedSequenceNumber + numPackets < int(seqn)) break; // for limit inbound speed + if (seqn > lastReceivedSeqn) lastReceivedSeqn = seqn; + } } if (lastReceivedSeqn < 0) { @@ -786,6 +816,11 @@ namespace stream for (auto it: m_SavedPackets) { auto seqn = it->GetSeqn (); + if (m_LastConfirmedReceivedSequenceNumber + numPackets < int(seqn)) // for limit inbound speed + { + htobe32buf (packet + 12, nextSeqn - 1); + break; + } if (numNacks + (seqn - nextSeqn) >= 256) { LogPrint (eLogError, "Streaming: Number of NACKs exceeds 256. seqn=", seqn, " nextSeqn=", nextSeqn); @@ -827,6 +862,8 @@ namespace stream p.len = size; SendPackets (std::vector { &p }); + m_LastACKSendTime = ts; // for limit inbound speed + m_LastConfirmedReceivedSequenceNumber = lastReceivedSeqn; // for limit inbound speed LogPrint (eLogDebug, "Streaming: Quick Ack sent. ", (int)numNacks, " NACKs"); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 22dad0e3..b1efcb60 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -249,6 +249,7 @@ namespace stream uint32_t m_TunnelsChangeSequenceNumber; int32_t m_LastReceivedSequenceNumber; int32_t m_PreviousReceivedSequenceNumber; + int32_t m_LastConfirmedReceivedSequenceNumber; // for limit inbound speed StreamStatus m_Status; bool m_IsAckSendScheduled; bool m_IsNAcked; @@ -277,6 +278,7 @@ namespace stream float m_WindowSize, m_LastWindowDropSize; int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample, m_PrevRTT, m_Jitter; uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, m_DropWindowDelayTime, m_LastSendTime; // microseconds + uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed int m_NumResendAttempts, m_NumPacketsToSend; size_t m_MTU; }; diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 3dfc6040..4f91c564 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -472,6 +472,7 @@ namespace client options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY); options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY); options[I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED, DEFAULT_MAX_OUTBOUND_SPEED); + options[I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED, DEFAULT_MAX_INBOUND_SPEED); options[I2CP_PARAM_STREAMING_ANSWER_PINGS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_ANSWER_PINGS, isServer ? DEFAULT_ANSWER_PINGS : false); options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE); std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "0,4"); From b4fcf764805dfa705c400a72733d4a13a2378daa Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 17 Aug 2024 17:52:42 -0400 Subject: [PATCH 016/527] fixed warning --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index bbb9d511..bc1672fe 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -786,7 +786,7 @@ namespace stream { auto seqn = it->GetSeqn (); if (m_LastConfirmedReceivedSequenceNumber + numPackets < int(seqn)) break; // for limit inbound speed - if (seqn > lastReceivedSeqn) lastReceivedSeqn = seqn; + if ((int)seqn > lastReceivedSeqn) lastReceivedSeqn = seqn; } } if (lastReceivedSeqn < 0) From 28adb54c0a95b7134a5c5db35e7d3af3faba448b Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 18 Aug 2024 13:33:16 -0400 Subject: [PATCH 017/527] don't send quick ack for each duplicated packet --- libi2pd/Streaming.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index bc1672fe..2f4d5c21 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -237,8 +237,14 @@ namespace stream UpdateCurrentRemoteLease (); } m_PreviousReceivedSequenceNumber = receivedSeqn; - SendQuickAck (); // resend ack for previous message again m_LocalDestination.DeletePacket (packet); // packet dropped + if (!m_IsAckSendScheduled) + { + SendQuickAck (); // resend ack for previous message again + auto ackTimeout = m_RTT/10; + if (ackTimeout > m_AckDelay) ackTimeout = m_AckDelay; + ScheduleAck (ackTimeout); + } } else { From 32ab95478e8f692428fcb037f95a54050dc5634f Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 18 Aug 2024 18:34:28 -0400 Subject: [PATCH 018/527] check crypto type and congestion of connected peer for tunnel --- libi2pd/Transports.cpp | 2 +- libi2pd/Transports.h | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 9a10ca72..4818d57f 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -1055,7 +1055,7 @@ namespace transport [isHighBandwidth](std::shared_ptr peer)->bool { // connected, not overloaded and not slow - return !peer->router && peer->IsConnected () && peer->isReachable && + return !peer->router && peer->IsConnected () && peer->isEligible && 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 0ad0c616..12846aa5 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -72,17 +72,18 @@ namespace transport uint64_t creationTime, nextRouterInfoUpdateTime; std::vector > delayedMessages; std::vector priority; - bool isHighBandwidth, isReachable; + bool isHighBandwidth, isEligible; Peer (std::shared_ptr r, uint64_t ts): numAttempts (0), router (r), creationTime (ts), nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL), - isHighBandwidth (false), isReachable (false) + isHighBandwidth (false), isEligible (false) { if (router) { isHighBandwidth = router->IsHighBandwidth (); - isReachable = (bool)router->GetCompatibleTransports (true); + isEligible = router->IsECIES () && (bool)router->GetCompatibleTransports (true) && // reachable + router->GetCongestion () != i2p::data::RouterInfo::eRejectAll; } } @@ -101,7 +102,8 @@ namespace transport if (router) { isHighBandwidth = router->IsHighBandwidth (); - isReachable = (bool)router->GetCompatibleTransports (true); + isEligible = router->IsECIES () && (bool)router->GetCompatibleTransports (true) && // reachable + router->GetCongestion () != i2p::data::RouterInfo::eRejectAll; } } From 0df895b6a758e238bd8e6eb09265af9cd53d890c Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 19 Aug 2024 14:39:07 -0400 Subject: [PATCH 019/527] check minimal router version for connected peer selection --- libi2pd/Transports.cpp | 11 +++++++++++ libi2pd/Transports.h | 17 ++++------------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 4818d57f..de0e5b5b 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -131,6 +131,17 @@ namespace transport LogPrint(eLogError, "Transports: Return null DHKeys"); } + void Peer::UpdateParams (std::shared_ptr router) + { + if (router) + { + isHighBandwidth = router->IsHighBandwidth (); + isEligible =(bool)router->GetCompatibleTransports (true) && // reachable + router->GetCongestion () != i2p::data::RouterInfo::eRejectAll && // accepts tunnel + router->IsECIES () && router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION; // not too old + } + } + Transports transports; Transports::Transports (): diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 12846aa5..e4526cd5 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -79,12 +79,7 @@ namespace transport nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL), isHighBandwidth (false), isEligible (false) { - if (router) - { - isHighBandwidth = router->IsHighBandwidth (); - isEligible = router->IsECIES () && (bool)router->GetCompatibleTransports (true) && // reachable - router->GetCongestion () != i2p::data::RouterInfo::eRejectAll; - } + UpdateParams (router); } void Done () @@ -99,15 +94,11 @@ namespace transport void SetRouter (std::shared_ptr r) { router = r; - if (router) - { - isHighBandwidth = router->IsHighBandwidth (); - isEligible = router->IsECIES () && (bool)router->GetCompatibleTransports (true) && // reachable - router->GetCongestion () != i2p::data::RouterInfo::eRejectAll; - } + UpdateParams (router); } - bool IsConnected () const { return !sessions.empty (); } + bool IsConnected () const { return !sessions.empty (); } + void UpdateParams (std::shared_ptr router); }; const uint64_t SESSION_CREATION_TIMEOUT = 15; // in seconds From 3720a5fce32fb1eae138eff2d83e1a2f5d0b57f1 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 19 Aug 2024 15:51:56 -0400 Subject: [PATCH 020/527] don't select same peer too often --- libi2pd/Transports.cpp | 13 ++++++++++--- libi2pd/Transports.h | 5 +++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index de0e5b5b..e4884d6b 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -977,6 +977,7 @@ namespace transport std::shared_ptr Transports::GetRandomPeer (Filter filter) const { if (m_Peers.empty()) return nullptr; + auto ts = i2p::util::GetSecondsSinceEpoch (); bool found = false; i2p::data::IdentHash ident; { @@ -1017,9 +1018,11 @@ namespace transport it = it1; while (it != it2 && it != m_Peers.end ()) { - if (filter (it->second)) + if (ts > it->second->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL && + filter (it->second)) { ident = it->first; + it->second->lastSelectionTime = ts; found = true; break; } @@ -1031,9 +1034,11 @@ namespace transport it = m_Peers.begin (); while (it != it1 && it != m_Peers.end ()) { - if (filter (it->second)) + if (ts > it->second->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL && + filter (it->second)) { ident = it->first; + it->second->lastSelectionTime = ts; found = true; break; } @@ -1045,9 +1050,11 @@ namespace transport it = it2; while (it != m_Peers.end ()) { - if (filter (it->second)) + if (ts > it->second->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL && + filter (it->second)) { ident = it->first; + it->second->lastSelectionTime = ts; found = true; break; } diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index e4526cd5..70273094 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -64,12 +64,13 @@ namespace transport const int PEER_ROUTER_INFO_UPDATE_INTERVAL = 31*60; // in seconds const int PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE = 7*60; // in seconds const size_t PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE = 25; + const int PEER_SELECTION_MIN_INTERVAL = 20; // in seconds struct Peer { int numAttempts; std::shared_ptr router; std::list > sessions; - uint64_t creationTime, nextRouterInfoUpdateTime; + uint64_t creationTime, nextRouterInfoUpdateTime, lastSelectionTime; std::vector > delayedMessages; std::vector priority; bool isHighBandwidth, isEligible; @@ -77,7 +78,7 @@ namespace transport Peer (std::shared_ptr r, uint64_t ts): numAttempts (0), router (r), creationTime (ts), nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL), - isHighBandwidth (false), isEligible (false) + lastSelectionTime (0), isHighBandwidth (false), isEligible (false) { UpdateParams (router); } From 7be64dad89c4e1800f1a6583dd891e8cb3541b29 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 19 Aug 2024 18:30:49 -0400 Subject: [PATCH 021/527] limit number of resent packets at the time --- libi2pd/Streaming.cpp | 18 ++++++++++++------ libi2pd/Streaming.h | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 2f4d5c21..14598b91 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -79,9 +79,9 @@ namespace stream m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), m_LastSendTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed - m_NumResendAttempts (0), m_MTU (STREAMING_MTU) + m_NumResendAttempts (0), m_NumPacketsToSend (0), m_NumPacketsToResend (0), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); m_RemoteIdentity = remote->GetIdentity (); @@ -106,9 +106,9 @@ namespace stream m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), m_LastSendTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed - m_NumResendAttempts (0), m_MTU (STREAMING_MTU) + m_NumResendAttempts (0), m_NumPacketsToSend (0), m_NumPacketsToResend (0), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); auto outboundSpeed = local.GetOwner ()->GetStreamingOutboundSpeed (); @@ -461,6 +461,7 @@ namespace stream m_IsNAcked = false; m_IsResendNeeded = false; int nackCount = packet->GetNACKCount (); + m_NumPacketsToResend = nackCount; for (auto it = m_SentPackets.begin (); it != m_SentPackets.end ();) { auto seqn = (*it)->GetSeqn (); @@ -1201,6 +1202,7 @@ namespace stream m_IsTimeOutResend = true; m_IsNAcked = false; m_IsResendNeeded = false; + m_NumPacketsToSend = 1; ResendPacket (); // send one packet per RTO, waiting for ack } } @@ -1217,6 +1219,7 @@ namespace stream } // collect packets to resend + int numPacketsToResend = m_NumPacketsToResend; auto ts = i2p::util::GetMillisecondsSinceEpoch (); std::vector packets; for (auto it : m_SentPackets) @@ -1226,10 +1229,13 @@ namespace stream if (ts < it->sendTime + m_RTO*2) it->resent = true; else + { it->resent = false; - it->sendTime = ts; + it->sendTime = ts; + } packets.push_back (it); - if (int(packets.size ()) >= m_NumPacketsToSend) break; + m_NumPacketsToResend--; + if ((int)packets.size () >= m_NumPacketsToSend || (int)packets.size () >= numPacketsToResend) break; } } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index b1efcb60..665c73f4 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -279,7 +279,7 @@ namespace stream int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample, m_PrevRTT, m_Jitter; uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, m_DropWindowDelayTime, m_LastSendTime; // microseconds uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed - int m_NumResendAttempts, m_NumPacketsToSend; + int m_NumResendAttempts, m_NumPacketsToSend, m_NumPacketsToResend; size_t m_MTU; }; From d169b422da52c2a30f4c3f3761362da07564ff85 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 19 Aug 2024 19:10:00 -0400 Subject: [PATCH 022/527] drop window if remote lease changes --- libi2pd/Streaming.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 14598b91..8f6e567b 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1418,6 +1418,16 @@ namespace stream LogPrint (eLogWarning, "Streaming: Remote LeaseSet not found"); m_CurrentRemoteLease = nullptr; } + // drop window to initial upon RemoteLease change + m_RTO = INITIAL_RTO; + m_WindowSize = INITIAL_WINDOW_SIZE; + m_LastWindowDropSize = 0; + m_WindowIncCounter = 0; + m_IsWinDropped = true; + m_IsFirstRttSample = true; + m_DropWindowDelayTime = 0; + m_IsFirstACK = true; + UpdatePacingTime (); } void Stream::ResetRoutingPath () From fa218d3cf5149a97bfcfcb931fc279b7d0a803b2 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 20 Aug 2024 15:50:37 -0400 Subject: [PATCH 023/527] reset routing path if session is stuck --- libi2pd/Datagram.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index f87f9653..9c80662a 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -383,8 +383,8 @@ namespace datagram } auto path = m_RoutingSession->GetSharedRoutingPath(); - if (path && m_RoutingSession->IsRatchets () && - m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT) + if (path && m_RoutingSession->IsRatchets () && (m_RoutingSession->CleanupUnconfirmedTags () || + m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT)) { m_RoutingSession->SetSharedRoutingPath (nullptr); path = nullptr; From 02c52f59cb6ccf519713978c4553221cd20d410f Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 20 Aug 2024 20:59:41 -0400 Subject: [PATCH 024/527] max flush interval --- libi2pd/Datagram.cpp | 12 ++++++++---- libi2pd/Datagram.h | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 9c80662a..86e38805 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -288,8 +288,8 @@ namespace datagram DatagramSession::DatagramSession(std::shared_ptr localDestination, const i2p::data::IdentHash & remoteIdent) : - m_LocalDestination(localDestination), - m_RemoteIdent(remoteIdent), + m_LocalDestination(localDestination), m_RemoteIdent(remoteIdent), + m_LastUse (0), m_LastFlush (0), m_RequestingLS(false) { } @@ -310,8 +310,12 @@ namespace datagram if (msg || m_SendQueue.empty ()) m_SendQueue.push_back(msg); // flush queue right away if full - if (!msg || m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE) + if (!msg || m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE || + m_LastUse > m_LastFlush + DATAGRAM_MAX_FLUSH_INTERVAL) + { FlushSendQueue(); + m_LastFlush = ts; + } } DatagramSession::Info DatagramSession::GetSessionInfo() const @@ -344,7 +348,7 @@ namespace datagram if(path) path->updateTime = i2p::util::GetSecondsSinceEpoch (); if (IsRatchets ()) - SendMsg (nullptr); // send empty message in case if we have some data to send + SendMsg (nullptr); // send empty message in case if we don't have some data to send } std::shared_ptr DatagramSession::GetSharedRoutingPath () diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index 45edecab..5a0bfc93 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -43,6 +43,7 @@ namespace datagram const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000; // max 64 messages buffered in send queue for each datagram session const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64; + const uint64_t DATAGRAM_MAX_FLUSH_INTERVAL = 5; // in milliseconds class DatagramSession : public std::enable_shared_from_this { @@ -98,7 +99,7 @@ namespace datagram std::shared_ptr m_RoutingSession; std::vector > m_PendingRoutingSessions; std::vector > m_SendQueue; - uint64_t m_LastUse; + uint64_t m_LastUse, m_LastFlush; // milliseconds bool m_RequestingLS; }; From bd98f2c3eea23c7c9e75c44dab6a6d7f51acc336 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 20 Aug 2024 21:21:28 -0400 Subject: [PATCH 025/527] max flush interval --- libi2pd/Datagram.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 86e38805..3f2fc8d0 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -314,7 +314,7 @@ namespace datagram m_LastUse > m_LastFlush + DATAGRAM_MAX_FLUSH_INTERVAL) { FlushSendQueue(); - m_LastFlush = ts; + m_LastFlush = m_LastUse; } } From c43926083edaffda374289cc99d7204bb2f98f98 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 21 Aug 2024 14:07:04 -0400 Subject: [PATCH 026/527] don't include already expired lease to LeaseSet --- libi2pd/LeaseSet.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 7834b6b9..cf94b955 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -861,12 +861,13 @@ namespace data m_Buffer[offset] = num; offset++; // num leases for (int i = 0; i < num; i++) { + auto ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // in seconds, 1 minute before expiration + if (ts <= publishedTimestamp) continue; // already expired, skip + if (ts > expirationTime) expirationTime = ts; memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32); offset += 32; // gateway id htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ()); offset += 4; // tunnel id - auto ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // in seconds, 1 minute before expiration - if (ts > expirationTime) expirationTime = ts; htobe32buf (m_Buffer + offset, ts); offset += 4; // end date } From 0191e58b057970fd1fbdc45d791885b9dd2c8185 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 21 Aug 2024 16:28:19 -0400 Subject: [PATCH 027/527] adjust number of leases in LS2 if expired tunnels --- libi2pd/LeaseSet.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index cf94b955..c2984bdf 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -858,11 +858,17 @@ namespace data } // leases uint32_t expirationTime = 0; // in seconds + int skipped = 0; auto numLeasesPos = offset; m_Buffer[offset] = num; offset++; // num leases for (int i = 0; i < num; i++) { auto ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // in seconds, 1 minute before expiration - if (ts <= publishedTimestamp) continue; // already expired, skip + if (ts <= publishedTimestamp) + { + // already expired, skip + skipped++; + continue; + } if (ts > expirationTime) expirationTime = ts; memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32); offset += 32; // gateway id @@ -871,6 +877,14 @@ namespace data htobe32buf (m_Buffer + offset, ts); offset += 4; // end date } + if (skipped > 0) + { + // adjust num leases + if (skipped > num) skipped = num; + num -= skipped; + m_BufferLen -= skipped*LEASE2_SIZE; + m_Buffer[numLeasesPos] = num; + } // update expiration if (expirationTime) { From ff5c76f8f269a827a2b6f531579e5537c45cb47e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 21 Aug 2024 19:21:02 -0400 Subject: [PATCH 028/527] don't include expired lease to LeaseSet for I2Cp --- libi2pd/LeaseSet.cpp | 26 +++++++++++++++++++++----- libi2pd_client/I2CP.cpp | 8 +++++--- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index c2984bdf..66faed84 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -728,25 +728,41 @@ namespace data memset (m_Buffer + offset, 0, signingKeyLen); offset += signingKeyLen; // num leases + auto numLeasesPos = offset; m_Buffer[offset] = num; offset++; // leases m_Leases = m_Buffer + offset; auto currentTime = i2p::util::GetMillisecondsSinceEpoch (); + int skipped = 0; for (int i = 0; i < num; i++) { + uint64_t ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration + ts *= 1000; // in milliseconds + if (ts <= currentTime) + { + // already expired, skip + skipped++; + continue; + } + if (ts > m_ExpirationTime) m_ExpirationTime = ts; + // make sure leaseset is newer than previous, but adding some time to expiration date + ts += (currentTime - tunnels[i]->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32); offset += 32; // gateway id htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ()); offset += 4; // tunnel id - uint64_t ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration - ts *= 1000; // in milliseconds - if (ts > m_ExpirationTime) m_ExpirationTime = ts; - // make sure leaseset is newer than previous, but adding some time to expiration date - ts += (currentTime - tunnels[i]->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs htobe64buf (m_Buffer + offset, ts); offset += 8; // end date } + if (skipped > 0) + { + // adjust num leases + if (skipped > num) skipped = num; + num -= skipped; + m_BufferLen -= skipped*LEASE_SIZE; + m_Buffer[numLeasesPos] = num; + } // we don't sign it yet. must be signed later on } diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 519f4ed6..12d2d0c9 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -102,15 +102,15 @@ namespace client i2p::data::LocalLeaseSet ls (m_Identity, priv, tunnels); // we don't care about encryption key, we need leases only m_LeaseSetExpirationTime = ls.GetExpirationTime (); uint8_t * leases = ls.GetLeases (); - leases[-1] = tunnels.size (); - if (m_Owner) + int numLeases = leases[-1]; + if (m_Owner && numLeases) { uint16_t sessionID = m_Owner->GetSessionID (); if (sessionID != 0xFFFF) { m_IsCreatingLeaseSet = true; htobe16buf (leases - 3, sessionID); - size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*tunnels.size (); + size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*numLeases; m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l); m_LeaseSetCreationTimer.expires_from_now (boost::posix_time::seconds (I2CP_LEASESET_CREATION_TIMEOUT)); auto s = GetSharedFromThis (); @@ -124,6 +124,8 @@ namespace client }); } } + else + LogPrint (eLogError, "I2CP: Can't request LeaseSet"); } void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len) From 879d54fad46a65b490bd56a1a8c5b7e4672a347b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 23 Aug 2024 22:01:08 -0400 Subject: [PATCH 029/527] replaced boost::date_time by functions from std --- daemon/I2PControl.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index e2ce7be4..fc7f2257 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -8,14 +8,12 @@ #include #include +#include #include #include // Use global placeholders from boost introduced when local_time.hpp is loaded #define BOOST_BIND_GLOBAL_PLACEHOLDERS - -#include -#include #include #include @@ -258,9 +256,9 @@ namespace client header << "Content-Length: " << boost::lexical_cast(len) << "\r\n"; header << "Content-Type: application/json\r\n"; header << "Date: "; - auto facet = new boost::local_time::local_time_facet ("%a, %d %b %Y %H:%M:%S GMT"); - header.imbue(std::locale (header.getloc(), facet)); - header << boost::posix_time::second_clock::local_time() << "\r\n"; + std::time_t t = std::time (nullptr); + std::tm tm = *std::gmtime (&t); + header << std::put_time(&tm, "%a, %d %b %Y %T GMT") << "\r\n"; header << "\r\n"; offset = header.str ().size (); memcpy (buf->data (), header.str ().c_str (), offset); From 65ceb082903b8107ab8d4679838ad305368d1f86 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 23 Aug 2024 22:35:52 -0400 Subject: [PATCH 030/527] correct translation of Network status --- i18n/Chinese.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/Chinese.cpp b/i18n/Chinese.cpp index c423165b..ad46178c 100644 --- a/i18n/Chinese.cpp +++ b/i18n/Chinese.cpp @@ -64,7 +64,7 @@ namespace chinese // language namespace {"Full cone NAT", "全锥型NAT"}, {"No Descriptors", "无描述符"}, {"Uptime", "运行时间"}, - {"Network status", "IPv4 网络状态"}, + {"Network status", "网络状态"}, {"Network status v6", "IPv6 网络状态"}, {"Stopping in", "距停止还有:"}, {"Family", "家族"}, From e7423b1ffc1d2d9d9c868f6beaf671b134eef41a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 25 Aug 2024 19:07:01 -0400 Subject: [PATCH 031/527] save timestamp from epoch instead local time to profiles --- libi2pd/Profiling.cpp | 48 ++++++++++++++++++++++++------------------ libi2pd/Profiling.h | 11 +++++----- libi2pd/RouterInfo.cpp | 1 + libi2pd/Transports.cpp | 1 + 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/libi2pd/Profiling.cpp b/libi2pd/Profiling.cpp index 6dcdabec..27925434 100644 --- a/libi2pd/Profiling.cpp +++ b/libi2pd/Profiling.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include "Base.h" @@ -27,14 +28,9 @@ namespace data static std::unordered_map > g_Profiles; static std::mutex g_ProfilesMutex; - static boost::posix_time::ptime GetTime () - { - return boost::posix_time::second_clock::local_time(); - } - RouterProfile::RouterProfile (): - m_LastUpdateTime (GetTime ()), m_IsUpdated (false), - m_LastDeclineTime (0), m_LastUnreachableTime (0), + m_IsUpdated (false), m_LastDeclineTime (0), m_LastUnreachableTime (0), + m_LastUpdateTime (i2p::util::GetSecondsSinceEpoch ()), m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0), m_NumTimesTaken (0), m_NumTimesRejected (0), m_HasConnected (false), m_IsDuplicated (false) @@ -43,7 +39,7 @@ namespace data void RouterProfile::UpdateTime () { - m_LastUpdateTime = GetTime (); + m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch (); m_IsUpdated = true; } @@ -62,7 +58,7 @@ namespace data usage.put (PEER_PROFILE_USAGE_DUPLICATED, true); // fill property tree boost::property_tree::ptree pt; - pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime)); + pt.put (PEER_PROFILE_LAST_UPDATE_TIMESTAMP, m_LastUpdateTime); if (m_LastUnreachableTime) pt.put (PEER_PROFILE_LAST_UNREACHABLE_TIME, m_LastUnreachableTime); pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation); @@ -104,10 +100,22 @@ namespace data try { - auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, ""); - if (t.length () > 0) - m_LastUpdateTime = boost::posix_time::time_from_string (t); - if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT) + auto ts = pt.get (PEER_PROFILE_LAST_UPDATE_TIMESTAMP, 0); + if (ts) + m_LastUpdateTime = ts; + else + { + // try old lastupdatetime + auto ut = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, ""); + if (ut.length () > 0) + { + std::istringstream ss (ut); std::tm t; + ss >> std::get_time(&t, "%Y-%b-%d %H:%M:%S"); + if (!ss.fail()) + m_LastUpdateTime = mktime (&t); // t is local time + } + } + if (i2p::util::GetSecondsSinceEpoch () - m_LastUpdateTime < PEER_PROFILE_EXPIRATION_TIMEOUT) { m_LastUnreachableTime = pt.get (PEER_PROFILE_LAST_UNREACHABLE_TIME, 0); try @@ -277,13 +285,13 @@ namespace data std::future PersistProfiles () { - auto ts = GetTime (); + auto ts = i2p::util::GetSecondsSinceEpoch (); std::list > > tmp; { std::unique_lock l(g_ProfilesMutex); for (auto it = g_Profiles.begin (); it != g_Profiles.end ();) { - if ((ts - it->second->GetLastUpdateTime ()).total_seconds () > PEER_PROFILE_PERSIST_INTERVAL) + if (ts - it->second->GetLastUpdateTime () > PEER_PROFILE_PERSIST_INTERVAL) { if (it->second->IsUpdated ()) tmp.push_back (std::make_pair (it->first, it->second)); @@ -305,9 +313,9 @@ namespace data std::unique_lock l(g_ProfilesMutex); std::swap (tmp, g_Profiles); } - auto ts = GetTime (); + auto ts = i2p::util::GetSecondsSinceEpoch (); for (auto& it: tmp) - if (it.second->IsUseful() && (it.second->IsUpdated () || (ts - it.second->GetLastUpdateTime ()).total_seconds () < PEER_PROFILE_EXPIRATION_TIMEOUT*3600)) + if (it.second->IsUseful() && (it.second->IsUpdated () || ts - it.second->GetLastUpdateTime () < PEER_PROFILE_EXPIRATION_TIMEOUT)) it.second->Save (it.first); } @@ -325,7 +333,7 @@ namespace data LogPrint(eLogWarning, "Profiling: Can't stat(): ", path); continue; } - if (now - st.st_mtime >= PEER_PROFILE_EXPIRATION_TIMEOUT*3600) + if (now - st.st_mtime >= PEER_PROFILE_EXPIRATION_TIMEOUT) { LogPrint(eLogDebug, "Profiling: Removing expired peer profile: ", path); i2p::fs::Remove(path); @@ -336,11 +344,11 @@ namespace data std::future DeleteObsoleteProfiles () { { - auto ts = GetTime (); + auto ts = i2p::util::GetSecondsSinceEpoch (); std::unique_lock l(g_ProfilesMutex); for (auto it = g_Profiles.begin (); it != g_Profiles.end ();) { - if ((ts - it->second->GetLastUpdateTime ()).total_seconds () >= PEER_PROFILE_EXPIRATION_TIMEOUT*3600) + if (ts - it->second->GetLastUpdateTime () >= PEER_PROFILE_EXPIRATION_TIMEOUT) it = g_Profiles.erase (it); else it++; diff --git a/libi2pd/Profiling.h b/libi2pd/Profiling.h index 3245d9f0..1846f08e 100644 --- a/libi2pd/Profiling.h +++ b/libi2pd/Profiling.h @@ -11,7 +11,6 @@ #include #include -#include #include "Identity.h" namespace i2p @@ -22,7 +21,8 @@ namespace data const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation"; const char PEER_PROFILE_SECTION_USAGE[] = "usage"; // params - const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime"; + const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime"; // deprecated + const char PEER_PROFILE_LAST_UPDATE_TIMESTAMP[] = "lastupdatetimestamp"; const char PEER_PROFILE_LAST_UNREACHABLE_TIME[] = "lastunreachabletime"; const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed"; const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined"; @@ -32,7 +32,7 @@ namespace data const char PEER_PROFILE_USAGE_CONNECTED[] = "connected"; const char PEER_PROFILE_USAGE_DUPLICATED[] = "duplicated"; - const int PEER_PROFILE_EXPIRATION_TIMEOUT = 36; // in hours (1.5 days) + const int PEER_PROFILE_EXPIRATION_TIMEOUT = 36*60*60; // in seconds (1.5 days) const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 1500; // in seconds (25 minutes) const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 900; // in seconds (15 minutes) const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_TIMEOUT = 5400; // in seconds (1.5 hours) @@ -62,7 +62,7 @@ namespace data void Connected (); void Duplicated (); - boost::posix_time::ptime GetLastUpdateTime () const { return m_LastUpdateTime; }; + uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; }; bool IsUpdated () const { return m_IsUpdated; }; bool IsUseful() const; @@ -79,9 +79,8 @@ namespace data private: - boost::posix_time::ptime m_LastUpdateTime; // TODO: use std::chrono bool m_IsUpdated; - uint64_t m_LastDeclineTime, m_LastUnreachableTime; // in seconds + uint64_t m_LastDeclineTime, m_LastUnreachableTime, m_LastUpdateTime; // in seconds // participation uint32_t m_NumTunnelsAgreed; uint32_t m_NumTunnelsDeclined; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index fafbe884..d819999e 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -12,6 +12,7 @@ #include #include #include +#include // for boost::to_lower #if (BOOST_VERSION >= 105300) #include #endif diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index e4884d6b..cf30b428 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -6,6 +6,7 @@ * See full license text in LICENSE file at top of project tree */ +#include // for boost::to_lower #include "Log.h" #include "Crypto.h" #include "RouterContext.h" From 0992a5124fc9d214624fccdf4386a50f53d6f8ef Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 25 Aug 2024 20:18:55 -0400 Subject: [PATCH 032/527] removed dependency from boost::date_time --- Makefile.bsd | 2 +- Makefile.haiku | 2 +- Makefile.homebrew | 4 ++-- Makefile.linux | 3 +-- Makefile.mingw | 1 - Makefile.osx | 4 ++-- build/CMakeLists.txt | 4 ++-- 7 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Makefile.bsd b/Makefile.bsd index 14449381..f9a47375 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -15,4 +15,4 @@ endif DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1 INCFLAGS = -I/usr/include/ -I/usr/local/include/ LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib -LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread +LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_filesystem -lboost_program_options -lpthread diff --git a/Makefile.haiku b/Makefile.haiku index 85c2835d..b5ecb1e8 100644 --- a/Makefile.haiku +++ b/Makefile.haiku @@ -2,7 +2,7 @@ CXX = g++ CXXFLAGS := -Wall -std=c++11 INCFLAGS = -I/system/develop/headers DEFINES = -D_DEFAULT_SOURCE -D_GNU_SOURCE -LDLIBS = -lbe -lbsd -lnetwork -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread +LDLIBS = -lbe -lbsd -lnetwork -lz -lcrypto -lssl -lboost_system -lboost_filesystem -lboost_program_options -lpthread ifeq ($(USE_UPNP),yes) DEFINES += -DUSE_UPNP diff --git a/Makefile.homebrew b/Makefile.homebrew index 496e203c..f19d64bb 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -11,14 +11,14 @@ LDFLAGS ?= ${LD_DEBUG} DEFINES += -DMAC_OSX ifeq ($(USE_STATIC),yes) - LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_date_time.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a + LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a ifeq ($(USE_UPNP),yes) LDLIBS += ${UPNPROOT}/lib/libminiupnpc.a endif LDLIBS += -lpthread -ldl else LDFLAGS += -L${SSLROOT}/lib -L${BOOSTROOT}/lib - LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread + LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_filesystem -lboost_program_options -lpthread ifeq ($(USE_UPNP),yes) LDFLAGS += -L${UPNPROOT}/lib LDLIBS += -lminiupnpc diff --git a/Makefile.linux b/Makefile.linux index 6c7a4619..86527b9a 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -39,7 +39,6 @@ ifeq ($(USE_STATIC),yes) # the shared libraries from the glibc version used for linking LIBDIR := /usr/lib/$(SYS) LDLIBS += $(LIBDIR)/libboost_system.a - LDLIBS += $(LIBDIR)/libboost_date_time.a LDLIBS += $(LIBDIR)/libboost_filesystem.a LDLIBS += $(LIBDIR)/libboost_program_options.a LDLIBS += $(LIBDIR)/libssl.a @@ -50,7 +49,7 @@ ifeq ($(USE_UPNP),yes) endif LDLIBS += -lpthread -ldl else - LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread + LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_filesystem -lboost_program_options -lpthread ifeq ($(USE_UPNP),yes) LDLIBS += -lminiupnpc endif diff --git a/Makefile.mingw b/Makefile.mingw index 38da225a..4a9d033b 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -18,7 +18,6 @@ endif LDLIBS += \ $(MINGW_PREFIX)/lib/libboost_system-mt.a \ - $(MINGW_PREFIX)/lib/libboost_date_time-mt.a \ $(MINGW_PREFIX)/lib/libboost_filesystem-mt.a \ $(MINGW_PREFIX)/lib/libboost_program_options-mt.a \ $(MINGW_PREFIX)/lib/libssl.a \ diff --git a/Makefile.osx b/Makefile.osx index 467c9fdd..963d4898 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -7,9 +7,9 @@ LDFLAGS += -Wl,-dead_strip LDFLAGS += -Wl,-dead_strip_dylibs ifeq ($(USE_STATIC),yes) - LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread + LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread else - LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread + LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_filesystem -lboost_program_options -lpthread endif ifeq ($(USE_UPNP),yes) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 232e427f..be75ca3c 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -277,14 +277,14 @@ else() if(NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") endif() - add_definitions(-DBOOST_ATOMIC_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK) + add_definitions(-DBOOST_ATOMIC_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK) if(WIN32) set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_STATIC_RUNTIME OFF) endif() endif() -find_package(Boost REQUIRED COMPONENTS system filesystem program_options date_time OPTIONAL_COMPONENTS atomic) +find_package(Boost REQUIRED COMPONENTS system filesystem program_options OPTIONAL_COMPONENTS atomic) if(NOT DEFINED Boost_FOUND) message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!") endif() From a69eade1f4359be6fe53b1f30c0ae5185a713b96 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 25 Aug 2024 21:35:33 -0400 Subject: [PATCH 033/527] use pool's rng for random tunnel/remote lease selection --- libi2pd/Datagram.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 3f2fc8d0..5db072a4 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -417,7 +417,14 @@ namespace datagram auto sz = ls.size(); if (sz) { - auto idx = rand() % sz; + int idx = -1; + if (m_LocalDestination) + { + auto pool = m_LocalDestination->GetTunnelPool (); + if (pool) + idx = m_LocalDestination->GetTunnelPool ()->GetRng ()() % sz; + } + if (idx < 0) idx = rand () % sz; path->remoteLease = ls[idx]; } else @@ -443,7 +450,14 @@ namespace datagram auto sz = ls.size(); if (sz) { - auto idx = rand() % sz; + int idx = -1; + if (m_LocalDestination) + { + auto pool = m_LocalDestination->GetTunnelPool (); + if (pool) + idx = m_LocalDestination->GetTunnelPool ()->GetRng ()() % sz; + } + if (idx < 0) idx = rand () % sz; path->remoteLease = ls[idx]; } else From 66223792f3fdffa180d3807e58a6dad2c7f122b4 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 26 Aug 2024 19:35:13 -0400 Subject: [PATCH 034/527] use std::mt19937 instead rand(). termination timeout variance --- libi2pd/NTCP2.cpp | 21 +++++++++++---------- libi2pd/NTCP2.h | 10 +++++++--- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 164ec217..35993aa0 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -108,10 +108,10 @@ namespace transport m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); } - void NTCP2Establisher::CreateSessionRequestMessage () + void NTCP2Establisher::CreateSessionRequestMessage (std::mt19937& rng) { // create buffer and fill padding - auto paddingLength = rand () % (NTCP2_SESSION_REQUEST_MAX_SIZE - 64); // message length doesn't exceed 287 bytes + auto paddingLength = rng () % (NTCP2_SESSION_REQUEST_MAX_SIZE - 64); // message length doesn't exceed 287 bytes m_SessionRequestBufferLen = paddingLength + 64; RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); // encrypt X @@ -149,9 +149,9 @@ namespace transport i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt } - void NTCP2Establisher::CreateSessionCreatedMessage () + void NTCP2Establisher::CreateSessionCreatedMessage (std::mt19937& rng) { - auto paddingLen = rand () % (NTCP2_SESSION_CREATED_MAX_SIZE - 64); + auto paddingLen = rng () % (NTCP2_SESSION_CREATED_MAX_SIZE - 64); m_SessionCreatedBufferLen = paddingLen + 64; RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); // encrypt Y @@ -349,7 +349,7 @@ namespace transport LogPrint (eLogWarning, "NTCP2: Missing NTCP2 address"); } m_NextRouterInfoResendTime = i2p::util::GetSecondsSinceEpoch () + NTCP2_ROUTERINFO_RESEND_INTERVAL + - rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD; + m_Server.GetRng ()() % NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD; } NTCP2Session::~NTCP2Session () @@ -411,7 +411,7 @@ namespace transport { m_IsEstablished = true; m_Establisher.reset (nullptr); - SetTerminationTimeout (NTCP2_TERMINATION_TIMEOUT); + SetTerminationTimeout (NTCP2_TERMINATION_TIMEOUT + m_Server.GetRng ()() % NTCP2_TERMINATION_TIMEOUT_VARIANCE); SendQueue (); transports.PeerConnected (shared_from_this ()); } @@ -464,7 +464,7 @@ namespace transport void NTCP2Session::SendSessionRequest () { - m_Establisher->CreateSessionRequestMessage (); + m_Establisher->CreateSessionRequestMessage (m_Server.GetRng ()); // send message m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch (); boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (), @@ -542,7 +542,7 @@ namespace transport void NTCP2Session::SendSessionCreated () { - m_Establisher->CreateSessionCreatedMessage (); + m_Establisher->CreateSessionCreatedMessage (m_Server.GetRng ()); // send message m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch (); boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (), @@ -1121,7 +1121,7 @@ namespace transport if (GetLastActivityTimestamp () > m_NextRouterInfoResendTime) { m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL + - rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD; + m_Server.GetRng ()() % NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD; SendRouterInfo (); } else @@ -1298,7 +1298,8 @@ namespace transport NTCP2Server::NTCP2Server (): RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()), - m_ProxyType(eNoProxy), m_Resolver(GetService ()) + m_ProxyType(eNoProxy), m_Resolver(GetService ()), + m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL) { } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 1efb482b..e7792bdd 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,8 @@ namespace transport const int NTCP2_CONNECT_TIMEOUT = 5; // 5 seconds const int NTCP2_ESTABLISH_TIMEOUT = 10; // 10 seconds - const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes + const int NTCP2_TERMINATION_TIMEOUT = 115; // 2 minutes - 5 seconds + const int NTCP2_TERMINATION_TIMEOUT_VARIANCE = 10; // 10 seconds const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds const int NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT = 3; // 3 seconds const int NTCP2_ROUTERINFO_RESEND_INTERVAL = 25*60; // 25 minuntes in seconds @@ -103,8 +105,8 @@ namespace transport void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate void CreateEphemeralKey (); - void CreateSessionRequestMessage (); - void CreateSessionCreatedMessage (); + void CreateSessionRequestMessage (std::mt19937& rng); + void CreateSessionCreatedMessage (std::mt19937& rng); void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce); void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce); @@ -248,6 +250,7 @@ namespace transport void Start (); void Stop (); boost::asio::io_service& GetService () { return GetIOService (); }; + std::mt19937& GetRng () { return m_Rng; }; bool AddNTCP2Session (std::shared_ptr session, bool incoming = false); void RemoveNTCP2Session (std::shared_ptr session); @@ -286,6 +289,7 @@ namespace transport boost::asio::ip::tcp::resolver m_Resolver; std::unique_ptr m_ProxyEndpoint; std::shared_ptr m_Address4, m_Address6, m_YggdrasilAddress; + std::mt19937 m_Rng; public: From da0e527777fcdfd8c1f142e8d9c2007bd477d3ac Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 26 Aug 2024 20:57:28 -0400 Subject: [PATCH 035/527] termination check timeout variance --- libi2pd/NTCP2.cpp | 3 ++- libi2pd/NTCP2.h | 3 ++- libi2pd/SSU2.cpp | 3 ++- libi2pd/SSU2.h | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 35993aa0..7f0f2189 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1642,7 +1642,8 @@ namespace transport void NTCP2Server::ScheduleTermination () { - m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP2_TERMINATION_CHECK_TIMEOUT)); + m_TerminationTimer.expires_from_now (boost::posix_time::seconds( + NTCP2_TERMINATION_CHECK_TIMEOUT + m_Rng () % NTCP2_TERMINATION_CHECK_TIMEOUT_VARIANCE)); m_TerminationTimer.async_wait (std::bind (&NTCP2Server::HandleTerminationTimer, this, std::placeholders::_1)); } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index e7792bdd..f7912b54 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -38,7 +38,8 @@ namespace transport const int NTCP2_ESTABLISH_TIMEOUT = 10; // 10 seconds const int NTCP2_TERMINATION_TIMEOUT = 115; // 2 minutes - 5 seconds const int NTCP2_TERMINATION_TIMEOUT_VARIANCE = 10; // 10 seconds - const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds + const int NTCP2_TERMINATION_CHECK_TIMEOUT = 28; // 28 seconds + const int NTCP2_TERMINATION_CHECK_TIMEOUT_VARIANCE = 5; // 5 seconds const int NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT = 3; // 3 seconds const int NTCP2_ROUTERINFO_RESEND_INTERVAL = 25*60; // 25 minuntes in seconds const int NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD = 25*60; // 25 minuntes diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 36c85615..b86e3743 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -914,7 +914,8 @@ namespace transport void SSU2Server::ScheduleTermination () { - m_TerminationTimer.expires_from_now (boost::posix_time::seconds(SSU2_TERMINATION_CHECK_TIMEOUT)); + m_TerminationTimer.expires_from_now (boost::posix_time::seconds( + SSU2_TERMINATION_CHECK_TIMEOUT + m_Rng () % SSU2_TERMINATION_CHECK_TIMEOUT_VARIANCE)); m_TerminationTimer.async_wait (std::bind (&SSU2Server::HandleTerminationTimer, this, std::placeholders::_1)); } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 55746c0f..fd071e8d 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -22,7 +22,8 @@ namespace i2p { namespace transport { - const int SSU2_TERMINATION_CHECK_TIMEOUT = 25; // in seconds + const int SSU2_TERMINATION_CHECK_TIMEOUT = 23; // in seconds + const int SSU2_TERMINATION_CHECK_TIMEOUT_VARIANCE = 5; // in seconds const int SSU2_CLEANUP_INTERVAL = 72; // in seconds const int SSU2_RESEND_CHECK_TIMEOUT = 40; // in milliseconds const int SSU2_RESEND_CHECK_TIMEOUT_VARIANCE = 10; // in milliseconds From 3ff79038b5e2f5912299c7167ebc55723d4b8842 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 27 Aug 2024 15:33:59 -0400 Subject: [PATCH 036/527] handle individual NACKs --- libi2pd/Streaming.cpp | 44 ++++++++++++++++++++++++++++++------------- libi2pd/Streaming.h | 3 ++- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 8f6e567b..d6f0441c 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -81,7 +81,7 @@ namespace stream m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), m_LastSendTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed - m_NumResendAttempts (0), m_NumPacketsToSend (0), m_NumPacketsToResend (0), m_MTU (STREAMING_MTU) + m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); m_RemoteIdentity = remote->GetIdentity (); @@ -108,7 +108,7 @@ namespace stream m_PrevRTTSample (INITIAL_RTT), m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), m_LastSendTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed - m_NumResendAttempts (0), m_NumPacketsToSend (0), m_NumPacketsToResend (0), m_MTU (STREAMING_MTU) + m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); auto outboundSpeed = local.GetOwner ()->GetStreamingOutboundSpeed (); @@ -147,6 +147,8 @@ namespace stream m_ReceiveQueue.pop (); m_LocalDestination.DeletePacket (packet); } + + m_NACKedPackets.clear (); for (auto it: m_SentPackets) m_LocalDestination.DeletePacket (it); @@ -452,6 +454,7 @@ namespace stream bool acknowledged = false; auto ts = i2p::util::GetMillisecondsSinceEpoch (); uint32_t ackThrough = packet->GetAckThrough (); + m_NACKedPackets.clear (); if (ackThrough > m_SequenceNumber) { LogPrint (eLogError, "Streaming: Unexpected ackThrough=", ackThrough, " > seqn=", m_SequenceNumber); @@ -461,7 +464,6 @@ namespace stream m_IsNAcked = false; m_IsResendNeeded = false; int nackCount = packet->GetNACKCount (); - m_NumPacketsToResend = nackCount; for (auto it = m_SentPackets.begin (); it != m_SentPackets.end ();) { auto seqn = (*it)->GetSeqn (); @@ -473,6 +475,7 @@ namespace stream for (int i = 0; i < nackCount; i++) if (seqn == packet->GetNACK (i)) { + m_NACKedPackets.insert (*it); m_IsNAcked = true; nacked = true; break; @@ -1219,23 +1222,38 @@ namespace stream } // collect packets to resend - int numPacketsToResend = m_NumPacketsToResend; auto ts = i2p::util::GetMillisecondsSinceEpoch (); std::vector packets; - for (auto it : m_SentPackets) + if (m_IsNAcked) { - if (ts >= it->sendTime + m_RTO) + for (auto it : m_NACKedPackets) { - if (ts < it->sendTime + m_RTO*2) - it->resent = true; - else + if (ts >= it->sendTime + m_RTO) { - it->resent = false; + if (ts < it->sendTime + m_RTO*2) + it->resent = true; + else + it->resent = false; it->sendTime = ts; + packets.push_back (it); + if ((int)packets.size () >= m_NumPacketsToSend) break; + } + } + } + else + { + for (auto it : m_SentPackets) + { + if (ts >= it->sendTime + m_RTO) + { + if (ts < it->sendTime + m_RTO*2) + it->resent = true; + else + it->resent = false; + it->sendTime = ts; + packets.push_back (it); + if ((int)packets.size () >= m_NumPacketsToSend) break; } - packets.push_back (it); - m_NumPacketsToResend--; - if ((int)packets.size () >= m_NumPacketsToSend || (int)packets.size () >= numPacketsToResend) break; } } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 665c73f4..a0229483 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -269,6 +269,7 @@ namespace stream std::queue m_ReceiveQueue; std::set m_SavedPackets; std::set m_SentPackets; + std::set m_NACKedPackets; boost::asio::deadline_timer m_ReceiveTimer, m_SendTimer, m_ResendTimer, m_AckSendTimer; size_t m_NumSentBytes, m_NumReceivedBytes; uint16_t m_Port; @@ -279,7 +280,7 @@ namespace stream int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample, m_PrevRTT, m_Jitter; uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, m_DropWindowDelayTime, m_LastSendTime; // microseconds uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed - int m_NumResendAttempts, m_NumPacketsToSend, m_NumPacketsToResend; + int m_NumResendAttempts, m_NumPacketsToSend; size_t m_MTU; }; From ae309ca63219db15bb3e4a11feb844cfe9ce3d83 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 27 Aug 2024 21:49:23 -0400 Subject: [PATCH 037/527] use std::filesystem for C++17 --- libi2pd/FS.cpp | 96 ++++++++++++++++++++-------------- libi2pd/FS.h | 6 ++- libi2pd_client/AddressBook.cpp | 17 ++++-- 3 files changed, 73 insertions(+), 46 deletions(-) diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index 47a3e52c..9bb7aee2 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -7,7 +7,6 @@ */ #include -#include #if defined(MAC_OSX) #include @@ -25,6 +24,14 @@ #include "Log.h" #include "Garlic.h" +#if STD_FILESYSTEM +#include +namespace fs_lib = std::filesystem; +#else +#include +namespace fs_lib = boost::filesystem; +#endif + namespace i2p { namespace fs { std::string appName = "i2pd"; @@ -55,13 +62,13 @@ namespace fs { const std::string GetUTF8DataDir () { #ifdef _WIN32 #if (BOOST_VERSION >= 108500) - boost::filesystem::path path (dataDir); + fs_lib::path path (dataDir); #else - boost::filesystem::wpath path (dataDir); + fs_lib::wpath path (dataDir); #endif - auto loc = boost::filesystem::path::imbue(std::locale( std::locale(), new std::codecvt_utf8_utf16() ) ); // convert path to UTF-8 + auto loc = fs_lib::path::imbue(std::locale( std::locale(), new std::codecvt_utf8_utf16() ) ); // convert path to UTF-8 auto dataDirUTF8 = path.string(); - boost::filesystem::path::imbue(loc); // Return locale settings back + fs_lib::path::imbue(loc); // Return locale settings back return dataDirUTF8; #else return dataDir; // linux, osx, android uses UTF-8 by default @@ -92,9 +99,9 @@ namespace fs { else { #if (BOOST_VERSION >= 108500) - dataDir = boost::filesystem::path(commonAppData).string() + "\\" + appName; + dataDir = fs_lib::path(commonAppData).string() + "\\" + appName; #else - dataDir = boost::filesystem::wpath(commonAppData).string() + "\\" + appName; + dataDir = fs_lib::wpath(commonAppData).string() + "\\" + appName; #endif } #else @@ -121,13 +128,13 @@ namespace fs { else { #if (BOOST_VERSION >= 108500) - auto execPath = boost::filesystem::path(localAppData).parent_path(); + auto execPath = fs_lib::path(localAppData).parent_path(); #else - auto execPath = boost::filesystem::wpath(localAppData).parent_path(); + auto execPath = fs_lib::wpath(localAppData).parent_path(); #endif // if config file exists in .exe's folder use it - if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string + if(fs_lib::exists(execPath/"i2pd.conf")) // TODO: magic string { dataDir = execPath.string (); } else // otherwise %appdata% @@ -144,9 +151,9 @@ namespace fs { else { #if (BOOST_VERSION >= 108500) - dataDir = boost::filesystem::path(localAppData).string() + "\\" + appName; + dataDir = fs_lib::path(localAppData).string() + "\\" + appName; #else - dataDir = boost::filesystem::wpath(localAppData).string() + "\\" + appName; + dataDir = fs_lib::wpath(localAppData).string() + "\\" + appName; #endif } } @@ -169,7 +176,7 @@ namespace fs { #if defined(ANDROID) const char * ext = getenv("EXTERNAL_STORAGE"); if (!ext) ext = "/sdcard"; - if (boost::filesystem::exists(ext)) + if (fs_lib::exists(ext)) { dataDir = std::string (ext) + "/" + appName; return; @@ -202,16 +209,16 @@ namespace fs { } bool Init() { - if (!boost::filesystem::exists(dataDir)) - boost::filesystem::create_directory(dataDir); + if (!fs_lib::exists(dataDir)) + fs_lib::create_directory(dataDir); std::string destinations = DataDirPath("destinations"); - if (!boost::filesystem::exists(destinations)) - boost::filesystem::create_directory(destinations); + if (!fs_lib::exists(destinations)) + fs_lib::create_directory(destinations); std::string tags = DataDirPath("tags"); - if (!boost::filesystem::exists(tags)) - boost::filesystem::create_directory(tags); + if (!fs_lib::exists(tags)) + fs_lib::create_directory(tags); else i2p::garlic::CleanUpTagsFiles (); @@ -219,13 +226,13 @@ namespace fs { } bool ReadDir(const std::string & path, std::vector & files) { - if (!boost::filesystem::exists(path)) + if (!fs_lib::exists(path)) return false; - boost::filesystem::directory_iterator it(path); - boost::filesystem::directory_iterator end; + fs_lib::directory_iterator it(path); + fs_lib::directory_iterator end; for ( ; it != end; it++) { - if (!boost::filesystem::is_regular_file(it->status())) + if (!fs_lib::is_regular_file(it->status())) continue; files.push_back(it->path().string()); } @@ -234,29 +241,38 @@ namespace fs { } bool Exists(const std::string & path) { - return boost::filesystem::exists(path); + return fs_lib::exists(path); } uint32_t GetLastUpdateTime (const std::string & path) { - if (!boost::filesystem::exists(path)) + if (!fs_lib::exists(path)) return 0; +#if STD_FILESYSTEM + std::error_code ec; + auto t = std::filesystem::last_write_time (path, ec); + if (ec) return 0; + auto sctp = std::chrono::time_point_cast( + t - decltype(t)::clock::now() + std::chrono::system_clock::now()); + return std::chrono::system_clock::to_time_t(sctp); +#else boost::system::error_code ec; auto t = boost::filesystem::last_write_time (path, ec); return ec ? 0 : t; +#endif } bool Remove(const std::string & path) { - if (!boost::filesystem::exists(path)) + if (!fs_lib::exists(path)) return false; - return boost::filesystem::remove(path); + return fs_lib::remove(path); } bool CreateDirectory (const std::string& path) { - if (boost::filesystem::exists(path) && boost::filesystem::is_directory (boost::filesystem::status (path))) + if (fs_lib::exists(path) && fs_lib::is_directory (fs_lib::status (path))) return true; - return boost::filesystem::create_directory(path); + return fs_lib::create_directory(path); } void HashedStorage::SetPlace(const std::string &path) { @@ -264,18 +280,18 @@ namespace fs { } bool HashedStorage::Init(const char * chars, size_t count) { - if (!boost::filesystem::exists(root)) { - boost::filesystem::create_directories(root); + if (!fs_lib::exists(root)) { + fs_lib::create_directories(root); } for (size_t i = 0; i < count; i++) { auto p = root + i2p::fs::dirSep + prefix1 + chars[i]; - if (boost::filesystem::exists(p)) + if (fs_lib::exists(p)) continue; #if TARGET_OS_SIMULATOR // ios simulator fs says it is case sensitive, but it is not boost::system::error_code ec; - if (boost::filesystem::create_directory(p, ec)) + if (fs_lib::create_directory(p, ec)) continue; switch (ec.value()) { case boost::system::errc::file_exists: @@ -285,7 +301,7 @@ namespace fs { throw boost::system::system_error( ec, __func__ ); } #else - if (boost::filesystem::create_directory(p)) + if (fs_lib::create_directory(p)) continue; /* ^ throws exception on failure */ #endif return false; @@ -308,9 +324,9 @@ namespace fs { void HashedStorage::Remove(const std::string & ident) { std::string path = Path(ident); - if (!boost::filesystem::exists(path)) + if (!fs_lib::exists(path)) return; - boost::filesystem::remove(path); + fs_lib::remove(path); } void HashedStorage::Traverse(std::vector & files) { @@ -321,12 +337,12 @@ namespace fs { void HashedStorage::Iterate(FilenameVisitor v) { - boost::filesystem::path p(root); - boost::filesystem::recursive_directory_iterator it(p); - boost::filesystem::recursive_directory_iterator end; + fs_lib::path p(root); + fs_lib::recursive_directory_iterator it(p); + fs_lib::recursive_directory_iterator end; for ( ; it != end; it++) { - if (!boost::filesystem::is_regular_file( it->status() )) + if (!fs_lib::is_regular_file( it->status() )) continue; const std::string & t = it->path().string(); v(t); diff --git a/libi2pd/FS.h b/libi2pd/FS.h index 7911c6a0..de5db9d3 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.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 * @@ -15,6 +15,10 @@ #include #include +#if (!defined(_WIN32) && !TARGET_OS_SIMULATOR && (__cplusplus >= 201703L)) // C++ 17 or higher +# define STD_FILESYSTEM 1 +#endif + namespace i2p { namespace fs { extern std::string dirSep; diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index 8f2117a7..928aaa05 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.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 * @@ -15,7 +15,6 @@ #include #include #include -#include #include "Base.h" #include "util.h" #include "Identity.h" @@ -27,6 +26,14 @@ #include "AddressBook.h" #include "Config.h" +#if STD_FILESYSTEM +#include +namespace fs_lib = std::filesystem; +#else +#include +namespace fs_lib = boost::filesystem; +#endif + namespace i2p { namespace client @@ -266,11 +273,11 @@ namespace client void AddressBookFilesystemStorage::ResetEtags () { LogPrint (eLogError, "Addressbook: Resetting eTags"); - for (boost::filesystem::directory_iterator it (etagsPath); it != boost::filesystem::directory_iterator (); ++it) + for (fs_lib::directory_iterator it (etagsPath); it != fs_lib::directory_iterator (); ++it) { - if (!boost::filesystem::is_regular_file (it->status ())) + if (!fs_lib::is_regular_file (it->status ())) continue; - boost::filesystem::remove (it->path ()); + fs_lib::remove (it->path ()); } } From a93043f0641181341f013aa49d15db73523934b0 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 27 Aug 2024 22:12:13 -0400 Subject: [PATCH 038/527] check for __cpp_lib_filesystem --- libi2pd/FS.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/FS.h b/libi2pd/FS.h index de5db9d3..7ba692dd 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -15,7 +15,8 @@ #include #include -#if (!defined(_WIN32) && !TARGET_OS_SIMULATOR && (__cplusplus >= 201703L)) // C++ 17 or higher +#if (!defined(_WIN32) && !TARGET_OS_SIMULATOR && \ + (__cplusplus >= 201703L) && defined(__cpp_lib_filesystem)) // C++ 17 or higher supporting filesystem # define STD_FILESYSTEM 1 #endif From 4a4b76141a8f132bab4f74da6c3774e0831d647f Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 28 Aug 2024 11:34:07 -0400 Subject: [PATCH 039/527] C++20 support --- Makefile.linux | 6 ++++-- build/CMakeLists.txt | 9 ++++++--- libi2pd/FS.cpp | 6 +++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Makefile.linux b/Makefile.linux index 86527b9a..ddb3692b 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -23,10 +23,12 @@ else ifeq ($(shell expr match ${CXXVER} "[5-6]"),1) # gcc 5 - 6 else ifeq ($(shell expr match ${CXXVER} "[7-9]"),1) # gcc 7 - 9 NEEDED_CXXFLAGS += -std=c++17 LDLIBS = -latomic -else ifeq ($(shell expr match ${CXXVER} "1[0-9]"),2) # gcc 10+ -# NEEDED_CXXFLAGS += -std=c++20 +else ifeq ($(shell expr match ${CXXVER} "10"),2) # gcc 10 NEEDED_CXXFLAGS += -std=c++17 LDLIBS = -latomic +else ifeq ($(shell expr match ${CXXVER} "1[1-9]"),2) # gcc 11+ + NEEDED_CXXFLAGS += -std=c++20 + LDLIBS = -latomic else # not supported $(error Compiler too old) endif diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index be75ca3c..daf43e6d 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -157,18 +157,21 @@ else() set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -ffunction-sections -fdata-sections") set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections") # -flto is added from above - # check for c++17 & c++11 support + # check for с++20 & c++17 & c++11 support include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG("-std=c++20" CXX20_SUPPORTED) CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED) CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED) - if(CXX17_SUPPORTED) + if(CXX20_SUPPORTED) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20") + elseif(CXX17_SUPPORTED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") elseif(CXX11_SUPPORTED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") else() - message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?") + message(SEND_ERROR "C++20 nor C++17 nor C++11 standard not seems to be supported by compiler. Too old version?") endif() endif() diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index 9bb7aee2..eb17af55 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -252,8 +252,12 @@ namespace fs { std::error_code ec; auto t = std::filesystem::last_write_time (path, ec); if (ec) return 0; - auto sctp = std::chrono::time_point_cast( +#if __cplusplus >= 202002L // C++ 20 or higher + const auto sctp = std::chrono::clock_cast(t); +#else + const auto sctp = std::chrono::time_point_cast( t - decltype(t)::clock::now() + std::chrono::system_clock::now()); +#endif return std::chrono::system_clock::to_time_t(sctp); #else boost::system::error_code ec; From d85cb6e30a7f10f38a52fb27fc986980121de22a Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 28 Aug 2024 12:01:19 -0400 Subject: [PATCH 040/527] fixed build for Debian Bookworm --- Makefile.linux | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.linux b/Makefile.linux index ddb3692b..6cd2a949 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -23,10 +23,10 @@ else ifeq ($(shell expr match ${CXXVER} "[5-6]"),1) # gcc 5 - 6 else ifeq ($(shell expr match ${CXXVER} "[7-9]"),1) # gcc 7 - 9 NEEDED_CXXFLAGS += -std=c++17 LDLIBS = -latomic -else ifeq ($(shell expr match ${CXXVER} "10"),2) # gcc 10 +else ifeq ($(shell expr match ${CXXVER} "1[0-2]"),2) # gcc 10-12 NEEDED_CXXFLAGS += -std=c++17 LDLIBS = -latomic -else ifeq ($(shell expr match ${CXXVER} "1[1-9]"),2) # gcc 11+ +else ifeq ($(shell expr match ${CXXVER} "1[3-9]"),2) # gcc 13+ NEEDED_CXXFLAGS += -std=c++20 LDLIBS = -latomic else # not supported From ac876a0cd5da5a598197c059eacc1b3a4f69fce4 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 28 Aug 2024 13:43:01 -0400 Subject: [PATCH 041/527] use boost::filesystem for Mac OS X --- libi2pd/FS.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/FS.h b/libi2pd/FS.h index 7ba692dd..01fa101f 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -15,7 +15,7 @@ #include #include -#if (!defined(_WIN32) && !TARGET_OS_SIMULATOR && \ +#if (!defined(_WIN32) && !defined(MAC_OSX) && !TARGET_OS_SIMULATOR && \ (__cplusplus >= 201703L) && defined(__cpp_lib_filesystem)) // C++ 17 or higher supporting filesystem # define STD_FILESYSTEM 1 #endif From b3aa5ad998c0f932f264f6c6e01145641a6d0d33 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 28 Aug 2024 15:12:29 -0400 Subject: [PATCH 042/527] don't link with boost::filesystem in newer versions --- Makefile.bsd | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile.bsd b/Makefile.bsd index f9a47375..59374f9d 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -1,5 +1,10 @@ CXX = clang++ CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation +DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1 +INCFLAGS = -I/usr/include/ -I/usr/local/include/ +LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib +LDLIBS = -lcrypto -lssl -lz -lpthread -lboost_system -lboost_program_options + ## NOTE: NEEDED_CXXFLAGS is here so that custom CXXFLAGS can be specified at build time ## **without** overwriting the CXXFLAGS which we need in order to build. ## For example, when adding 'hardening flags' to the build @@ -9,10 +14,7 @@ CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misl CXXVER := $(shell $(CXX) -dumpversion) ifeq (${CXXVER}, "4.2.1") # older clang always returned 4.2.1 NEEDED_CXXFLAGS = -std=c++11 + LDLIBS += -lboost_filesystem else # newer versions support C++17 NEEDED_CXXFLAGS = -std=c++17 endif -DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1 -INCFLAGS = -I/usr/include/ -I/usr/local/include/ -LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib -LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_filesystem -lboost_program_options -lpthread From e957d7bbfb4a3e73a332309be4051987dd265935 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 28 Aug 2024 17:52:08 -0400 Subject: [PATCH 043/527] use std::filesystem for windows --- libi2pd/FS.cpp | 8 ++++---- libi2pd/FS.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index eb17af55..61bdefe0 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -61,7 +61,7 @@ namespace fs { const std::string GetUTF8DataDir () { #ifdef _WIN32 -#if (BOOST_VERSION >= 108500) +#if ((BOOST_VERSION >= 108500) || STD_FILESYSTEM) fs_lib::path path (dataDir); #else fs_lib::wpath path (dataDir); @@ -98,7 +98,7 @@ namespace fs { } else { -#if (BOOST_VERSION >= 108500) +#if ((BOOST_VERSION >= 108500) || STD_FILESYSTEM) dataDir = fs_lib::path(commonAppData).string() + "\\" + appName; #else dataDir = fs_lib::wpath(commonAppData).string() + "\\" + appName; @@ -127,7 +127,7 @@ namespace fs { } else { -#if (BOOST_VERSION >= 108500) +#if ((BOOST_VERSION >= 108500) || STD_FILESYSTEM) auto execPath = fs_lib::path(localAppData).parent_path(); #else auto execPath = fs_lib::wpath(localAppData).parent_path(); @@ -150,7 +150,7 @@ namespace fs { } else { -#if (BOOST_VERSION >= 108500) +#if ((BOOST_VERSION >= 108500) || STD_FILESYSTEM) dataDir = fs_lib::path(localAppData).string() + "\\" + appName; #else dataDir = fs_lib::wpath(localAppData).string() + "\\" + appName; diff --git a/libi2pd/FS.h b/libi2pd/FS.h index 01fa101f..a4682199 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -15,7 +15,7 @@ #include #include -#if (!defined(_WIN32) && !defined(MAC_OSX) && !TARGET_OS_SIMULATOR && \ +#if (!defined(MAC_OSX) && !TARGET_OS_SIMULATOR && \ (__cplusplus >= 201703L) && defined(__cpp_lib_filesystem)) // C++ 17 or higher supporting filesystem # define STD_FILESYSTEM 1 #endif From bc48e6881dc5b20c96aada6fa89701af5bb9dd1f Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 28 Aug 2024 18:25:42 -0400 Subject: [PATCH 044/527] use boost::filesystem for Win32 and clang --- libi2pd/FS.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/FS.h b/libi2pd/FS.h index a4682199..2c44285b 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -15,7 +15,7 @@ #include #include -#if (!defined(MAC_OSX) && !TARGET_OS_SIMULATOR && \ +#if (!(defined(_WIN32) && defined(__clang__)) && !defined(MAC_OSX) && !TARGET_OS_SIMULATOR && \ (__cplusplus >= 201703L) && defined(__cpp_lib_filesystem)) // C++ 17 or higher supporting filesystem # define STD_FILESYSTEM 1 #endif From e87ace0c3d013a5fff9473741983af545ad7672e Mon Sep 17 00:00:00 2001 From: Vort Date: Thu, 29 Aug 2024 16:52:25 +0300 Subject: [PATCH 045/527] implement UTF-8 conversion with WinAPI for Windows platform --- Win32/Win32App.cpp | 2 +- libi2pd/FS.cpp | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index 742ad30d..0c701c59 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -313,7 +313,7 @@ namespace win32 } case ID_DATADIR: { - std::string datadir(i2p::fs::GetUTF8DataDir()); + std::string datadir(i2p::fs::GetDataDir()); ShellExecute(NULL, "explore", datadir.c_str(), NULL, NULL, SW_SHOWNORMAL); return 0; } diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index 61bdefe0..a370bc2f 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -61,15 +61,17 @@ namespace fs { const std::string GetUTF8DataDir () { #ifdef _WIN32 -#if ((BOOST_VERSION >= 108500) || STD_FILESYSTEM) - fs_lib::path path (dataDir); -#else - fs_lib::wpath path (dataDir); -#endif - auto loc = fs_lib::path::imbue(std::locale( std::locale(), new std::codecvt_utf8_utf16() ) ); // convert path to UTF-8 - auto dataDirUTF8 = path.string(); - fs_lib::path::imbue(loc); // Return locale settings back - return dataDirUTF8; + int size = MultiByteToWideChar(CP_ACP, 0, + dataDir.c_str(), dataDir.size(), nullptr, 0); + std::wstring utf16Str(size, L'\0'); + MultiByteToWideChar(CP_ACP, 0, + dataDir.c_str(), dataDir.size(), &utf16Str[0], size); + int utf8Size = WideCharToMultiByte(CP_UTF8, 0, + utf16Str.c_str(), utf16Str.size(), nullptr, 0, nullptr, nullptr); + std::string utf8Str(utf8Size, '\0'); + WideCharToMultiByte(CP_UTF8, 0, + utf16Str.c_str(), utf16Str.size(), &utf8Str[0], utf8Size, nullptr, nullptr); + return utf8Str; #else return dataDir; // linux, osx, android uses UTF-8 by default #endif From 937809bc0f69689a51223803410951ca6767a437 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 29 Aug 2024 15:14:17 -0400 Subject: [PATCH 046/527] don't use clock_cast with clang --- libi2pd/FS.cpp | 2 +- libi2pd/FS.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index a370bc2f..f700f8db 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -254,7 +254,7 @@ namespace fs { std::error_code ec; auto t = std::filesystem::last_write_time (path, ec); if (ec) return 0; -#if __cplusplus >= 202002L // C++ 20 or higher +#if !defined(__clang__) && __cplusplus >= 202002L // C++ 20 or higher const auto sctp = std::chrono::clock_cast(t); #else const auto sctp = std::chrono::time_point_cast( diff --git a/libi2pd/FS.h b/libi2pd/FS.h index 2c44285b..a4682199 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -15,7 +15,7 @@ #include #include -#if (!(defined(_WIN32) && defined(__clang__)) && !defined(MAC_OSX) && !TARGET_OS_SIMULATOR && \ +#if (!defined(MAC_OSX) && !TARGET_OS_SIMULATOR && \ (__cplusplus >= 201703L) && defined(__cpp_lib_filesystem)) // C++ 17 or higher supporting filesystem # define STD_FILESYSTEM 1 #endif From 604bdf314f0b074c0f5ed49d887138cb9dcb79ee Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 29 Aug 2024 18:57:14 -0400 Subject: [PATCH 047/527] improved window size reculculation algorithm --- libi2pd/Streaming.cpp | 198 +++++++++++++++++++++++------------------- libi2pd/Streaming.h | 11 ++- 2 files changed, 115 insertions(+), 94 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index d6f0441c..2866f945 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -68,18 +68,19 @@ namespace stream Stream::Stream (boost::asio::io_service& service, StreamingDestination& local, std::shared_ptr remote, int port): m_Service (service), - m_SendStreamID (0), m_SequenceNumber (0), + m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), - m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (true), + m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsTimeOutResend (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), - m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), + m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), + m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), - m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), m_LastSendTime (0), + m_Jitter (0), m_MinPacingTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { @@ -95,18 +96,18 @@ namespace stream } Stream::Stream (boost::asio::io_service& service, StreamingDestination& local): - m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), + m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), - m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (true), + m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsTimeOutResend (false), m_LocalDestination (local), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), - m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowIncCounter (0), + m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), - m_PrevRTTSample (INITIAL_RTT), m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), m_LastSendTime (0), + m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { @@ -339,8 +340,15 @@ namespace stream } if (delayRequested >= DELAY_CHOKING) { - m_WindowSize = 1; - m_WindowIncCounter = 0; + if (!m_IsWinDropped) + { + m_WindowDropTargetSize = MIN_WINDOW_SIZE; + m_LastWindowDropSize = 0; + m_WindowIncCounter = 0; + m_IsWinDropped = true; // don't drop window twice + m_DropWindowDelaySequenceNumber = m_SequenceNumber; + UpdatePacingTime (); + } } } optionData += 2; @@ -451,6 +459,7 @@ namespace stream void Stream::ProcessAck (Packet * packet) { + srand (time(NULL)); bool acknowledged = false; auto ts = i2p::util::GetMillisecondsSinceEpoch (); uint32_t ackThrough = packet->GetAckThrough (); @@ -464,6 +473,7 @@ namespace stream m_IsNAcked = false; m_IsResendNeeded = false; int nackCount = packet->GetNACKCount (); + int ackCount = 0; for (auto it = m_SentPackets.begin (); it != m_SentPackets.end ();) { auto seqn = (*it)->GetSeqn (); @@ -502,59 +512,42 @@ namespace stream m_SentPackets.erase (it++); m_LocalDestination.DeletePacket (sentPacket); acknowledged = true; + ackCount++; if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK) - m_WindowIncCounter++; + if (m_RTT < rand () % INITIAL_RTT) // dirty + m_WindowIncCounter++; } else break; } if (rttSample != INT_MAX) { - if (m_IsFirstRttSample) + if (m_IsFirstRttSample && !m_IsFirstACK) { m_RTT = rttSample; m_SlowRTT = rttSample; m_PrevRTTSample = rttSample; - if (m_RoutingSession) - m_RoutingSession->SetSharedRoutingPath ( - std::make_shared ( - i2p::garlic::GarlicRoutingPath{m_CurrentOutboundTunnel, m_CurrentRemoteLease, (int)m_RTT, 0})); m_IsFirstRttSample = false; } else - m_RTT = RTT_EWMA_ALPHA * m_RTT + (1.0 - RTT_EWMA_ALPHA) * rttSample; + m_RTT = RTT_EWMA_ALPHA * rttSample + (1.0 - RTT_EWMA_ALPHA) * m_RTT; // calculate jitter - int jitter = 0; + double jitter = 0; if (rttSample > m_PrevRTTSample) jitter = rttSample - m_PrevRTTSample; else if (rttSample < m_PrevRTTSample) jitter = m_PrevRTTSample - rttSample; else jitter = std::round (rttSample / 10); // 10% - jitter += 5; // for low-latency connections - m_Jitter = std::round (RTT_EWMA_ALPHA * jitter + (1.0 - RTT_EWMA_ALPHA) * m_Jitter); - m_PrevRTTSample = rttSample; + jitter += 1; // for low-latency connections + m_Jitter = (0.025 * jitter) + (1.0 - 0.025) * m_Jitter; // // delay-based CC - if ((m_PrevRTT > m_SlowRTT + m_Jitter) && (m_RTT > m_SlowRTT + m_Jitter) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection - { - if (m_LastWindowDropSize) - m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2; - else - m_LastWindowDropSize = m_WindowSize; - m_WindowSize = m_WindowSize / 2; // /2 - if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; - m_WindowIncCounter = 0; - m_DropWindowDelayTime = ts + m_SlowRTT; - m_IsFirstACK = true; - m_IsWinDropped = true; // don't drop window twice - } + if ((m_RTT > m_SlowRTT + m_Jitter && rttSample > m_RTT && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection + ProcessWindowDrop (); UpdatePacingTime (); - if (rttSample < m_RTT) // need for delay-based CC - m_SlowRTT = RTT_EWMA_ALPHA * rttSample + (1.0 - RTT_EWMA_ALPHA) * m_SlowRTT; - else - m_SlowRTT = RTT_EWMA_ALPHA * m_RTT + (1.0 - RTT_EWMA_ALPHA) * m_SlowRTT; - m_PrevRTT = m_RTT; + m_SlowRTT = SLOWRTT_EWMA_ALPHA * rttSample + (1.0 - SLOWRTT_EWMA_ALPHA) * m_SlowRTT; + m_PrevRTTSample = rttSample; bool wasInitial = m_RTO == INITIAL_RTO; m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter)); // TODO: implement it better @@ -562,8 +555,21 @@ namespace stream if (wasInitial) ScheduleResend (); } - if ( ts > m_DropWindowDelayTime) + if (ackThrough > m_DropWindowDelaySequenceNumber && m_WindowSize <= m_WindowDropTargetSize) m_IsWinDropped = false; + if (acknowledged && m_IsWinDropped && m_WindowSize > m_WindowDropTargetSize) + { + if (ackCount > 1) + m_WindowSize = m_SentPackets.size () + 1; + else + { + m_WindowSize = m_SentPackets.size (); + m_IsResendNeeded = true; + } + if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; + m_WindowIncCounter = 0; + UpdatePacingTime (); + } if (acknowledged || m_IsNAcked) { ScheduleResend (); @@ -578,10 +584,18 @@ namespace stream m_ResendTimer.cancel (); m_SendTimer.cancel (); } + if (acknowledged && m_IsFirstACK) + { + if (m_RoutingSession) + m_RoutingSession->SetSharedRoutingPath ( + std::make_shared ( + i2p::garlic::GarlicRoutingPath{m_CurrentOutboundTunnel, m_CurrentRemoteLease, (int)m_RTT, 0})); + m_IsFirstACK = false; + } if (acknowledged) { m_NumResendAttempts = 0; - m_IsFirstACK = false; + m_IsTimeOutResend = false; SendBuffer (); } if (m_Status == eStreamStatusClosed) @@ -1135,45 +1149,37 @@ namespace stream { if (ecode != boost::asio::error::operation_aborted) { - if (m_WindowIncCounter && m_WindowSize < MAX_WINDOW_SIZE) - { - if (m_LastWindowDropSize && (m_LastWindowDropSize > m_WindowSize)) - { - m_WindowSize += 2.001-(2/((m_LastWindowDropSize+(1/m_WindowSize))/m_WindowSize)); // some magic here - m_WindowIncCounter --; - } - else - { - m_WindowSize += 1; - m_WindowIncCounter --; - } - if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; - UpdatePacingTime (); - } auto ts = i2p::util::GetMillisecondsSinceEpoch (); if (m_LastSendTime && ts*1000 > m_LastSendTime*1000 + m_PacingTime) { m_NumPacketsToSend = ((ts*1000 - m_LastSendTime*1000) + m_PacingTimeRem) / m_PacingTime; m_PacingTimeRem = ((ts*1000 - m_LastSendTime*1000) + m_PacingTimeRem) - (m_NumPacketsToSend * m_PacingTime); m_IsSendTime = true; - if (m_IsNAcked || m_IsResendNeeded) // resend packets + if (m_WindowIncCounter && m_WindowSize < MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty ()) + { + for (int i = 0; i < m_NumPacketsToSend; i++) + { + if (m_WindowIncCounter) + { + if (m_LastWindowDropSize && (m_LastWindowDropSize >= m_WindowSize)) + m_WindowSize += 1 - (1 / ((m_LastWindowDropSize + PREV_SPEED_KEEP_TIME_COEFF) / m_WindowSize)); // some magic here + else if (m_LastWindowDropSize && (m_LastWindowDropSize < m_WindowSize)) + m_WindowSize += (m_WindowSize - (m_LastWindowDropSize - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize; // some magic here + else + m_WindowSize += (m_WindowSize - (1 - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize; + if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; + m_WindowIncCounter --; + UpdatePacingTime (); + } + } + } + if (m_IsNAcked) + ResendPacket (); + else if (m_IsResendNeeded) // resend packets ResendPacket (); // delay-based CC else if (!m_IsWinDropped && int(m_SentPackets.size ()) == m_WindowSize) // we sending packets too fast, early detection - { - auto ts = i2p::util::GetMillisecondsSinceEpoch (); - if (m_LastWindowDropSize) - m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2; - else - m_LastWindowDropSize = m_WindowSize; - m_WindowSize = m_WindowSize / 2; // /2 - if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; - m_WindowIncCounter = 0; - m_DropWindowDelayTime = ts + m_SlowRTT; - m_IsFirstACK = true; - m_IsWinDropped = true; // don't drop window twice - UpdatePacingTime (); - } + ProcessWindowDrop (); else if (m_WindowSize > int(m_SentPackets.size ())) // send packets SendBuffer (); } @@ -1266,30 +1272,18 @@ namespace stream { // loss-based CC if (!m_IsWinDropped) - { - if (m_LastWindowDropSize) - m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2; - else - m_LastWindowDropSize = m_WindowSize; - m_WindowSize = m_WindowSize / 2; // /2 - if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; - m_WindowIncCounter = 0; - m_IsWinDropped = true; // don't drop window twice - m_DropWindowDelayTime = ts + m_SlowRTT; - m_IsFirstACK = true; - UpdatePacingTime (); - } + ProcessWindowDrop (); } else if (m_IsTimeOutResend) { m_IsTimeOutResend = false; m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change - m_WindowSize = INITIAL_WINDOW_SIZE; + m_WindowDropTargetSize = INITIAL_WINDOW_SIZE; m_LastWindowDropSize = 0; m_WindowIncCounter = 0; m_IsWinDropped = true; m_IsFirstRttSample = true; - m_DropWindowDelayTime = 0; + m_DropWindowDelaySequenceNumber = 0; m_IsFirstACK = true; UpdatePacingTime (); if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); @@ -1438,12 +1432,16 @@ namespace stream } // drop window to initial upon RemoteLease change m_RTO = INITIAL_RTO; - m_WindowSize = INITIAL_WINDOW_SIZE; + if (m_WindowSize > INITIAL_WINDOW_SIZE) + { + m_WindowDropTargetSize = INITIAL_WINDOW_SIZE; + m_IsWinDropped = true; + } + else + m_WindowSize = INITIAL_WINDOW_SIZE; m_LastWindowDropSize = 0; m_WindowIncCounter = 0; - m_IsWinDropped = true; m_IsFirstRttSample = true; - m_DropWindowDelayTime = 0; m_IsFirstACK = true; UpdatePacingTime (); } @@ -1464,6 +1462,24 @@ namespace stream if (m_MinPacingTime && m_PacingTime < m_MinPacingTime) m_PacingTime = m_MinPacingTime; } + + void Stream::ProcessWindowDrop () + { + if (m_WindowSize > m_LastWindowDropSize) + m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2; + else + m_LastWindowDropSize = m_WindowSize; + m_WindowDropTargetSize = m_LastWindowDropSize - (m_LastWindowDropSize / 4); // -25%; + if (m_WindowDropTargetSize < MIN_WINDOW_SIZE + 1) + m_WindowDropTargetSize = MIN_WINDOW_SIZE + 1; + m_WindowSize = m_SentPackets.size (); // stop sending now + if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; + m_WindowIncCounter = 0; // disable window growth + m_DropWindowDelaySequenceNumber = m_SequenceNumber; + m_IsFirstACK = true; // ignore first RTT sample + m_IsWinDropped = true; // don't drop window twice + UpdatePacingTime (); + } StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort, bool gzip): m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index a0229483..204d4ef9 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -56,7 +56,9 @@ namespace stream const int INITIAL_WINDOW_SIZE = 10; const int MIN_WINDOW_SIZE = 1; const int MAX_WINDOW_SIZE = 1024; - const double RTT_EWMA_ALPHA = 0.125; + const double RTT_EWMA_ALPHA = 0.25; + const double SLOWRTT_EWMA_ALPHA = 0.125; + const double PREV_SPEED_KEEP_TIME_COEFF = 0.1; // 0.1 - 1 // how long will the window size stay around the previous drop level, less is longer const int MIN_RTO = 20; // in milliseconds const int INITIAL_RTT = 8000; // in milliseconds const int INITIAL_RTO = 9000; // in milliseconds @@ -241,11 +243,13 @@ namespace stream void HandleAckSendTimer (const boost::system::error_code& ecode); void UpdatePacingTime (); + void ProcessWindowDrop (); private: boost::asio::io_service& m_Service; uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber; + uint32_t m_DropWindowDelaySequenceNumber; uint32_t m_TunnelsChangeSequenceNumber; int32_t m_LastReceivedSequenceNumber; int32_t m_PreviousReceivedSequenceNumber; @@ -276,8 +280,9 @@ namespace stream SendBufferQueue m_SendBuffer; double m_RTT, m_SlowRTT; - float m_WindowSize, m_LastWindowDropSize; - int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample, m_PrevRTT, m_Jitter; + float m_WindowSize, m_LastWindowDropSize, m_WindowDropTargetSize; + int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; + double m_Jitter; uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, m_DropWindowDelayTime, m_LastSendTime; // microseconds uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed int m_NumResendAttempts, m_NumPacketsToSend; From 3679c6aea03ca00a70734497a46dc4db90dfc392 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 30 Aug 2024 11:03:06 -0400 Subject: [PATCH 048/527] switch to C++17 --- Makefile.haiku | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.haiku b/Makefile.haiku index b5ecb1e8..d0824d73 100644 --- a/Makefile.haiku +++ b/Makefile.haiku @@ -1,8 +1,8 @@ CXX = g++ -CXXFLAGS := -Wall -std=c++11 +CXXFLAGS := -Wall -std=c++17 INCFLAGS = -I/system/develop/headers DEFINES = -D_DEFAULT_SOURCE -D_GNU_SOURCE -LDLIBS = -lbe -lbsd -lnetwork -lz -lcrypto -lssl -lboost_system -lboost_filesystem -lboost_program_options -lpthread +LDLIBS = -lbe -lbsd -lnetwork -lz -lcrypto -lssl -lboost_system -lboost_program_options -lpthread ifeq ($(USE_UPNP),yes) DEFINES += -DUSE_UPNP From 2679e8cfd8586e180c78866a2fb2d91683e9af85 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 30 Aug 2024 13:28:01 -0400 Subject: [PATCH 049/527] removed dependency from boost::filesystem --- Makefile.mingw | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile.mingw b/Makefile.mingw index 4a9d033b..8db38e8f 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -18,7 +18,6 @@ endif LDLIBS += \ $(MINGW_PREFIX)/lib/libboost_system-mt.a \ - $(MINGW_PREFIX)/lib/libboost_filesystem-mt.a \ $(MINGW_PREFIX)/lib/libboost_program_options-mt.a \ $(MINGW_PREFIX)/lib/libssl.a \ $(MINGW_PREFIX)/lib/libcrypto.a \ From 8189ff0f48f83b7d5b87e5b184110764632f177d Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 30 Aug 2024 14:36:56 -0400 Subject: [PATCH 050/527] innclude before _cpp_lib_filesystem check --- libi2pd/FS.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libi2pd/FS.h b/libi2pd/FS.h index a4682199..aa819551 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -15,10 +15,14 @@ #include #include -#if (!defined(MAC_OSX) && !TARGET_OS_SIMULATOR && \ - (__cplusplus >= 201703L) && defined(__cpp_lib_filesystem)) // C++ 17 or higher supporting filesystem +#ifndef STD_FILESYSTEM +#include +#if __cplusplus >= 201703L // C++ 17 or higher +#if (!defined(MAC_OSX) && !TARGET_OS_SIMULATOR && defined(__cpp_lib_filesystem)) // supports std::filesystem # define STD_FILESYSTEM 1 #endif +#endif +#endif namespace i2p { namespace fs { From ea3f356856a8ce5190a2ae581a4ee67f6528bbd3 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 30 Aug 2024 14:40:44 -0400 Subject: [PATCH 051/527] removed dependency from boost::filesystem --- libi2pd/FS.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/FS.h b/libi2pd/FS.h index aa819551..987e0aa9 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -16,8 +16,8 @@ #include #ifndef STD_FILESYSTEM -#include #if __cplusplus >= 201703L // C++ 17 or higher +#include #if (!defined(MAC_OSX) && !TARGET_OS_SIMULATOR && defined(__cpp_lib_filesystem)) // supports std::filesystem # define STD_FILESYSTEM 1 #endif From 5cc15fac31a7a79c50ce1cd99a31323119f9723d Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 30 Aug 2024 15:03:50 -0400 Subject: [PATCH 052/527] rollback --- Makefile.mingw | 1 + libi2pd/FS.h | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile.mingw b/Makefile.mingw index 8db38e8f..4a9d033b 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -18,6 +18,7 @@ endif LDLIBS += \ $(MINGW_PREFIX)/lib/libboost_system-mt.a \ + $(MINGW_PREFIX)/lib/libboost_filesystem-mt.a \ $(MINGW_PREFIX)/lib/libboost_program_options-mt.a \ $(MINGW_PREFIX)/lib/libssl.a \ $(MINGW_PREFIX)/lib/libcrypto.a \ diff --git a/libi2pd/FS.h b/libi2pd/FS.h index 987e0aa9..45155451 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -16,12 +16,13 @@ #include #ifndef STD_FILESYSTEM -#if __cplusplus >= 201703L // C++ 17 or higher -#include -#if (!defined(MAC_OSX) && !TARGET_OS_SIMULATOR && defined(__cpp_lib_filesystem)) // supports std::filesystem +#if (!defined(MAC_OSX) && !TARGET_OS_SIMULATOR && \ + (__cplusplus >= 201703L) && defined(__cpp_lib_filesystem)) // C++ 17 or higher supporting std::filesystem # define STD_FILESYSTEM 1 +#else +# define STD_FILESYSTEM 0 #endif -#endif + #endif namespace i2p { From 2f5f39aaf2676aa20b1fc7048eaebd4ee633d3cf Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 30 Aug 2024 17:51:03 -0400 Subject: [PATCH 053/527] disable clock_cast iuntil implemented --- libi2pd/FS.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index f700f8db..21993958 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -254,12 +254,12 @@ namespace fs { std::error_code ec; auto t = std::filesystem::last_write_time (path, ec); if (ec) return 0; -#if !defined(__clang__) && __cplusplus >= 202002L // C++ 20 or higher +/*#if __cplusplus >= 202002L // C++ 20 or higher const auto sctp = std::chrono::clock_cast(t); -#else +#else */ // TODO: wait until implemented const auto sctp = std::chrono::time_point_cast( t - decltype(t)::clock::now() + std::chrono::system_clock::now()); -#endif +/*#endif */ return std::chrono::system_clock::to_time_t(sctp); #else boost::system::error_code ec; From 83c0764ed43df29f14fb07fda45a03654ff9ce8a Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 30 Aug 2024 17:54:56 -0400 Subject: [PATCH 054/527] link with stdc++fs for g++8 and g++9 --- Makefile.linux | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.linux b/Makefile.linux index 6cd2a949..5ac73b8b 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -17,13 +17,13 @@ else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10 NEEDED_CXXFLAGS += -std=c++11 else ifeq ($(shell expr match ${CXXVER} "4\.[8-9]"),3) # gcc 4.8 - 4.9 NEEDED_CXXFLAGS += -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -else ifeq ($(shell expr match ${CXXVER} "[5-6]"),1) # gcc 5 - 6 +else ifeq ($(shell expr match ${CXXVER} "[5-7]"),1) # gcc 5 - 7 NEEDED_CXXFLAGS += -std=c++11 LDLIBS = -latomic -else ifeq ($(shell expr match ${CXXVER} "[7-9]"),1) # gcc 7 - 9 +else ifeq ($(shell expr match ${CXXVER} "[8-9]"),1) # gcc 8 - 9 NEEDED_CXXFLAGS += -std=c++17 - LDLIBS = -latomic -else ifeq ($(shell expr match ${CXXVER} "1[0-2]"),2) # gcc 10-12 + LDLIBS = -latomic -lstdc++fs +else ifeq ($(shell expr match ${CXXVER} "1[0-2]"),2) # gcc 10 - 12 NEEDED_CXXFLAGS += -std=c++17 LDLIBS = -latomic else ifeq ($(shell expr match ${CXXVER} "1[3-9]"),2) # gcc 13+ From a1f40d30488b21ec064416da6792c92e33263708 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 30 Aug 2024 17:56:34 -0400 Subject: [PATCH 055/527] use __has_include()) to detect if std::filesystem can be used --- libi2pd/FS.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libi2pd/FS.h b/libi2pd/FS.h index 45155451..006ee68d 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -16,13 +16,12 @@ #include #ifndef STD_FILESYSTEM -#if (!defined(MAC_OSX) && !TARGET_OS_SIMULATOR && \ - (__cplusplus >= 201703L) && defined(__cpp_lib_filesystem)) // C++ 17 or higher supporting std::filesystem -# define STD_FILESYSTEM 1 -#else -# define STD_FILESYSTEM 0 -#endif - +# if (!defined(MAC_OSX) && !TARGET_OS_SIMULATOR && \ + (__cplusplus >= 201703L) && __has_include()) // C++ 17 or higher and supports std::filesystem +# define STD_FILESYSTEM 1 +# else +# define STD_FILESYSTEM 0 +# endif #endif namespace i2p { From 8cf9cc1a01bd348b68e741958d2be6f66c2fc0cc Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 30 Aug 2024 18:25:16 -0400 Subject: [PATCH 056/527] removed dependency from boost::filesystem --- Makefile.mingw | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile.mingw b/Makefile.mingw index 4a9d033b..8db38e8f 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -18,7 +18,6 @@ endif LDLIBS += \ $(MINGW_PREFIX)/lib/libboost_system-mt.a \ - $(MINGW_PREFIX)/lib/libboost_filesystem-mt.a \ $(MINGW_PREFIX)/lib/libboost_program_options-mt.a \ $(MINGW_PREFIX)/lib/libssl.a \ $(MINGW_PREFIX)/lib/libcrypto.a \ From 509c039e2f42666f1c73f0f986635c51e2aba563 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 31 Aug 2024 08:02:56 -0400 Subject: [PATCH 057/527] use Rng from pool if possible --- libi2pd/Datagram.cpp | 4 ++-- libi2pd/Streaming.cpp | 15 ++++++++++++--- libi2pd/Streaming.h | 1 + 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 5db072a4..1e0c06cc 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -422,7 +422,7 @@ namespace datagram { auto pool = m_LocalDestination->GetTunnelPool (); if (pool) - idx = m_LocalDestination->GetTunnelPool ()->GetRng ()() % sz; + idx = pool->GetRng ()() % sz; } if (idx < 0) idx = rand () % sz; path->remoteLease = ls[idx]; @@ -455,7 +455,7 @@ namespace datagram { auto pool = m_LocalDestination->GetTunnelPool (); if (pool) - idx = m_LocalDestination->GetTunnelPool ()->GetRng ()() % sz; + idx = pool->GetRng ()() % sz; } if (idx < 0) idx = rand () % sz; path->remoteLease = ls[idx]; diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 2866f945..c099e538 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -459,7 +459,6 @@ namespace stream void Stream::ProcessAck (Packet * packet) { - srand (time(NULL)); bool acknowledged = false; auto ts = i2p::util::GetMillisecondsSinceEpoch (); uint32_t ackThrough = packet->GetAckThrough (); @@ -514,7 +513,7 @@ namespace stream acknowledged = true; ackCount++; if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK) - if (m_RTT < rand () % INITIAL_RTT) // dirty + if (m_RTT < m_LocalDestination.GetRandom () % INITIAL_RTT) // dirty m_WindowIncCounter++; } else @@ -1410,7 +1409,7 @@ namespace stream } if (!updated) { - uint32_t i = rand () % leases.size (); + uint32_t i = m_LocalDestination.GetRandom () % leases.size (); if (m_CurrentRemoteLease && leases[i]->tunnelID == m_CurrentRemoteLease->tunnelID) // make sure we don't select previous i = (i + 1) % leases.size (); // if so, pick next @@ -1811,5 +1810,15 @@ namespace stream return msg; } + uint32_t StreamingDestination::GetRandom () + { + if (m_Owner) + { + auto pool = m_Owner->GetTunnelPool (); + if (pool) + return pool->GetRng ()(); + } + return rand (); + } } } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 204d4ef9..c251d822 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -321,6 +321,7 @@ namespace stream Packet * NewPacket () { return m_PacketsPool.Acquire(); } void DeletePacket (Packet * p) { return m_PacketsPool.Release(p); } + uint32_t GetRandom (); private: From bbadbdbfdbd60bcf0bbeaa983bc9ef3abc68cd6f Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 1 Sep 2024 15:23:14 -0400 Subject: [PATCH 058/527] Switch to C++17 for Mac OS X --- Makefile.homebrew | 2 +- Makefile.osx | 2 +- libi2pd/FS.cpp | 2 ++ libi2pd/FS.h | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile.homebrew b/Makefile.homebrew index f19d64bb..e14ea955 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -5,7 +5,7 @@ SSLROOT = ${BREWROOT}/opt/openssl@1.1 UPNPROOT = ${BREWROOT}/opt/miniupnpc CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wno-overloaded-virtual -NEEDED_CXXFLAGS ?= -std=c++11 +NEEDED_CXXFLAGS ?= -std=c++17 INCFLAGS ?= -I${SSLROOT}/include -I${BOOSTROOT}/include LDFLAGS ?= ${LD_DEBUG} DEFINES += -DMAC_OSX diff --git a/Makefile.osx b/Makefile.osx index 963d4898..48eb1a51 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -1,5 +1,5 @@ CXX = clang++ -CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 +CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++17 INCFLAGS = -I/usr/local/include DEFINES := -DMAC_OSX LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index 21993958..fdfd577e 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -9,7 +9,9 @@ #include #if defined(MAC_OSX) +#if !STD_FILESYSTEM #include +#endif #include #endif diff --git a/libi2pd/FS.h b/libi2pd/FS.h index 006ee68d..455012ba 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -16,7 +16,7 @@ #include #ifndef STD_FILESYSTEM -# if (!defined(MAC_OSX) && !TARGET_OS_SIMULATOR && \ +# if (!TARGET_OS_SIMULATOR && \ (__cplusplus >= 201703L) && __has_include()) // C++ 17 or higher and supports std::filesystem # define STD_FILESYSTEM 1 # else From a837e5c50239665cf5ca25c080107cf48ba987c9 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 1 Sep 2024 16:39:19 -0400 Subject: [PATCH 059/527] use rng from pool for lease selection --- libi2pd_client/I2CP.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 12d2d0c9..fc6d1b40 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -226,7 +226,8 @@ namespace client leases = remote->GetNonExpiredLeases (true); // with threshold if (!leases.empty ()) { - remoteLease = leases[rand () % leases.size ()]; + auto pool = GetTunnelPool (); + remoteLease = leases[(pool ? pool->GetRng ()() : rand ()) % leases.size ()]; auto leaseRouter = i2p::data::netdb.FindRouter (remoteLease->tunnelGateway); outboundTunnel = GetTunnelPool ()->GetNextOutboundTunnel (nullptr, leaseRouter ? leaseRouter->GetCompatibleTransports (false) : (i2p::data::RouterInfo::CompatibleTransports)i2p::data::RouterInfo::eAllTransports); From 9668ea9338fe8524781d6966f576227775129769 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 2 Sep 2024 10:18:08 -0400 Subject: [PATCH 060/527] removed C++11 support --- Makefile.bsd | 3 +-- Makefile.linux | 18 ++++-------------- tests/Makefile | 4 ++-- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/Makefile.bsd b/Makefile.bsd index 59374f9d..edcc0b58 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -13,8 +13,7 @@ LDLIBS = -lcrypto -lssl -lz -lpthread -lboost_system -lboost_program_options ## custom FLAGS to work at build-time. CXXVER := $(shell $(CXX) -dumpversion) ifeq (${CXXVER}, "4.2.1") # older clang always returned 4.2.1 - NEEDED_CXXFLAGS = -std=c++11 - LDLIBS += -lboost_filesystem + $(error Compiler too old) else # newer versions support C++17 NEEDED_CXXFLAGS = -std=c++17 endif diff --git a/Makefile.linux b/Makefile.linux index 5ac73b8b..88abdcbf 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -9,26 +9,17 @@ LDFLAGS ?= ${LD_DEBUG} ## -std=c++11. If you want to remove this variable please do so in a way that allows setting ## custom FDLAGS to work at build-time. -# detect proper flag for c++11 support by compilers +# detect proper flag for c++17 support by compilers CXXVER := $(shell $(CXX) -dumpversion) ifeq ($(shell expr match $(CXX) 'clang'),5) - NEEDED_CXXFLAGS += -std=c++11 -else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10 - NEEDED_CXXFLAGS += -std=c++11 -else ifeq ($(shell expr match ${CXXVER} "4\.[8-9]"),3) # gcc 4.8 - 4.9 - NEEDED_CXXFLAGS += -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -else ifeq ($(shell expr match ${CXXVER} "[5-7]"),1) # gcc 5 - 7 - NEEDED_CXXFLAGS += -std=c++11 - LDLIBS = -latomic + NEEDED_CXXFLAGS += -std=c++17 else ifeq ($(shell expr match ${CXXVER} "[8-9]"),1) # gcc 8 - 9 NEEDED_CXXFLAGS += -std=c++17 - LDLIBS = -latomic -lstdc++fs + LDLIBS = -lstdc++fs else ifeq ($(shell expr match ${CXXVER} "1[0-2]"),2) # gcc 10 - 12 NEEDED_CXXFLAGS += -std=c++17 - LDLIBS = -latomic else ifeq ($(shell expr match ${CXXVER} "1[3-9]"),2) # gcc 13+ NEEDED_CXXFLAGS += -std=c++20 - LDLIBS = -latomic else # not supported $(error Compiler too old) endif @@ -41,7 +32,6 @@ ifeq ($(USE_STATIC),yes) # the shared libraries from the glibc version used for linking LIBDIR := /usr/lib/$(SYS) LDLIBS += $(LIBDIR)/libboost_system.a - LDLIBS += $(LIBDIR)/libboost_filesystem.a LDLIBS += $(LIBDIR)/libboost_program_options.a LDLIBS += $(LIBDIR)/libssl.a LDLIBS += $(LIBDIR)/libcrypto.a @@ -51,7 +41,7 @@ ifeq ($(USE_UPNP),yes) endif LDLIBS += -lpthread -ldl else - LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_filesystem -lboost_program_options -lpthread + LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_program_options -lpthread -latomic ifeq ($(USE_UPNP),yes) LDLIBS += -lminiupnpc endif diff --git a/tests/Makefile b/tests/Makefile index 7c44e467..798fab42 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ SYS := $(shell $(CXX) -dumpmachine) -CXXFLAGS += -Wall -Wno-unused-parameter -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -DOPENSSL_SUPPRESS_DEPRECATED -pthread -Wl,--unresolved-symbols=ignore-in-object-files +CXXFLAGS += -Wall -Wno-unused-parameter -Wextra -pedantic -O0 -g -std=c++17 -D_GLIBCXX_USE_NANOSLEEP=1 -DOPENSSL_SUPPRESS_DEPRECATED -pthread -Wl,--unresolved-symbols=ignore-in-object-files INCFLAGS += -I../libi2pd LIBI2PD = ../libi2pd.a @@ -18,7 +18,7 @@ ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstrin endif LDLIBS = \ - -lboost_filesystem$(BOOST_SUFFIX) \ + -lboost_system$(BOOST_SUFFIX) \ -lboost_program_options$(BOOST_SUFFIX) \ -lssl \ -lcrypto \ From c21cf0565b7b331712dbeb0ff4940f216c0706f1 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 2 Sep 2024 10:55:22 -0400 Subject: [PATCH 061/527] removed C++11 support --- build/CMakeLists.txt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index daf43e6d..19c51dfd 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -157,21 +157,19 @@ else() set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -ffunction-sections -fdata-sections") set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections") # -flto is added from above - # check for с++20 & c++17 & c++11 support + # check for с++20 & c++17 support include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++20" CXX20_SUPPORTED) CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED) - CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED) + if(CXX20_SUPPORTED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20") elseif(CXX17_SUPPORTED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") - elseif(CXX11_SUPPORTED) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") else() - message(SEND_ERROR "C++20 nor C++17 nor C++11 standard not seems to be supported by compiler. Too old version?") + message(SEND_ERROR "C++20 nor C++17 standard not seems to be supported by compiler. Too old version?") endif() endif() From 56b8534e0c911147a38964e97aebf218e55bdad7 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 2 Sep 2024 15:00:25 -0400 Subject: [PATCH 062/527] gcc7 support --- Makefile.linux | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.linux b/Makefile.linux index 88abdcbf..2955d301 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -13,6 +13,9 @@ LDFLAGS ?= ${LD_DEBUG} CXXVER := $(shell $(CXX) -dumpversion) ifeq ($(shell expr match $(CXX) 'clang'),5) NEEDED_CXXFLAGS += -std=c++17 +else ifeq ($(shell expr match ${CXXVER} "7"),1) # gcc 7 + NEEDED_CXXFLAGS += -std=c++17 + LDLIBS = -lboost_filesystem else ifeq ($(shell expr match ${CXXVER} "[8-9]"),1) # gcc 8 - 9 NEEDED_CXXFLAGS += -std=c++17 LDLIBS = -lstdc++fs From a3e0b3710c66b854eee33d7532cbe262e9a72ba0 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 2 Sep 2024 17:34:15 -0400 Subject: [PATCH 063/527] pass std::string_view to parse --- libi2pd/HTTP.cpp | 90 ++++++++++++++++++++++++++++++------------------ libi2pd/HTTP.h | 11 +++--- 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index f4c3dcb9..ecb1d550 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.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 * @@ -40,12 +40,13 @@ namespace http inline bool is_http_method(const std::string & str) { return std::find(HTTP_METHODS.begin(), HTTP_METHODS.end(), str) != std::end(HTTP_METHODS); } - - void strsplit(const std::string & line, std::vector &tokens, char delim, std::size_t limit = 0) { + + static void strsplit(std::stringstream& ss, std::vector &tokens, char delim, std::size_t limit = 0) + { std::size_t count = 0; - std::stringstream ss(line); std::string token; - while (1) { + while (1) + { count++; if (limit > 0 && count >= limit) delim = '\n'; /* reset delimiter */ @@ -55,7 +56,19 @@ namespace http } } - static std::pair parse_header_line(const std::string& line) + static void strsplit(const std::string & line, std::vector &tokens, char delim, std::size_t limit = 0) + { + std::stringstream ss(line); + strsplit (ss, tokens, delim, limit); + } + + static void strsplit(std::string_view line, std::vector &tokens, char delim, std::size_t limit = 0) + { + std::stringstream ss(std::move(std::string(line))); + strsplit (ss, tokens, delim, limit); + } + + static std::pair parse_header_line(std::string_view line) { std::size_t pos = 0; std::size_t len = 1; /*: */ @@ -69,7 +82,8 @@ namespace http if (len == 1) return std::make_pair("", ""); // no following space, but something else } - return std::make_pair(line.substr(0, pos), line.substr(pos + len)); + return std::make_pair(std::move (std::string (line.substr(0, pos))), + std::move (std::string (line.substr(pos + len)))); } void gen_rfc7231_date(std::string & out) { @@ -83,15 +97,17 @@ namespace http out = buf; } - bool URL::parse(const char *str, std::size_t len) { - std::string url(str, len ? len : strlen(str)); - return parse(url); + bool URL::parse(const char *str, std::size_t len) + { + return parse({str, len ? len : strlen(str)}); } - bool URL::parse(const std::string& url) { + bool URL::parse(std::string_view url) + { std::size_t pos_p = 0; /* < current parse position */ std::size_t pos_c = 0; /* < work position */ - if(url.at(0) != '/' || pos_p > 0) { + if(url.at(0) != '/' || pos_p > 0) + { std::size_t pos_s = 0; /* schema */ @@ -141,7 +157,7 @@ namespace http /* port[/path] */ pos_p = pos_c + 1; pos_c = url.find('/', pos_p); - std::string port_str = (pos_c == std::string::npos) + std::string_view port_str = (pos_c == std::string::npos) ? url.substr(pos_p, std::string::npos) : url.substr(pos_p, pos_c - pos_p); /* stoi throws exception on failure, we don't need it */ @@ -272,12 +288,13 @@ namespace http headers.erase(name); } - int HTTPReq::parse(const char *buf, size_t len) { - std::string str(buf, len); - return parse(str); + int HTTPReq::parse(const char *buf, size_t len) + { + return parse({buf, len}); } - int HTTPReq::parse(const std::string& str) { + int HTTPReq::parse(std::string_view str) + { enum { REQ_LINE, HEADER_LINE } expect = REQ_LINE; std::size_t eoh = str.find(HTTP_EOH); /* request head size */ std::size_t eol = 0, pos = 0; @@ -286,9 +303,11 @@ namespace http if (eoh == std::string::npos) return 0; /* str not contains complete request */ - while ((eol = str.find(CRLF, pos)) != std::string::npos) { - if (expect == REQ_LINE) { - std::string line = str.substr(pos, eol - pos); + while ((eol = str.find(CRLF, pos)) != std::string::npos) + { + if (expect == REQ_LINE) + { + std::string_view line = str.substr(pos, eol - pos); std::vector tokens; strsplit(line, tokens, ' '); if (tokens.size() != 3) @@ -307,7 +326,7 @@ namespace http } else { - std::string line = str.substr(pos, eol - pos); + std::string_view line = str.substr(pos, eol - pos); auto p = parse_header_line(line); if (p.first.length () > 0) headers.push_back (p); @@ -413,12 +432,13 @@ namespace http return length; } - int HTTPRes::parse(const char *buf, size_t len) { - std::string str(buf, len); - return parse(str); + int HTTPRes::parse(const char *buf, size_t len) + { + return parse({buf,len}); } - int HTTPRes::parse(const std::string& str) { + int HTTPRes::parse(std::string_view str) + { enum { RES_LINE, HEADER_LINE } expect = RES_LINE; std::size_t eoh = str.find(HTTP_EOH); /* request head size */ std::size_t eol = 0, pos = 0; @@ -426,9 +446,11 @@ namespace http if (eoh == std::string::npos) return 0; /* str not contains complete request */ - while ((eol = str.find(CRLF, pos)) != std::string::npos) { - if (expect == RES_LINE) { - std::string line = str.substr(pos, eol - pos); + while ((eol = str.find(CRLF, pos)) != std::string::npos) + { + if (expect == RES_LINE) + { + std::string_view line = str.substr(pos, eol - pos); std::vector tokens; strsplit(line, tokens, ' ', 3); if (tokens.size() != 3) @@ -442,8 +464,10 @@ namespace http version = tokens[0]; status = tokens[2]; expect = HEADER_LINE; - } else { - std::string line = str.substr(pos, eol - pos); + } + else + { + std::string_view line = str.substr(pos, eol - pos); auto p = parse_header_line(line); if (p.first.length () > 0) headers.insert (p); @@ -508,14 +532,14 @@ namespace http return ptr; } - std::string UrlDecode(const std::string& data, bool allow_null) + std::string UrlDecode(std::string_view data, bool allow_null) { std::string decoded(data); size_t pos = 0; while ((pos = decoded.find('%', pos)) != std::string::npos) { - char c = strtol(decoded.substr(pos + 1, 2).c_str(), NULL, 16); - if (c == '\0' && !allow_null) + char c = std::stol(decoded.substr(pos + 1, 2), nullptr, 16); + if (!c && !allow_null) { pos += 3; continue; diff --git a/libi2pd/HTTP.h b/libi2pd/HTTP.h index 41f0560a..d71c7505 100644 --- a/libi2pd/HTTP.h +++ b/libi2pd/HTTP.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 * @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace i2p @@ -45,7 +46,7 @@ namespace http * @return true on success, false on invalid url */ bool parse (const char *str, std::size_t len = 0); - bool parse (const std::string& url); + bool parse (std::string_view url); /** * @brief Parse query part of url to key/value map @@ -92,7 +93,7 @@ namespace http * @note Positive return value is a size of header */ int parse(const char *buf, size_t len); - int parse(const std::string& buf); + int parse(std::string_view buf); /** @brief Serialize HTTP request to string */ std::string to_string(); @@ -128,7 +129,7 @@ namespace http * @note Positive return value is a size of header */ int parse(const char *buf, size_t len); - int parse(const std::string& buf); + int parse(const std::string_view buf); /** * @brief Serialize HTTP response to string @@ -161,7 +162,7 @@ namespace http * @param null If set to true - decode also %00 sequence, otherwise - skip * @return Decoded string */ - std::string UrlDecode(const std::string& data, bool null = false); + std::string UrlDecode(std::string_view data, bool null = false); /** * @brief Merge HTTP response content with Transfer-Encoding: chunked From cc590035606f0fb07b21f660a878ae48f4ca13ce Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 2 Sep 2024 18:22:33 -0400 Subject: [PATCH 064/527] removed C++17 check --- Win32/Win32App.cpp | 4 +--- libi2pd/ECIESX25519AEADRatchetSession.cpp | 2 -- libi2pd/FS.h | 3 +-- libi2pd/Garlic.cpp | 2 -- libi2pd/Log.h | 20 -------------------- libi2pd/NetDb.cpp | 17 ++--------------- libi2pd/RouterContext.cpp | 2 -- libi2pd/SSU2Session.cpp | 4 ---- libi2pd_client/SOCKS.cpp | 2 -- 9 files changed, 4 insertions(+), 52 deletions(-) diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index 0c701c59..5234b032 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -355,9 +355,7 @@ namespace win32 } } } -#if (__cplusplus >= 201703L) // C++ 17 or higher - [[fallthrough]]; -#endif + [fallthrough]]; } case WM_TRAYICON: { diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 9f23482b..138d21e9 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -801,9 +801,7 @@ namespace garlic m_State = eSessionStateEstablished; m_NSRSendTagset = nullptr; m_EphemeralKeys = nullptr; -#if (__cplusplus >= 201703L) // C++ 17 or higher [[fallthrough]]; -#endif case eSessionStateEstablished: if (m_SendReverseKey && receiveTagset->GetTagSetID () == m_NextReceiveRatchet->GetReceiveTagSetID ()) m_SendReverseKey = false; // tag received on new tagset diff --git a/libi2pd/FS.h b/libi2pd/FS.h index 455012ba..8bf8101e 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -16,8 +16,7 @@ #include #ifndef STD_FILESYSTEM -# if (!TARGET_OS_SIMULATOR && \ - (__cplusplus >= 201703L) && __has_include()) // C++ 17 or higher and supports std::filesystem +# if (!TARGET_OS_SIMULATOR && __has_include()) // supports std::filesystem # define STD_FILESYSTEM 1 # else # define STD_FILESYSTEM 0 diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 54fc781e..fb99ce6d 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -1031,9 +1031,7 @@ namespace garlic case eGarlicDeliveryTypeDestination: LogPrint (eLogDebug, "Garlic: Type destination"); buf += 32; // TODO: check destination -#if (__cplusplus >= 201703L) // C++ 17 or higher [[fallthrough]]; -#endif // no break here case eGarlicDeliveryTypeLocal: { diff --git a/libi2pd/Log.h b/libi2pd/Log.h index 0164ea4f..18592c9e 100644 --- a/libi2pd/Log.h +++ b/libi2pd/Log.h @@ -172,16 +172,6 @@ void LogPrint (std::stringstream& s, TValue&& arg) noexcept s << std::forward(arg); } -#if (__cplusplus < 201703L) // below C++ 17 -/** internal usage only -- folding args array to single string */ -template -void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept -{ - LogPrint (s, std::forward(arg)); - LogPrint (s, std::forward(args)...); -} -#endif - /** * @brief Create log message and send it to queue * @param level Message level (eLogError, eLogInfo, ...) @@ -194,13 +184,7 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept // fold message to single string std::stringstream ss; - -#if (__cplusplus >= 201703L) // C++ 17 or higher (LogPrint (ss, std::forward(args)), ...); -#else - LogPrint (ss, std::forward(args)...); -#endif - auto msg = std::make_shared(level, std::time(nullptr), std::move(ss).str()); msg->tid = std::this_thread::get_id(); i2p::log::Logger().Append(msg); @@ -217,11 +201,7 @@ void ThrowFatal (TArgs&&... args) noexcept if (!f) return; // fold message to single string std::stringstream ss(""); -#if (__cplusplus >= 201703L) // C++ 17 or higher (LogPrint (ss, std::forward(args)), ...); -#else - LogPrint (ss, std::forward(args)...); -#endif f (ss.str ()); } diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 9bd78776..b222ac88 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1314,12 +1314,8 @@ namespace data { // update selection m_ExploratorySelection.clear (); -#if (__cplusplus >= 201703L) // C++ 17 or higher std::vector > eligible; - eligible.reserve (m_RouterInfos.size ()); -#else - auto& eligible = m_ExploratorySelection; -#endif + eligible.reserve (m_RouterInfos.size ()); { // collect eligible from current netdb bool checkIsReal = i2p::tunnel::tunnels.GetPreciseTunnelCreationSuccessRate () < NETDB_TUNNEL_CREATION_RATE_THRESHOLD; // too low rate @@ -1329,22 +1325,13 @@ namespace data (!checkIsReal || (it.second->HasProfile () && it.second->GetProfile ()->IsReal ()))) eligible.push_back (it.second); } -#if (__cplusplus >= 201703L) // C++ 17 or higher if (eligible.size () > NETDB_MAX_EXPLORATORY_SELECTION_SIZE) { std::sample (eligible.begin(), eligible.end(), std::back_inserter(m_ExploratorySelection), NETDB_MAX_EXPLORATORY_SELECTION_SIZE, std::mt19937(ts)); } else - std::swap (m_ExploratorySelection, eligible); -#else - if (m_ExploratorySelection.size () > NETDB_MAX_EXPLORATORY_SELECTION_SIZE) - { - // reduce number of eligible to max selection size - std::shuffle (m_ExploratorySelection.begin(), m_ExploratorySelection.end(), std::mt19937(ts)); - m_ExploratorySelection.resize (NETDB_MAX_EXPLORATORY_SELECTION_SIZE); - } -#endif + std::swap (m_ExploratorySelection, eligible); m_LastExploratorySelectionUpdateTime = ts; } diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 5461cdfd..89c46c45 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -626,9 +626,7 @@ namespace i2p case low : /* not set */; break; case extra : caps |= i2p::data::RouterInfo::eExtraBandwidth; break; // 'P' case unlim : caps |= i2p::data::RouterInfo::eExtraBandwidth; -#if (__cplusplus >= 201703L) // C++ 17 or higher [[fallthrough]]; -#endif // no break here, extra + high means 'X' case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break; } diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 92fe2d46..62bbf41f 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -587,11 +587,7 @@ namespace transport if (!resentPackets.empty ()) { m_LastResendTime = ts; -#if (__cplusplus >= 201703L) // C++ 17 or higher m_SentPackets.merge (resentPackets); -#else - m_SentPackets.insert (resentPackets.begin (), resentPackets.end ()); -#endif m_WindowSize >>= 1; // /2 if (m_WindowSize < SSU2_MIN_WINDOW_SIZE) m_WindowSize = SSU2_MIN_WINDOW_SIZE; return resentPackets.size (); diff --git a/libi2pd_client/SOCKS.cpp b/libi2pd_client/SOCKS.cpp index 3174bdb3..0961690b 100644 --- a/libi2pd_client/SOCKS.cpp +++ b/libi2pd_client/SOCKS.cpp @@ -444,9 +444,7 @@ namespace proxy break; case CMD_UDP: if (m_socksv == SOCKS5) break; -#if (__cplusplus >= 201703L) // C++ 17 or higher [[fallthrough]]; -#endif default: LogPrint(eLogError, "SOCKS: Invalid command: ", ((int)*sock_buff)); SocksRequestFailed(SOCKS5_GEN_FAIL); From 06e3a1b57aaa612bbfa84696a9c2daea896df32d Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 2 Sep 2024 18:32:52 -0400 Subject: [PATCH 065/527] fixed typo --- Win32/Win32App.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index 5234b032..0e29c517 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -355,7 +355,7 @@ namespace win32 } } } - [fallthrough]]; + [[fallthrough]]; } case WM_TRAYICON: { From 0046a8b3ecd0f926f1767042e01ce78c412ee2c6 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 2 Sep 2024 21:05:40 -0400 Subject: [PATCH 066/527] pass const strings for HTTP headers --- libi2pd/HTTP.cpp | 2 +- libi2pd/HTTP.h | 2 +- libi2pd_client/HTTPProxy.cpp | 23 +++++++++++++---------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index ecb1d550..6e427298 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.cpp @@ -269,7 +269,7 @@ namespace http return host.rfind(".i2p") == ( host.size() - 4 ); } - void HTTPMsg::add_header(const char *name, std::string & value, bool replace) { + void HTTPMsg::add_header(const char *name, const std::string & value, bool replace) { add_header(name, value.c_str(), replace); } diff --git a/libi2pd/HTTP.h b/libi2pd/HTTP.h index d71c7505..438ef953 100644 --- a/libi2pd/HTTP.h +++ b/libi2pd/HTTP.h @@ -70,7 +70,7 @@ namespace http { std::map headers; - void add_header(const char *name, std::string & value, bool replace = false); + void add_header(const char *name, const std::string & value, bool replace = false); void add_header(const char *name, const char *value, bool replace = false); void del_header(const char *name); diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 01678f4a..67ee2c5e 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,8 @@ namespace proxy { "\r\n" ; - bool str_rmatch(std::string & str, const char *suffix) { + static bool str_rmatch(std::string & str, const char *suffix) + { auto pos = str.rfind (suffix); if (pos == std::string::npos) return false; /* not found */ @@ -77,16 +79,16 @@ namespace proxy { void Terminate(); void AsyncSockRead(); static bool ExtractAddressHelper(i2p::http::URL& url, std::string& jump, bool& confirm); - static bool VerifyAddressHelper (const std::string& jump); + static bool VerifyAddressHelper (std::string_view jump); static void SanitizeHTTPRequest(i2p::http::HTTPReq& req); void SentHTTPFailed(const boost::system::error_code & ecode); void HandleStreamRequestComplete (std::shared_ptr stream); /* error helpers */ void GenericProxyError(const std::string& title, const std::string& description); void GenericProxyInfo(const std::string& title, const std::string& description); - void HostNotFound(std::string& host); - void SendProxyError(std::string& content); - void SendRedirect(std::string& address); + void HostNotFound(const std::string& host); + void SendProxyError(const std::string& content); + void SendRedirect(const std::string& address); void ForwardToUpstreamProxy(); void HandleUpstreamHTTPProxyConnect(const boost::system::error_code & ec); @@ -175,7 +177,8 @@ namespace proxy { SendProxyError(content); } - void HTTPReqHandler::HostNotFound(std::string& host) { + void HTTPReqHandler::HostNotFound(const std::string& host) + { std::stringstream ss; ss << "

" << tr("Proxy error: Host not found") << "

\r\n" << "

" << tr("Remote host not found in router's addressbook") << "

\r\n" @@ -192,7 +195,7 @@ namespace proxy { SendProxyError(content); } - void HTTPReqHandler::SendProxyError(std::string& content) + void HTTPReqHandler::SendProxyError(const std::string& content) { i2p::http::HTTPRes res; res.code = 500; @@ -208,7 +211,7 @@ namespace proxy { std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } - void HTTPReqHandler::SendRedirect(std::string& address) + void HTTPReqHandler::SendRedirect(const std::string& address) { i2p::http::HTTPRes res; res.code = 302; @@ -272,7 +275,7 @@ namespace proxy { return true; } - bool HTTPReqHandler::VerifyAddressHelper (const std::string& jump) + bool HTTPReqHandler::VerifyAddressHelper (std::string_view jump) { auto pos = jump.find(".b32.i2p"); if (pos != std::string::npos) @@ -441,7 +444,7 @@ namespace proxy { bool useConnect = false; if(m_ClientRequest.method == "CONNECT") { - std::string uri(m_ClientRequest.uri); + const std::string& uri = m_ClientRequest.uri; auto pos = uri.find(":"); if(pos == std::string::npos || pos == uri.size() - 1) { From ae65af07c27163d9d462d628f189458067430788 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Sep 2024 13:00:04 -0400 Subject: [PATCH 067/527] handle immediate ack request --- libi2pd/Streaming.cpp | 12 +++++++++--- libi2pd/Streaming.h | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index c099e538..1974cd10 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -326,12 +326,16 @@ namespace stream LogPrint (eLogInfo, "Streaming: Invalid option size ", optionSize, " Discarded"); return false; } + if (!flags) return true; + bool immediateAckRequested = false; if (flags & PACKET_FLAG_DELAY_REQUESTED) { - if (!m_IsAckSendScheduled) + uint16_t delayRequested = bufbe16toh (optionData); + if (!delayRequested) // 0 requests an immediate ack + immediateAckRequested = true; + else if (!m_IsAckSendScheduled) { - uint16_t delayRequested = bufbe16toh (optionData); - if (delayRequested > 0 && delayRequested < m_RTT) + if (delayRequested < m_RTT) { m_IsAckSendScheduled = true; m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(delayRequested)); @@ -432,6 +436,8 @@ namespace stream return false; } } + if (immediateAckRequested) + SendQuickAck (); return true; } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index c251d822..c0b73162 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -283,7 +283,7 @@ namespace stream float m_WindowSize, m_LastWindowDropSize, m_WindowDropTargetSize; int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; double m_Jitter; - uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, m_DropWindowDelayTime, m_LastSendTime; // microseconds + uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, m_LastSendTime; // microseconds uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed int m_NumResendAttempts, m_NumPacketsToSend; size_t m_MTU; From ead1b72886b01a418828c1774987ae5213cf80d0 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Sep 2024 15:20:33 -0400 Subject: [PATCH 068/527] set half of window on remote lease change --- libi2pd/Streaming.cpp | 2 +- libi2pd/Streaming.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 1974cd10..881818d5 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1439,7 +1439,7 @@ namespace stream m_RTO = INITIAL_RTO; if (m_WindowSize > INITIAL_WINDOW_SIZE) { - m_WindowDropTargetSize = INITIAL_WINDOW_SIZE; + m_WindowDropTargetSize = std::max (m_WindowSize/2, (float)INITIAL_WINDOW_SIZE); m_IsWinDropped = true; } else diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index c0b73162..84b92c9f 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -58,7 +58,7 @@ namespace stream const int MAX_WINDOW_SIZE = 1024; const double RTT_EWMA_ALPHA = 0.25; const double SLOWRTT_EWMA_ALPHA = 0.125; - const double PREV_SPEED_KEEP_TIME_COEFF = 0.1; // 0.1 - 1 // how long will the window size stay around the previous drop level, less is longer + const double PREV_SPEED_KEEP_TIME_COEFF = 0.35; // 0.1 - 1 // how long will the window size stay around the previous drop level, less is longer const int MIN_RTO = 20; // in milliseconds const int INITIAL_RTT = 8000; // in milliseconds const int INITIAL_RTO = 9000; // in milliseconds From 53db54dafba455a5a63999681c32fd299909145b Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Sep 2024 18:36:50 -0400 Subject: [PATCH 069/527] consider N routers as low bandwidth --- libi2pd/RouterInfo.cpp | 8 ++++---- libi2pd/RouterInfo.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index d819999e..c24d0957 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -538,10 +538,10 @@ namespace data case CAPS_FLAG_LOW_BANDWIDTH1: case CAPS_FLAG_LOW_BANDWIDTH2: case CAPS_FLAG_LOW_BANDWIDTH3: + case CAPS_FLAG_LOW_BANDWIDTH4: m_BandwidthCap = *cap; break; - case CAPS_FLAG_HIGH_BANDWIDTH1: - case CAPS_FLAG_HIGH_BANDWIDTH2: + case CAPS_FLAG_HIGH_BANDWIDTH: m_Caps |= Caps::eHighBandwidth; m_BandwidthCap = *cap; break; @@ -1224,7 +1224,7 @@ namespace data CAPS_FLAG_EXTRA_BANDWIDTH2 : // 'X' CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P' else - caps += CAPS_FLAG_HIGH_BANDWIDTH2; // 'O' + caps += CAPS_FLAG_HIGH_BANDWIDTH; // 'O' caps += CAPS_FLAG_FLOODFILL; // floodfill } else @@ -1232,7 +1232,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_BANDWIDTH2 /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth + caps += (c & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH /* '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 c2668bc4..16f072d0 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -40,8 +40,8 @@ namespace data const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; /* < 12 KBps */ const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L'; /* 12-48 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_LOW_BANDWIDTH4 = 'N'; /* 64-128 KBps */ + const char CAPS_FLAG_HIGH_BANDWIDTH = '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 d1620d70bbb6ce1afe3b38ecc2a9ea0dd0d8045a Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Sep 2024 18:43:25 -0400 Subject: [PATCH 070/527] consider N routers as low bandwidth --- libi2pd/RouterContext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 89c46c45..efbfee65 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -610,8 +610,8 @@ 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_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_LOW_BANDWIDTH4 : limit = 128; type = low; break; + case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH : 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: From 911620bcd317ba2f20510dc63f7f2cf93e856199 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Sep 2024 13:21:13 -0400 Subject: [PATCH 071/527] C++20 for clang >= 16 --- Makefile.bsd | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.bsd b/Makefile.bsd index edcc0b58..03b50483 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -14,6 +14,8 @@ LDLIBS = -lcrypto -lssl -lz -lpthread -lboost_system -lboost_program_options CXXVER := $(shell $(CXX) -dumpversion) ifeq (${CXXVER}, "4.2.1") # older clang always returned 4.2.1 $(error Compiler too old) -else # newer versions support C++17 +else ifeq ($(shell expr match ${CXXVER} "1[6-9]"),2) # clang 16 - 19 + NEEDED_CXXFLAGS += -std=c++20 +else NEEDED_CXXFLAGS = -std=c++17 endif From 2ee5af0c061b4e43dc1ad43d00023bdc5065da57 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Sep 2024 13:23:12 -0400 Subject: [PATCH 072/527] C++20 for clang >= 16 --- Makefile.bsd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.bsd b/Makefile.bsd index 03b50483..eb528799 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -15,7 +15,8 @@ CXXVER := $(shell $(CXX) -dumpversion) ifeq (${CXXVER}, "4.2.1") # older clang always returned 4.2.1 $(error Compiler too old) else ifeq ($(shell expr match ${CXXVER} "1[6-9]"),2) # clang 16 - 19 - NEEDED_CXXFLAGS += -std=c++20 + NEEDED_CXXFLAGS = -std=c++20 else NEEDED_CXXFLAGS = -std=c++17 endif + From cab671e177d27b5e60541d571f5bbbf21ad0077d Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Sep 2024 13:28:34 -0400 Subject: [PATCH 073/527] use gexpr instead expr --- Makefile.bsd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.bsd b/Makefile.bsd index eb528799..c97527b4 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -14,7 +14,7 @@ LDLIBS = -lcrypto -lssl -lz -lpthread -lboost_system -lboost_program_options CXXVER := $(shell $(CXX) -dumpversion) ifeq (${CXXVER}, "4.2.1") # older clang always returned 4.2.1 $(error Compiler too old) -else ifeq ($(shell expr match ${CXXVER} "1[6-9]"),2) # clang 16 - 19 +else ifeq ($(shell gexpr match ${CXXVER} "1[6-9]"),2) # clang 16 - 19 NEEDED_CXXFLAGS = -std=c++20 else NEEDED_CXXFLAGS = -std=c++17 From 306ea2df37b7ad8ca216a93a54d995a53c13f83e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Sep 2024 14:12:30 -0400 Subject: [PATCH 074/527] don't apply std::move to prvalue --- libi2pd/HTTP.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index 6e427298..990781bc 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.cpp @@ -58,13 +58,13 @@ namespace http static void strsplit(const std::string & line, std::vector &tokens, char delim, std::size_t limit = 0) { - std::stringstream ss(line); + std::stringstream ss{line}; strsplit (ss, tokens, delim, limit); } static void strsplit(std::string_view line, std::vector &tokens, char delim, std::size_t limit = 0) { - std::stringstream ss(std::move(std::string(line))); + std::stringstream ss{std::string(line)}; strsplit (ss, tokens, delim, limit); } @@ -74,16 +74,15 @@ namespace http std::size_t len = 1; /*: */ std::size_t max = line.length(); if ((pos = line.find(':', pos)) == std::string::npos) - return std::make_pair("", ""); // no ':' found + return std::pair{"", ""}; // no ':' found if (pos + 1 < max) // ':' at the end of header is valid { while ((pos + len) < max && isspace(line.at(pos + len))) len++; if (len == 1) - return std::make_pair("", ""); // no following space, but something else + return std::pair{"", ""}; // no following space, but something else } - return std::make_pair(std::move (std::string (line.substr(0, pos))), - std::move (std::string (line.substr(pos + len)))); + return std::pair{std::string (line.substr(0, pos)), std::string (line.substr(pos + len))}; } void gen_rfc7231_date(std::string & out) { From 9a77c0a4b13f158aa68dab55d228673a637d62b1 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Sep 2024 07:43:24 -0400 Subject: [PATCH 075/527] recognize compiler version without gexpr --- Makefile.bsd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.bsd b/Makefile.bsd index c97527b4..4cf8f80a 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -11,10 +11,10 @@ LDLIBS = -lcrypto -lssl -lz -lpthread -lboost_system -lboost_program_options ## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove ## -std=c++11. If you want to remove this variable please do so in a way that allows setting ## custom FLAGS to work at build-time. -CXXVER := $(shell $(CXX) -dumpversion) -ifeq (${CXXVER}, "4.2.1") # older clang always returned 4.2.1 +CXXVER := $(shell $(CXX) -dumpversion|cut -c 1-2) +ifeq (${CXXVER}, "4.") # older clang always returned 4.2.1 $(error Compiler too old) -else ifeq ($(shell gexpr match ${CXXVER} "1[6-9]"),2) # clang 16 - 19 +else ifeq (${CXXVER}, ${filter ${CXXVER},16 17 18 19}) # clang 16 - 19 NEEDED_CXXFLAGS = -std=c++20 else NEEDED_CXXFLAGS = -std=c++17 From fde301deaf7277109694b50bc9c901d7d667f049 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Sep 2024 19:24:23 -0400 Subject: [PATCH 076/527] check for duplicated routers in NTCP2. Insert router into netdb right a way --- libi2pd/I2NPProtocol.h | 1 - libi2pd/NTCP2.cpp | 39 ++++++++++++++++++++++++++++++++------- libi2pd/NetDb.cpp | 4 ---- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 1acd4242..4e26fc94 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -107,7 +107,6 @@ namespace i2p enum I2NPMessageType { - eI2NPDummyMsg = 0, eI2NPDatabaseStore = 1, eI2NPDatabaseLookup = 2, eI2NPDatabaseSearchReply = 3, diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 7f0f2189..de14d3b0 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -724,8 +724,24 @@ namespace transport SendTerminationAndTerminate (eNTCP2Message3Error); return; } - auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri.GetNTCP2V4Address () : - (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri.GetYggdrasilAddress () : ri.GetNTCP2V6Address ()); + // update RouterInfo in netdb + auto ri1 = i2p::data::netdb.AddRouterInfo (ri.GetBuffer (), ri.GetBufferLen ()); // ri1 points to one from netdb now + if (!ri1) + { + LogPrint (eLogError, "NTCP2: Couldn't update RouterInfo from SessionConfirmed in netdb"); + return; + } + std::shared_ptr profile; // not null if older + if (ri.GetTimestamp () + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri1->GetTimestamp ()) + { + // received RouterInfo is older than one in netdb + profile = i2p::data::GetRouterProfile (ri1->GetIdentHash ()); // retrieve profile + if (profile && profile->IsDuplicated ()) + return; + } + + auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri1->GetNTCP2V4Address () : + (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri1->GetYggdrasilAddress () : ri1->GetNTCP2V6Address ()); if (!addr || memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32)) { LogPrint (eLogError, "NTCP2: Wrong static key in SessionConfirmed"); @@ -737,16 +753,17 @@ namespace transport memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data () + 1, addr->host.to_v6 ().to_bytes ().data () + 1, 7) : // from the same yggdrasil subnet memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), addr->host.to_v6 ().to_bytes ().data (), 8)))) // temporary address { - LogPrint (eLogError, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ()); + if (profile) // older router? + profile->Duplicated (); // mark router as duplicated in profile + else + LogPrint (eLogError, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ()); Terminate (); return; } - i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, buf.data () + 3, size)); // TODO: should insert ri and not parse it twice // TODO: process options // ready to communicate - auto existing = i2p::data::netdb.FindRouter (ri.GetRouterIdentity ()->GetIdentHash ()); // check if exists already - SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ()); + SetRemoteIdentity (ri1->GetRouterIdentity ()); if (m_Server.AddNTCP2Session (shared_from_this (), true)) { Established (); @@ -939,7 +956,15 @@ namespace transport case eNTCP2BlkRouterInfo: { LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", (int)frame[offset]); - i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, frame + offset, size)); + i2p::data::RouterInfo ri (frame + offset + 1, size - 1); + auto newRi = i2p::data::netdb.AddRouterInfo (ri.GetBuffer (), ri.GetBufferLen ()); + if (newRi) + { + auto remoteIdentity = GetRemoteIdentity (); + if (remoteIdentity && remoteIdentity->GetIdentHash () == newRi->GetIdentHash ()) + // peer's RouterInfo update + SetRemoteIdentity (newRi->GetIdentity ()); + } break; } case eNTCP2BlkI2NPMessage: diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index b222ac88..ccc43d7a 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -141,10 +141,6 @@ namespace data case eI2NPDatabaseLookup: HandleDatabaseLookupMsg (msg); break; - case eI2NPDummyMsg: - // plain RouterInfo from NTCP2 with flags for now - HandleNTCP2RouterInfoMsg (msg); - break; default: // WTF? LogPrint (eLogError, "NetDb: Unexpected message type ", (int) msg->GetTypeID ()); //i2p::HandleI2NPMessage (msg); From e0af7b077fe9ad4aeeb01de8a79cabf815d1b9ca Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Sep 2024 20:28:40 -0400 Subject: [PATCH 077/527] set max number of tags adequate to max window size --- libi2pd/ECIESX25519AEADRatchetSession.h | 2 +- libi2pd/Streaming.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 10645251..bcc07b30 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -35,7 +35,7 @@ namespace garlic const int ECIESX25519_ACK_REQUEST_MAX_NUM_ATTEMPTS = 3; const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 8192; // number of tags we request new tagset after const int ECIESX25519_MIN_NUM_GENERATED_TAGS = 24; - const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 320; + const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 800; const int ECIESX25519_NSR_NUM_GENERATED_TAGS = 12; const size_t ECIESX25519_OPTIMAL_PAYLOAD_SIZE = 1912; // 1912 = 1956 /* to fit 2 tunnel messages */ diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 84b92c9f..6a983520 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -54,8 +54,8 @@ namespace stream const size_t COMPRESSION_THRESHOLD_SIZE = 66; const int MAX_NUM_RESEND_ATTEMPTS = 10; const int INITIAL_WINDOW_SIZE = 10; - const int MIN_WINDOW_SIZE = 1; - const int MAX_WINDOW_SIZE = 1024; + const int MIN_WINDOW_SIZE = 2; + const int MAX_WINDOW_SIZE = 512; const double RTT_EWMA_ALPHA = 0.25; const double SLOWRTT_EWMA_ALPHA = 0.125; const double PREV_SPEED_KEEP_TIME_COEFF = 0.35; // 0.1 - 1 // how long will the window size stay around the previous drop level, less is longer From 855fd4d471421cec5e482b3fadd23aa5da53f489 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 6 Sep 2024 09:49:24 -0400 Subject: [PATCH 078/527] eliminate extra parsing of RouterInfo coming as RouterInfo block --- libi2pd/NTCP2.cpp | 5 ++--- libi2pd/SSU2Session.cpp | 40 +++++++++++++++++++++++----------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index de14d3b0..f7d81671 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -955,9 +955,8 @@ namespace transport break; case eNTCP2BlkRouterInfo: { - LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", (int)frame[offset]); - i2p::data::RouterInfo ri (frame + offset + 1, size - 1); - auto newRi = i2p::data::netdb.AddRouterInfo (ri.GetBuffer (), ri.GetBufferLen ()); + LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", (int)frame[offset]); + auto newRi = i2p::data::netdb.AddRouterInfo (frame + offset + 1, size - 1); if (newRi) { auto remoteIdentity = GetRemoteIdentity (); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 62bbf41f..eb662716 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1750,28 +1750,34 @@ namespace transport void SSU2Session::HandleRouterInfo (const uint8_t * buf, size_t len) { - auto ri = ExtractRouterInfo (buf, len); - if (ri) + if (len < 2) return; + // not from SessionConfirmed, we must add it instantly to use in next block + std::shared_ptr newRi; + if (buf[0] & SSU2_ROUTER_INFO_FLAG_GZIP) // compressed? { - // not from SessionConfirmed, we must add it instantly to use in next block - auto newRi = i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // TODO: add ri - if (newRi) + auto ri = ExtractRouterInfo (buf, len); + if (ri) + newRi = i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); + } + else // use buffer directly. TODO: handle frag + newRi = i2p::data::netdb.AddRouterInfo (buf + 2, len - 2); + + if (newRi) + { + auto remoteIdentity = GetRemoteIdentity (); + if (remoteIdentity && remoteIdentity->GetIdentHash () == newRi->GetIdentHash ()) { - auto remoteIdentity = GetRemoteIdentity (); - if (remoteIdentity && remoteIdentity->GetIdentHash () == newRi->GetIdentHash ()) + // peer's RouterInfo update + SetRemoteIdentity (newRi->GetIdentity ()); + auto address = m_RemoteEndpoint.address ().is_v6 () ? newRi->GetSSU2V6Address () : newRi->GetSSU2V4Address (); + if (address) { - // peer's RouterInfo update - SetRemoteIdentity (newRi->GetIdentity ()); - auto address = m_RemoteEndpoint.address ().is_v6 () ? newRi->GetSSU2V6Address () : newRi->GetSSU2V4Address (); - if (address) - { - m_Address = address; - if (IsOutgoing () && m_RelayTag && !address->IsIntroducer ()) - m_RelayTag = 0; // not longer introducer - } + m_Address = address; + if (IsOutgoing () && m_RelayTag && !address->IsIntroducer ()) + m_RelayTag = 0; // not longer introducer } } - } + } } void SSU2Session::HandleAck (const uint8_t * buf, size_t len) From d539c9677e83434471d82733d13640f44af9f6be Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 6 Sep 2024 19:04:07 -0400 Subject: [PATCH 079/527] don't accept tunnels if connected through proxy --- libi2pd/RouterContext.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index efbfee65..c9bc5229 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -323,6 +323,9 @@ namespace i2p case eRouterStatusFirewalled: SetUnreachable (true, false); // ipv4 break; + case eRouterStatusProxy: + m_AcceptsTunnels = false; + break; default: ; } From 8d1c18666593cfae9e3585756437b6ea6025ef0f Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 7 Sep 2024 16:25:26 -0400 Subject: [PATCH 080/527] limited connectivity mode --- libi2pd/NetDb.cpp | 3 ++- libi2pd/RouterContext.h | 1 + libi2pd/Transports.cpp | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index ccc43d7a..55e17b23 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -759,7 +759,8 @@ 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 + if (direct && (i2p::transport::transports.RoutesRestricted () || i2p::context.IsLimitedConnectivity ())) + direct = false; // always use tunnels for restricted routes or limited connectivity if (m_Requests) m_Requests->PostRequestDestination (destination, requestComplete, direct); else diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 09c3678f..03f1d10d 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -177,6 +177,7 @@ namespace garlic void SetMTU (int mtu, bool v4); void SetHidden(bool hide) { m_IsHiddenMode = hide; }; bool IsHidden() const { return m_IsHiddenMode; }; + bool IsLimitedConnectivity () const { return m_Status == eRouterStatusProxy; }; // TODO: implement other cases i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; }; void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index cf30b428..549efb63 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -599,7 +599,7 @@ namespace transport } LogPrint (eLogInfo, "Transports: No compatible addresses available"); - if (peer->router->IsReachableFrom (i2p::context.GetRouterInfo ())) + if (!i2p::context.IsLimitedConnectivity () && peer->router->IsReachableFrom (i2p::context.GetRouterInfo ())) i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed but router claimed them peer->Done (); std::unique_lock l(m_PeersMutex); From ba451eeca5ebf13f48b50cf3b44abe84a5f3269d Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 7 Sep 2024 18:01:48 -0400 Subject: [PATCH 081/527] set congestion cap G immediately if through proxy --- libi2pd/RouterContext.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index c9bc5229..f9548139 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -325,6 +325,7 @@ namespace i2p break; case eRouterStatusProxy: m_AcceptsTunnels = false; + UpdateCongestion (); break; default: ; From cd648b9b3fb7c5ee3aed89d71728dba3c12f4f27 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 8 Sep 2024 16:30:27 -0400 Subject: [PATCH 082/527] use std::atomic> instead boost::shared_ptr if applicable --- libi2pd/NetDb.hpp | 6 +- libi2pd/RouterInfo.cpp | 123 ++++++++++++++++++++++------------------- libi2pd/RouterInfo.h | 21 +++++-- 3 files changed, 84 insertions(+), 66 deletions(-) diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 8efba61a..1797c04d 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -127,12 +127,12 @@ namespace data } bool PopulateRouterInfoBuffer (std::shared_ptr r); std::shared_ptr NewRouterInfoAddress () { return m_RouterInfoAddressesPool.AcquireSharedMt (); }; - boost::shared_ptr NewRouterInfoAddresses () + RouterInfo::AddressesPtr NewRouterInfoAddresses () { - return boost::shared_ptr(m_RouterInfoAddressVectorsPool.AcquireMt (), + return RouterInfo::AddressesPtr{m_RouterInfoAddressVectorsPool.AcquireMt (), std::bind ::*)(RouterInfo::Addresses *)> (&i2p::util::MemoryPoolMt::ReleaseMt, - &m_RouterInfoAddressVectorsPool, std::placeholders::_1)); + &m_RouterInfoAddressVectorsPool, std::placeholders::_1)}; }; std::shared_ptr NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); }; std::shared_ptr NewIdentity (const uint8_t * buf, size_t len) { return m_IdentitiesPool.AcquireSharedMt (buf, len); }; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index c24d0957..b6abb48a 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -10,10 +10,10 @@ #include #include "I2PEndian.h" #include +#include #include -#include #include // for boost::to_lower -#if (BOOST_VERSION >= 105300) +#ifndef __cpp_lib_atomic_shared_ptr #include #endif #include "version.h" @@ -40,7 +40,7 @@ namespace data RouterInfo::RouterInfo (): m_Buffer (nullptr) { - m_Addresses = boost::make_shared(); // create empty list + m_Addresses = AddressesPtr(new Addresses ()); // create empty list } RouterInfo::RouterInfo (const std::string& fullPath): @@ -48,7 +48,7 @@ namespace data m_SupportedTransports (0),m_ReachableTransports (0), m_PublishedTransports (0), m_Caps (0), m_Version (0), m_Congestion (eLowCongestion) { - m_Addresses = boost::make_shared(); // create empty list + m_Addresses = AddressesPtr(new Addresses ()); // create empty list m_Buffer = NewBuffer (); // always RouterInfo's ReadFromFile (fullPath); } @@ -60,7 +60,7 @@ namespace data { if (len <= MAX_RI_BUFFER_SIZE) { - m_Addresses = boost::make_shared(); // create empty list + m_Addresses = AddressesPtr(new Addresses ()); // create empty list m_Buffer = buf; if (m_Buffer) m_Buffer->SetBufferLen (len); ReadFromBuffer (true); @@ -439,10 +439,10 @@ namespace data } m_ReachableTransports |= m_PublishedTransports; // update addresses -#if (BOOST_VERSION >= 105300) +#ifdef __cpp_lib_atomic_shared_ptr + m_Addresses = addresses; +#else boost::atomic_store (&m_Addresses, addresses); -#else - m_Addresses = addresses; // race condition #endif // read peers uint8_t numPeers; @@ -692,12 +692,12 @@ namespace data if (addr->IsV4 ()) { m_SupportedTransports |= eNTCP2V4; - (*m_Addresses)[eNTCP2V4Idx] = addr; + (*GetAddresses ())[eNTCP2V4Idx] = addr; } if (addr->IsV6 ()) { m_SupportedTransports |= eNTCP2V6; - (*m_Addresses)[eNTCP2V6Idx] = addr; + (*GetAddresses ())[eNTCP2V6Idx] = addr; } } @@ -718,11 +718,12 @@ namespace data if (host.is_v4 ()) addr->caps |= eV4; if (host.is_v6 ()) addr->caps |= eV6; } + auto addresses = GetAddresses (); if (addr->IsV4 ()) { m_SupportedTransports |= eNTCP2V4; m_ReachableTransports |= eNTCP2V4; - (*m_Addresses)[eNTCP2V4Idx] = addr; + (*addresses)[eNTCP2V4Idx] = addr; } if (addr->IsV6 ()) { @@ -730,30 +731,31 @@ namespace data { m_SupportedTransports |= eNTCP2V6Mesh; m_ReachableTransports |= eNTCP2V6Mesh; - (*m_Addresses)[eNTCP2V6MeshIdx] = addr; + (*addresses)[eNTCP2V6MeshIdx] = addr; } else { m_SupportedTransports |= eNTCP2V6; m_ReachableTransports |= eNTCP2V6; - (*m_Addresses)[eNTCP2V6Idx] = addr; + (*addresses)[eNTCP2V6Idx] = addr; } } } void RouterInfo::RemoveNTCP2Address (bool v4) { + auto addresses = GetAddresses (); if (v4) { - if ((*m_Addresses)[eNTCP2V6Idx]) - (*m_Addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4; - (*m_Addresses)[eNTCP2V4Idx].reset (); + if ((*addresses)[eNTCP2V6Idx]) + (*addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4; + (*addresses)[eNTCP2V4Idx].reset (); } else { - if ((*m_Addresses)[eNTCP2V4Idx]) - (*m_Addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6; - (*m_Addresses)[eNTCP2V6Idx].reset (); + if ((*addresses)[eNTCP2V4Idx]) + (*addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6; + (*addresses)[eNTCP2V6Idx].reset (); } UpdateSupportedTransports (); } @@ -769,15 +771,16 @@ namespace data addr->ssu->mtu = 0; memcpy (addr->s, staticKey, 32); memcpy (addr->i, introKey, 32); + auto addresses = GetAddresses (); if (addr->IsV4 ()) { m_SupportedTransports |= eSSU2V4; - (*m_Addresses)[eSSU2V4Idx] = addr; + (*addresses)[eSSU2V4Idx] = addr; } if (addr->IsV6 ()) { m_SupportedTransports |= eSSU2V6; - (*m_Addresses)[eSSU2V6Idx] = addr; + (*addresses)[eSSU2V6Idx] = addr; } } @@ -802,33 +805,35 @@ namespace data if (host.is_v4 ()) addr->caps |= eV4; if (host.is_v6 ()) addr->caps |= eV6; } + auto addresses = GetAddresses (); if (addr->IsV4 ()) { m_SupportedTransports |= eSSU2V4; m_ReachableTransports |= eSSU2V4; - (*m_Addresses)[eSSU2V4Idx] = addr; + (*addresses)[eSSU2V4Idx] = addr; } if (addr->IsV6 ()) { m_SupportedTransports |= eSSU2V6; m_ReachableTransports |= eSSU2V6; - (*m_Addresses)[eSSU2V6Idx] = addr; + (*addresses)[eSSU2V6Idx] = addr; } } void RouterInfo::RemoveSSU2Address (bool v4) { + auto addresses = GetAddresses (); if (v4) { - if ((*m_Addresses)[eSSU2V6Idx]) - (*m_Addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4; - (*m_Addresses)[eSSU2V4Idx].reset (); + if ((*addresses)[eSSU2V6Idx]) + (*addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4; + (*addresses)[eSSU2V4Idx].reset (); } else { - if ((*m_Addresses)[eSSU2V4Idx]) - (*m_Addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6; - (*m_Addresses)[eSSU2V6Idx].reset (); + if ((*addresses)[eSSU2V4Idx]) + (*addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6; + (*addresses)[eSSU2V6Idx].reset (); } UpdateSupportedTransports (); } @@ -869,17 +874,18 @@ namespace data { if (IsV6 ()) { - if ((*m_Addresses)[eNTCP2V6Idx]) + auto addresses = GetAddresses (); + if ((*addresses)[eNTCP2V6Idx]) { - if ((*m_Addresses)[eNTCP2V6Idx]->IsV4 () && (*m_Addresses)[eNTCP2V4Idx]) - (*m_Addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6; - (*m_Addresses)[eNTCP2V6Idx].reset (); + if ((*addresses)[eNTCP2V6Idx]->IsV4 () && (*addresses)[eNTCP2V4Idx]) + (*addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6; + (*addresses)[eNTCP2V6Idx].reset (); } - if ((*m_Addresses)[eSSU2V6Idx]) + if ((*addresses)[eSSU2V6Idx]) { - if ((*m_Addresses)[eSSU2V6Idx]->IsV4 () && (*m_Addresses)[eSSU2V4Idx]) - (*m_Addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6; - (*m_Addresses)[eSSU2V6Idx].reset (); + if ((*addresses)[eSSU2V6Idx]->IsV4 () && (*addresses)[eSSU2V4Idx]) + (*addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6; + (*addresses)[eSSU2V6Idx].reset (); } UpdateSupportedTransports (); } @@ -889,17 +895,18 @@ namespace data { if (IsV4 ()) { - if ((*m_Addresses)[eNTCP2V4Idx]) + auto addresses = GetAddresses (); + if ((*addresses)[eNTCP2V4Idx]) { - if ((*m_Addresses)[eNTCP2V4Idx]->IsV6 () && (*m_Addresses)[eNTCP2V6Idx]) - (*m_Addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4; - (*m_Addresses)[eNTCP2V4Idx].reset (); + if ((*addresses)[eNTCP2V4Idx]->IsV6 () && (*addresses)[eNTCP2V6Idx]) + (*addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4; + (*addresses)[eNTCP2V4Idx].reset (); } - if ((*m_Addresses)[eSSU2V4Idx]) + if ((*addresses)[eSSU2V4Idx]) { - if ((*m_Addresses)[eSSU2V4Idx]->IsV6 () && (*m_Addresses)[eSSU2V6Idx]) - (*m_Addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4; - (*m_Addresses)[eSSU2V4Idx].reset (); + if ((*addresses)[eSSU2V4Idx]->IsV6 () && (*addresses)[eSSU2V6Idx]) + (*addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4; + (*addresses)[eSSU2V4Idx].reset (); } UpdateSupportedTransports (); } @@ -920,7 +927,7 @@ namespace data { m_SupportedTransports &= ~eNTCP2V6Mesh; m_ReachableTransports &= ~eNTCP2V6Mesh; - (*m_Addresses)[eNTCP2V6MeshIdx].reset (); + (*GetAddresses ())[eNTCP2V6MeshIdx].reset (); } } @@ -949,12 +956,12 @@ namespace data return nullptr; } - boost::shared_ptr RouterInfo::GetAddresses () const + RouterInfo::AddressesPtr RouterInfo::GetAddresses () const { -#if (BOOST_VERSION >= 105300) - return boost::atomic_load (&m_Addresses); -#else +#ifdef __cpp_lib_atomic_shared_ptr return m_Addresses; +#else + return boost::atomic_load (&m_Addresses); #endif } @@ -962,10 +969,10 @@ namespace data std::shared_ptr RouterInfo::GetAddress (Filter filter) const { // TODO: make it more generic using comparator -#if (BOOST_VERSION >= 105300) +#ifdef __cpp_lib_atomic_shared_ptr + AddressesPtr addresses = m_Addresses; +#else auto addresses = boost::atomic_load (&m_Addresses); -#else - auto addresses = m_Addresses; #endif for (const auto& address : *addresses) if (address && filter (address)) return address; @@ -1062,7 +1069,7 @@ namespace data void RouterInfo::SetUnreachableAddressesTransportCaps (uint8_t transports) { - for (auto& addr: *m_Addresses) + for (auto& addr: *GetAddresses ()) { if (addr && !addr->published) { @@ -1076,7 +1083,7 @@ namespace data { m_SupportedTransports = 0; m_ReachableTransports = 0; - for (const auto& addr: *m_Addresses) + for (const auto& addr: *GetAddresses ()) { if (!addr) continue; uint8_t transports = 0; @@ -1151,7 +1158,7 @@ namespace data return netdb.NewRouterInfoAddress (); } - boost::shared_ptr RouterInfo::NewAddresses () const + RouterInfo::AddressesPtr RouterInfo::NewAddresses () const { return netdb.NewRouterInfoAddresses (); } @@ -1503,9 +1510,9 @@ namespace data return std::make_shared
(); } - boost::shared_ptr LocalRouterInfo::NewAddresses () const + RouterInfo::AddressesPtr LocalRouterInfo::NewAddresses () const { - return boost::make_shared (); + return RouterInfo::AddressesPtr(new RouterInfo::Addresses ()); } std::shared_ptr LocalRouterInfo::NewIdentity (const uint8_t * buf, size_t len) const diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 16f072d0..68d6b0f0 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -15,8 +15,11 @@ #include #include #include +#include #include +#ifndef __cpp_lib_atomic_shared_ptr #include +#endif #include "Identity.h" #include "Profiling.h" #include "Family.h" @@ -199,7 +202,11 @@ namespace data }; typedef std::array, eNumTransports> Addresses; - +#ifdef __cpp_lib_atomic_shared_ptr + typedef std::shared_ptr AddressesPtr; +#else + typedef boost::shared_ptr AddressesPtr; +#endif RouterInfo (const std::string& fullPath); RouterInfo (const RouterInfo& ) = default; RouterInfo& operator=(const RouterInfo& ) = default; @@ -214,7 +221,7 @@ namespace data int GetVersion () const { return m_Version; }; virtual void SetProperty (const std::string& key, const std::string& value) {}; virtual void ClearProperties () {}; - boost::shared_ptr GetAddresses () const; // should be called for local RI only, otherwise must return shared_ptr + AddressesPtr GetAddresses () const; // should be called for local RI only, otherwise must return shared_ptr std::shared_ptr GetNTCP2V4Address () const; std::shared_ptr GetNTCP2V6Address () const; std::shared_ptr GetPublishedNTCP2V4Address () const; @@ -333,7 +340,7 @@ namespace data std::shared_ptr GetAddress (Filter filter) const; virtual std::shared_ptr NewBuffer () const; virtual std::shared_ptr
NewAddress () const; - virtual boost::shared_ptr NewAddresses () const; + virtual AddressesPtr NewAddresses () const; virtual std::shared_ptr NewIdentity (const uint8_t * buf, size_t len) const; private: @@ -342,7 +349,11 @@ namespace data std::shared_ptr m_RouterIdentity; std::shared_ptr m_Buffer; uint64_t m_Timestamp; // in milliseconds - boost::shared_ptr m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9 +#ifdef __cpp_lib_atomic_shared_ptr + std::atomic m_Addresses; +#else + AddressesPtr m_Addresses; +#endif bool m_IsUpdated, m_IsUnreachable, m_IsFloodfill; CompatibleTransports m_SupportedTransports, m_ReachableTransports, m_PublishedTransports; uint8_t m_Caps; @@ -377,7 +388,7 @@ namespace data void WriteString (const std::string& str, std::ostream& s) const; std::shared_ptr NewBuffer () const override; std::shared_ptr
NewAddress () const override; - boost::shared_ptr NewAddresses () const override; + RouterInfo::AddressesPtr NewAddresses () const override; std::shared_ptr NewIdentity (const uint8_t * buf, size_t len) const override; private: From bcace3fb295bbe2ad971347e29fb237f4bd33929 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 8 Sep 2024 17:53:41 -0400 Subject: [PATCH 083/527] use -std=c++17 --- build/cmake_modules/CheckAtomic.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/cmake_modules/CheckAtomic.cmake b/build/cmake_modules/CheckAtomic.cmake index d5ec6a0a..4954e3e5 100644 --- a/build/cmake_modules/CheckAtomic.cmake +++ b/build/cmake_modules/CheckAtomic.cmake @@ -8,7 +8,7 @@ INCLUDE(CheckLibraryExists) function(check_working_cxx_atomics varname) set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11") + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++17") CHECK_CXX_SOURCE_COMPILES(" #include std::atomic x; @@ -25,7 +25,7 @@ endfunction(check_working_cxx_atomics) function(check_working_cxx_atomics64 varname) set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}") + set(CMAKE_REQUIRED_FLAGS "-std=c++17 ${CMAKE_REQUIRED_FLAGS}") CHECK_CXX_SOURCE_COMPILES(" #include #include From 07d108bb6f8b4cc9398c18e3e5d23d146344aa79 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 9 Sep 2024 18:40:06 -0400 Subject: [PATCH 084/527] send immediate ack request if no packet being sent --- libi2pd/Streaming.cpp | 11 ++++++++--- libi2pd/Streaming.h | 7 +++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 881818d5..4ee3eb85 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -877,13 +877,18 @@ namespace stream } packet[size] = 0; size++; // resend delay - htobuf16 (packet + size, choking ? PACKET_FLAG_DELAY_REQUESTED : 0); // no flags set or delay + bool requestImmediateAck = false; + if (!choking) + requestImmediateAck = m_LastSendTime && ts > m_LastSendTime + REQUEST_IMMEDIATE_ACK_INTERVAL && + ts > m_LastSendTime + REQUEST_IMMEDIATE_ACK_INTERVAL + m_LocalDestination.GetRandom () % REQUEST_IMMEDIATE_ACK_INTERVAL_VARIANCE; + htobuf16 (packet + size, (choking || requestImmediateAck) ? PACKET_FLAG_DELAY_REQUESTED : 0); // no flags set or delay requested size += 2; // flags - if (choking) + if (choking || requestImmediateAck) { htobuf16 (packet + size, 2); // 2 bytes delay interval - htobuf16 (packet + size + 2, DELAY_CHOKING); // set choking interval + htobuf16 (packet + size + 2, choking ? DELAY_CHOKING : 0); // set choking or immediated ack interval size += 2; + if (requestImmediateAck) m_LastSendTime = ts; // ack request sent } else htobuf16 (packet + size, 0); // no options diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 6a983520..69941040 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -70,7 +70,9 @@ namespace stream const int MAX_RECEIVE_TIMEOUT = 20; // in seconds const uint16_t DELAY_CHOKING = 60000; // in milliseconds const uint64_t SEND_INTERVAL = 1000; // in microseconds - + const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL = 7500; // in milliseconds + const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL_VARIANCE = 3200; // in milliseconds + struct Packet { size_t len, offset; @@ -283,7 +285,8 @@ namespace stream float m_WindowSize, m_LastWindowDropSize, m_WindowDropTargetSize; int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; double m_Jitter; - uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, m_LastSendTime; // microseconds + uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, // microseconds + m_LastSendTime; // miliseconds uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed int m_NumResendAttempts, m_NumPacketsToSend; size_t m_MTU; From 699e17b594de6ac6378c9649e97a6db973fd4c65 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 9 Sep 2024 22:26:03 -0400 Subject: [PATCH 085/527] handle plain ack with options --- libi2pd/Streaming.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 4ee3eb85..d5ec57ce 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -184,10 +184,15 @@ namespace stream ProcessAck (packet); int32_t receivedSeqn = packet->GetSeqn (); - if (!receivedSeqn && !packet->GetFlags ()) + if (!receivedSeqn) { - // plain ack - LogPrint (eLogDebug, "Streaming: Plain ACK received"); + uint16_t flags = packet->GetFlags (); + if (flags) + // plain ack with options + ProcessOptions (flags, packet); + else + // plain ack + LogPrint (eLogDebug, "Streaming: Plain ACK received"); m_LocalDestination.DeletePacket (packet); return; } From 50d297fa29cd0c17f8096cebc313a7b5dc0f8c0e Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 9 Sep 2024 22:37:35 -0400 Subject: [PATCH 086/527] check if first packet --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index d5ec57ce..ba886ab9 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -184,7 +184,7 @@ namespace stream ProcessAck (packet); int32_t receivedSeqn = packet->GetSeqn (); - if (!receivedSeqn) + if (!receivedSeqn && m_LastReceivedSequenceNumber >= 0) { uint16_t flags = packet->GetFlags (); if (flags) From a65dd218da008d6420ef322bc47e527583929511 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 10 Sep 2024 10:27:26 -0400 Subject: [PATCH 087/527] correct endianess in SendQuickAck --- libi2pd/Streaming.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index ba886ab9..e75aa39b 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -886,12 +886,12 @@ namespace stream if (!choking) requestImmediateAck = m_LastSendTime && ts > m_LastSendTime + REQUEST_IMMEDIATE_ACK_INTERVAL && ts > m_LastSendTime + REQUEST_IMMEDIATE_ACK_INTERVAL + m_LocalDestination.GetRandom () % REQUEST_IMMEDIATE_ACK_INTERVAL_VARIANCE; - htobuf16 (packet + size, (choking || requestImmediateAck) ? PACKET_FLAG_DELAY_REQUESTED : 0); // no flags set or delay requested + htobe16buf (packet + size, (choking || requestImmediateAck) ? PACKET_FLAG_DELAY_REQUESTED : 0); // no flags set or delay requested size += 2; // flags if (choking || requestImmediateAck) { - htobuf16 (packet + size, 2); // 2 bytes delay interval - htobuf16 (packet + size + 2, choking ? DELAY_CHOKING : 0); // set choking or immediated ack interval + htobe16buf (packet + size, 2); // 2 bytes delay interval + htobe16buf (packet + size + 2, choking ? DELAY_CHOKING : 0); // set choking or immediated ack interval size += 2; if (requestImmediateAck) m_LastSendTime = ts; // ack request sent } From 261acbbd6609f724ace3278cc527fcf079ba15eb Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 10 Sep 2024 12:22:42 -0400 Subject: [PATCH 088/527] recalculate RTT for one way communications --- libi2pd/Streaming.cpp | 20 ++++++++++++++++---- libi2pd/Streaming.h | 1 + 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index e75aa39b..5c9dc6dc 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -73,7 +73,7 @@ namespace stream m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), - m_IsTimeOutResend (false), m_LocalDestination (local), + m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), @@ -101,7 +101,7 @@ namespace stream m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), - m_IsTimeOutResend (false), m_LocalDestination (local), + m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_LocalDestination (local), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), @@ -192,7 +192,15 @@ namespace stream ProcessOptions (flags, packet); else // plain ack - LogPrint (eLogDebug, "Streaming: Plain ACK received"); + { + LogPrint (eLogDebug, "Streaming: Plain ACK received"); + if (m_IsImmediateAckRequested) + { + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + m_RTT = (m_RTT + (ts - m_LastSendTime)) / 2; + m_IsImmediateAckRequested = false; + } + } m_LocalDestination.DeletePacket (packet); return; } @@ -893,7 +901,11 @@ namespace stream htobe16buf (packet + size, 2); // 2 bytes delay interval htobe16buf (packet + size + 2, choking ? DELAY_CHOKING : 0); // set choking or immediated ack interval size += 2; - if (requestImmediateAck) m_LastSendTime = ts; // ack request sent + if (requestImmediateAck) // ack request sent + { + m_LastSendTime = ts; + m_IsImmediateAckRequested = true; + } } else htobuf16 (packet + size, 0); // no options diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 69941040..70853d64 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -265,6 +265,7 @@ namespace stream bool m_IsSendTime; bool m_IsWinDropped; bool m_IsTimeOutResend; + bool m_IsImmediateAckRequested; StreamingDestination& m_LocalDestination; std::shared_ptr m_RemoteIdentity; std::shared_ptr m_TransientVerifier; // in case of offline key From 272bf7dbc199de9e45beb04da7538266b31edc02 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 10 Sep 2024 12:35:36 -0400 Subject: [PATCH 089/527] terminate NTCP2 session from duplicated router properly --- libi2pd/NTCP2.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f7d81671..a33d4fef 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -729,6 +729,7 @@ namespace transport if (!ri1) { LogPrint (eLogError, "NTCP2: Couldn't update RouterInfo from SessionConfirmed in netdb"); + Terminate (); return; } std::shared_ptr profile; // not null if older @@ -737,7 +738,10 @@ namespace transport // received RouterInfo is older than one in netdb profile = i2p::data::GetRouterProfile (ri1->GetIdentHash ()); // retrieve profile if (profile && profile->IsDuplicated ()) + { + SendTerminationAndTerminate (eNTCP2Banned); return; + } } auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri1->GetNTCP2V4Address () : @@ -756,8 +760,8 @@ namespace transport if (profile) // older router? profile->Duplicated (); // mark router as duplicated in profile else - LogPrint (eLogError, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ()); - Terminate (); + LogPrint (eLogInfo, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ()); + SendTerminationAndTerminate (eNTCP2Banned); return; } // TODO: process options From 78ec5b2c6e375f5552fe273f7121e0abb58ab680 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 11 Sep 2024 11:24:51 -0400 Subject: [PATCH 090/527] faster RTT recalculation if bad sample --- libi2pd/Streaming.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 5c9dc6dc..ba71f0ac 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -197,7 +197,13 @@ namespace stream if (m_IsImmediateAckRequested) { auto ts = i2p::util::GetMillisecondsSinceEpoch (); - m_RTT = (m_RTT + (ts - m_LastSendTime)) / 2; + if (m_IsFirstRttSample) + { + m_RTT = ts - m_LastSendTime; + m_IsFirstRttSample = false; + } + else + m_RTT = (m_RTT + (ts - m_LastSendTime)) / 2; m_IsImmediateAckRequested = false; } } From 3d0a1afd64826fe582d4e87475f8d61d66cbfb47 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 11 Sep 2024 12:06:55 -0400 Subject: [PATCH 091/527] check if addressbook is enabled --- libi2pd_client/AddressBook.cpp | 18 +++++++++++------- libi2pd_client/AddressBook.h | 5 +++-- libi2pd_client/HTTPProxy.cpp | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index 928aaa05..14599cf7 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -441,7 +441,7 @@ namespace client auto ident = std::make_shared(); if (ident->FromBase64 (jump)) { - m_Storage->AddAddress (ident); + if (m_Storage) m_Storage->AddAddress (ident); m_Addresses[address] = std::make_shared
(ident->GetIdentHash ()); LogPrint (eLogInfo, "Addressbook: Added ", address," -> ", ToAddress(ident->GetIdentHash ())); } @@ -452,18 +452,19 @@ namespace client void AddressBook::InsertFullAddress (std::shared_ptr address) { - m_Storage->AddAddress (address); + if (m_Storage) m_Storage->AddAddress (address); } std::shared_ptr AddressBook::GetFullAddress (const std::string& address) { auto addr = GetAddress (address); if (!addr || !addr->IsIdentHash ()) return nullptr; - return m_Storage->GetAddress (addr->identHash); + return m_Storage ? m_Storage->GetAddress (addr->identHash) : nullptr; } void AddressBook::LoadHosts () { + if (!m_Storage) return; if (m_Storage->Load (m_Addresses) > 0) { m_IsLoaded = true; @@ -534,15 +535,18 @@ namespace client ident->GetSigningKeyType () != i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) // don't replace by DSA { it->second->identHash = ident->GetIdentHash (); - m_Storage->AddAddress (ident); - m_Storage->RemoveAddress (it->second->identHash); + if (m_Storage) + { + m_Storage->AddAddress (ident); + m_Storage->RemoveAddress (it->second->identHash); + } LogPrint (eLogInfo, "Addressbook: Updated host: ", name); } } else { m_Addresses.emplace (name, std::make_shared
(ident->GetIdentHash ())); - m_Storage->AddAddress (ident); + if (m_Storage) m_Storage->AddAddress (ident); if (is_update) LogPrint (eLogInfo, "Addressbook: Added new host: ", name); } @@ -554,7 +558,7 @@ namespace client if (numAddresses > 0) { if (!incomplete) m_IsLoaded = true; - m_Storage->Save (m_Addresses); + if (m_Storage) m_Storage->Save (m_Addresses); } return !incomplete; } diff --git a/libi2pd_client/AddressBook.h b/libi2pd_client/AddressBook.h index 9b2c7e7e..fc4f19a7 100644 --- a/libi2pd_client/AddressBook.h +++ b/libi2pd_client/AddressBook.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 * @@ -99,7 +99,8 @@ namespace client std::string ToAddress(std::shared_ptr ident) { return ToAddress(ident->GetIdentHash ()); } bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified); - + bool IsEnabled () const { return m_IsEnabled; } + private: void StartSubscriptions (); diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 67ee2c5e..30a4e181 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -376,7 +376,7 @@ namespace proxy { std::string jump; if (ExtractAddressHelper(m_RequestURL, jump, m_Confirm)) { - if (!m_Addresshelper) + if (!m_Addresshelper || !i2p::client::context.GetAddressBook ().IsEnabled ()) { LogPrint(eLogWarning, "HTTPProxy: Addresshelper request rejected"); GenericProxyError(tr("Invalid request"), tr("Addresshelper is not supported")); From a5e9d9c6a3bc35b0b8128b779cfb8296fb860a0f Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 11 Sep 2024 20:18:05 +0300 Subject: [PATCH 092/527] [gha] winxp build fix --- .github/workflows/build-windows.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 06bc898c..536d16e0 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -205,6 +205,7 @@ jobs: run: | cd MINGW-packages/mingw-w64-openssl gpg --recv-keys D894E2CE8B3D79F5 + gpg --recv-keys 216094DFD0CB81EF MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck - name: Install openssl package run: pacman --noconfirm -U MINGW-packages/mingw-w64-openssl/mingw-w64-i686-*-any.pkg.tar.zst From cb0801fc16b691c516ecac725224c0df66c9a348 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 11 Sep 2024 20:54:22 -0400 Subject: [PATCH 093/527] reduce number of retransmits --- libi2pd/Streaming.cpp | 68 +++++++++++++++++++++++++------------------ libi2pd/Streaming.h | 7 +++-- 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index ba71f0ac..5cabc36c 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -76,7 +76,7 @@ namespace stream m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), - m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), + m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), @@ -103,7 +103,7 @@ namespace stream m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_LocalDestination (local), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), - m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), + m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), @@ -550,27 +550,34 @@ namespace stream { m_RTT = rttSample; m_SlowRTT = rttSample; + m_SlowRTT2 = rttSample; m_PrevRTTSample = rttSample; + m_Jitter = rttSample / 10; // 10% + m_Jitter += 5; // for low-latency connections m_IsFirstRttSample = false; } else - m_RTT = RTT_EWMA_ALPHA * rttSample + (1.0 - RTT_EWMA_ALPHA) * m_RTT; - // calculate jitter - double jitter = 0; - if (rttSample > m_PrevRTTSample) - jitter = rttSample - m_PrevRTTSample; - else if (rttSample < m_PrevRTTSample) - jitter = m_PrevRTTSample - rttSample; - else - jitter = std::round (rttSample / 10); // 10% - jitter += 1; // for low-latency connections - m_Jitter = (0.025 * jitter) + (1.0 - 0.025) * m_Jitter; + m_RTT = (m_PrevRTTSample + rttSample) / 2; + if (!m_IsWinDropped) + { + m_SlowRTT = SLOWRTT_EWMA_ALPHA * m_RTT + (1.0 - SLOWRTT_EWMA_ALPHA) * m_SlowRTT; + m_SlowRTT2 = RTT_EWMA_ALPHA * m_RTT + (1.0 - RTT_EWMA_ALPHA) * m_SlowRTT2; + // calculate jitter + double jitter = 0; + if (rttSample > m_PrevRTTSample) + jitter = rttSample - m_PrevRTTSample; + else if (rttSample < m_PrevRTTSample) + jitter = m_PrevRTTSample - rttSample; + else + jitter = rttSample / 10; // 10% + jitter += 5; // for low-latency connections + m_Jitter = (0.05 * jitter) + (1.0 - 0.05) * m_Jitter; + } // // delay-based CC - if ((m_RTT > m_SlowRTT + m_Jitter && rttSample > m_RTT && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection + if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection ProcessWindowDrop (); UpdatePacingTime (); - m_SlowRTT = SLOWRTT_EWMA_ALPHA * rttSample + (1.0 - SLOWRTT_EWMA_ALPHA) * m_SlowRTT; m_PrevRTTSample = rttSample; bool wasInitial = m_RTO == INITIAL_RTO; @@ -579,18 +586,23 @@ namespace stream if (wasInitial) ScheduleResend (); } - if (ackThrough > m_DropWindowDelaySequenceNumber && m_WindowSize <= m_WindowDropTargetSize) - m_IsWinDropped = false; - if (acknowledged && m_IsWinDropped && m_WindowSize > m_WindowDropTargetSize) + if (m_IsWinDropped && ackThrough > m_DropWindowDelaySequenceNumber) { - if (ackCount > 1) - m_WindowSize = m_SentPackets.size () + 1; - else - { - m_WindowSize = m_SentPackets.size (); - m_IsResendNeeded = true; - } + m_IsFirstRttSample = true; + m_IsWinDropped = false; + } + if (m_WindowDropTargetSize && m_WindowSize <= m_WindowDropTargetSize) + { + m_WindowDropTargetSize = 0; + m_DropWindowDelaySequenceNumber = m_SequenceNumber; + } + if (acknowledged && m_WindowDropTargetSize && m_WindowSize > m_WindowDropTargetSize) + { + m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter)); // we assume that the next rtt sample may be much larger than the current + m_IsResendNeeded = true; + m_WindowSize = m_SentPackets.size () + 1; // if there are no packets to resend, just send one regular packet if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; + if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; m_WindowIncCounter = 0; UpdatePacingTime (); } @@ -598,10 +610,10 @@ namespace stream { ScheduleResend (); } - if ((m_SendBuffer.IsEmpty () && m_SentPackets.size () > 0) // tail loss - || int(m_SentPackets.size ()) > m_WindowSize) // or we drop window + if (m_SendBuffer.IsEmpty () && m_SentPackets.size () > 0) // tail loss { m_IsResendNeeded = true; + m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter)); // to prevent spurious retransmit } if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ()) { @@ -1304,7 +1316,7 @@ namespace stream if (m_NumResendAttempts == 1 && m_RTO != INITIAL_RTO) { // loss-based CC - if (!m_IsWinDropped) + if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED) ProcessWindowDrop (); } else if (m_IsTimeOutResend) diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 70853d64..63fe2033 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -56,8 +56,8 @@ namespace stream const int INITIAL_WINDOW_SIZE = 10; const int MIN_WINDOW_SIZE = 2; const int MAX_WINDOW_SIZE = 512; - const double RTT_EWMA_ALPHA = 0.25; - const double SLOWRTT_EWMA_ALPHA = 0.125; + const double RTT_EWMA_ALPHA = 0.5; + const double SLOWRTT_EWMA_ALPHA = 0.05; const double PREV_SPEED_KEEP_TIME_COEFF = 0.35; // 0.1 - 1 // how long will the window size stay around the previous drop level, less is longer const int MIN_RTO = 20; // in milliseconds const int INITIAL_RTT = 8000; // in milliseconds @@ -72,6 +72,7 @@ namespace stream const uint64_t SEND_INTERVAL = 1000; // in microseconds const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL = 7500; // in milliseconds const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL_VARIANCE = 3200; // in milliseconds + const bool LOSS_BASED_CONTROL_ENABLED = 1; // 0/1 struct Packet { @@ -282,7 +283,7 @@ namespace stream uint16_t m_Port; SendBufferQueue m_SendBuffer; - double m_RTT, m_SlowRTT; + double m_RTT, m_SlowRTT, m_SlowRTT2; float m_WindowSize, m_LastWindowDropSize, m_WindowDropTargetSize; int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; double m_Jitter; From ebec4d8a5ea6ec425aec38b71707035a5a7d213e Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Sep 2024 18:56:23 -0400 Subject: [PATCH 094/527] set default i2cp.leaseSetEncType to 0,4 and to 4 for server tunnels --- libi2pd/Destination.cpp | 14 +++++--------- libi2pd/Destination.h | 2 +- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 9285b05d..05c4be00 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1013,18 +1013,15 @@ namespace client } } // if no param or valid crypto type use from identity - bool isSingleKey = false; if (encryptionKeyTypes.empty ()) - { - isSingleKey = true; - encryptionKeyTypes.insert (GetIdentity ()->GetCryptoKeyType ()); - } + encryptionKeyTypes.insert ( { GetIdentity ()->GetCryptoKeyType (), + i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD }); // usually 0,4 for (auto& it: encryptionKeyTypes) { auto encryptionKey = new EncryptionKey (it); if (IsPublic ()) - PersistTemporaryKeys (encryptionKey, isSingleKey); + PersistTemporaryKeys (encryptionKey); else encryptionKey->GenerateKeys (); encryptionKey->CreateDecryptor (); @@ -1383,12 +1380,11 @@ namespace client return ret; } - void ClientDestination::PersistTemporaryKeys (EncryptionKey * keys, bool isSingleKey) + void ClientDestination::PersistTemporaryKeys (EncryptionKey * keys) { if (!keys) return; std::string ident = GetIdentHash().ToBase32(); - std::string path = i2p::fs::DataDirPath("destinations", - isSingleKey ? (ident + ".dat") : (ident + "." + std::to_string (keys->keyType) + ".dat")); + std::string path = i2p::fs::DataDirPath("destinations", ident + "." + std::to_string (keys->keyType) + ".dat"); std::ifstream f(path, std::ifstream::binary); if (f) { diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 9dcc64c6..1cd004a4 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -289,7 +289,7 @@ namespace client std::shared_ptr GetSharedFromThis () { return std::static_pointer_cast(shared_from_this ()); } - void PersistTemporaryKeys (EncryptionKey * keys, bool isSingleKey); + void PersistTemporaryKeys (EncryptionKey * keys); void ReadAuthKey (const std::string& group, const std::map * params); template From d20475e3d0a16028ac6c5fb53615ab33940dd8aa Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Sep 2024 19:11:13 -0400 Subject: [PATCH 095/527] set default i2cp.leaseSetEncType to 0,4 and to 4 for server tunnels --- libi2pd_client/ClientContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 4f91c564..b8c4e335 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -475,7 +475,7 @@ namespace client options[I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED, DEFAULT_MAX_INBOUND_SPEED); options[I2CP_PARAM_STREAMING_ANSWER_PINGS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_ANSWER_PINGS, isServer ? DEFAULT_ANSWER_PINGS : false); options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE); - std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "0,4"); + std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, isServer ? "4" : "0,4"); if (encType.length () > 0) options[I2CP_PARAM_LEASESET_ENCRYPTION_TYPE] = encType; std::string privKey = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_PRIV_KEY, ""); if (privKey.length () > 0) options[I2CP_PARAM_LEASESET_PRIV_KEY] = privKey; From 17d0e59d02ed2c0880853243e35d624e95ebee18 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Sep 2024 20:30:26 -0400 Subject: [PATCH 096/527] fixed warning --- libi2pd/Streaming.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 5cabc36c..29b04069 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -497,7 +497,6 @@ namespace stream m_IsNAcked = false; m_IsResendNeeded = false; int nackCount = packet->GetNACKCount (); - int ackCount = 0; for (auto it = m_SentPackets.begin (); it != m_SentPackets.end ();) { auto seqn = (*it)->GetSeqn (); @@ -536,7 +535,6 @@ namespace stream m_SentPackets.erase (it++); m_LocalDestination.DeletePacket (sentPacket); acknowledged = true; - ackCount++; if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK) if (m_RTT < m_LocalDestination.GetRandom () % INITIAL_RTT) // dirty m_WindowIncCounter++; From d5aca85a35e1dea4771044866b88e0fcb3cd7a7b Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Sep 2024 21:03:46 -0400 Subject: [PATCH 097/527] don't try to generate more ECIES-X25519-AEAD-Ratchet tags if decryption failed --- libi2pd/Garlic.cpp | 35 ++--------------------------------- libi2pd/Garlic.h | 1 - 2 files changed, 2 insertions(+), 34 deletions(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index fb99ce6d..1705b03a 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -541,34 +541,7 @@ namespace garlic // otherwise ECIESx25519 auto session = std::make_shared (this, false); // incoming if (!session->HandleNextMessage (buf, length, nullptr, 0)) - { - // try to generate more tags for last tagset - if (m_LastTagset && (m_LastTagset->GetNextIndex () - m_LastTagset->GetTrimBehind () < 3*ECIESX25519_MAX_NUM_GENERATED_TAGS)) - { - uint64_t missingTag; memcpy (&missingTag, buf, 8); - auto maxTags = std::max (m_NumRatchetInboundTags, ECIESX25519_MAX_NUM_GENERATED_TAGS); - LogPrint (eLogWarning, "Garlic: Trying to generate more ECIES-X25519-AEAD-Ratchet tags"); - for (int i = 0; i < maxTags; i++) - { - auto nextTag = AddECIESx25519SessionNextTag (m_LastTagset); - if (!nextTag) - { - LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for last tagset"); - break; - } - if (nextTag == missingTag) - { - LogPrint (eLogDebug, "Garlic: Missing ECIES-X25519-AEAD-Ratchet tag was generated"); - if (m_LastTagset->HandleNextMessage (buf, length, m_ECIESx25519Tags[nextTag].index)) - found = true; - break; - } - } - if (!found) m_LastTagset = nullptr; - } - if (!found) - LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); - } + LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); } else LogPrint (eLogError, "Garlic: Failed to decrypt message"); @@ -583,9 +556,7 @@ 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)) - m_LastTagset = it->second.tagset; - else + if (!it->second.tagset || !it->second.tagset->HandleNextMessage (buf, len, it->second.index)) LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); m_ECIESx25519Tags.erase (it); return true; @@ -893,8 +864,6 @@ namespace garlic } if (numExpiredTags > 0) LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " ECIESx25519 tags expired for ", GetIdentHash().ToBase64 ()); - if (m_LastTagset && m_LastTagset->IsExpired (ts)) - m_LastTagset = nullptr; } void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID) diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index d1b97ade..a4475dc7 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -288,7 +288,6 @@ namespace garlic int m_NumRatchetInboundTags; std::unordered_map, std::hash > > m_Tags; std::unordered_map m_ECIESx25519Tags; // session tag -> session - ReceiveRatchetTagSetPtr m_LastTagset; // tagset last message came for // DeliveryStatus std::mutex m_DeliveryStatusSessionsMutex; std::unordered_map m_DeliveryStatusSessions; // msgID -> session From d4c1a1c0bbe26682415427047657857abc31b0d1 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 16 Sep 2024 13:39:11 -0400 Subject: [PATCH 098/527] cleanup streaming destination's pools --- libi2pd/Streaming.cpp | 7 +++++-- libi2pd/Streaming.h | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 29b04069..ca3c431a 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1526,7 +1526,8 @@ namespace stream StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort, bool gzip): m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), - m_PendingIncomingTimer (m_Owner->GetService ()) + m_PendingIncomingTimer (m_Owner->GetService ()), + m_LastCleanupTime (i2p::util::GetSecondsSinceEpoch ()) { } @@ -1715,10 +1716,12 @@ namespace stream m_IncomingStreams.erase (stream->GetSendStreamID ()); if (m_LastStream == stream) m_LastStream = nullptr; } - if (m_Streams.empty ()) + auto ts = i2p::util::GetSecondsSinceEpoch (); + if (m_Streams.empty () || ts > m_LastCleanupTime + STREAMING_DESTINATION_POOLS_CLEANUP_INTERVAL) { m_PacketsPool.CleanUp (); m_I2NPMsgsPool.CleanUp (); + m_LastCleanupTime = ts; } } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 63fe2033..4d246453 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -73,6 +73,7 @@ namespace stream const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL = 7500; // in milliseconds const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL_VARIANCE = 3200; // in milliseconds const bool LOSS_BASED_CONTROL_ENABLED = 1; // 0/1 + const uint64_t STREAMING_DESTINATION_POOLS_CLEANUP_INTERVAL = 646; // in seconds struct Packet { @@ -350,7 +351,8 @@ namespace stream i2p::util::MemoryPool m_PacketsPool; i2p::util::MemoryPool > m_I2NPMsgsPool; - + uint64_t m_LastCleanupTime; // in seconds + public: i2p::data::GzipInflator m_Inflator; From 13b2fc326686372c47113553e93ce7e6511f8375 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 16 Sep 2024 19:09:18 -0400 Subject: [PATCH 099/527] drop window size only when lease changes --- libi2pd/Streaming.cpp | 40 +++++++++++++++++++++++++++------------- libi2pd/Streaming.h | 2 +- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index ca3c431a..75dce5fa 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -835,7 +835,15 @@ namespace stream numPackets = (passedTime + m_PacketACKIntervalRem) / m_PacketACKInterval; m_PacketACKIntervalRem = (passedTime + m_PacketACKIntervalRem) - (numPackets * m_PacketACKInterval); if (m_LastConfirmedReceivedSequenceNumber + numPackets < m_LastReceivedSequenceNumber) + { lastReceivedSeqn = m_LastConfirmedReceivedSequenceNumber + numPackets; + if (!m_IsAckSendScheduled) + { + auto ackTimeout = m_RTT/10; + if (ackTimeout > m_AckDelay) ackTimeout = m_AckDelay; + ScheduleAck (ackTimeout); + } + } if (numPackets == 0) return; // for limit inbound speed if (!m_SavedPackets.empty ()) @@ -1396,6 +1404,7 @@ namespace stream void Stream::UpdateCurrentRemoteLease (bool expired) { + bool isLeaseChanged = true; if (!m_RemoteLeaseSet || m_RemoteLeaseSet->IsExpired ()) { auto remoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ()); @@ -1451,7 +1460,7 @@ namespace stream break; } } - if (!updated) + if (!updated && leases.size () > 1) { uint32_t i = m_LocalDestination.GetRandom () % leases.size (); if (m_CurrentRemoteLease && leases[i]->tunnelID == m_CurrentRemoteLease->tunnelID) @@ -1459,6 +1468,8 @@ namespace stream i = (i + 1) % leases.size (); // if so, pick next m_CurrentRemoteLease = leases[i]; } + else + isLeaseChanged = false; } else { @@ -1473,20 +1484,23 @@ namespace stream LogPrint (eLogWarning, "Streaming: Remote LeaseSet not found"); m_CurrentRemoteLease = nullptr; } - // drop window to initial upon RemoteLease change - m_RTO = INITIAL_RTO; - if (m_WindowSize > INITIAL_WINDOW_SIZE) + if (isLeaseChanged) { - m_WindowDropTargetSize = std::max (m_WindowSize/2, (float)INITIAL_WINDOW_SIZE); - m_IsWinDropped = true; + // drop window to initial upon RemoteLease change + m_RTO = INITIAL_RTO; + if (m_WindowSize > INITIAL_WINDOW_SIZE) + { + m_WindowDropTargetSize = std::max (m_WindowSize/2, (float)INITIAL_WINDOW_SIZE); + m_IsWinDropped = true; + } + else + m_WindowSize = INITIAL_WINDOW_SIZE; + m_LastWindowDropSize = 0; + m_WindowIncCounter = 0; + m_IsFirstRttSample = true; + m_IsFirstACK = true; + UpdatePacingTime (); } - else - m_WindowSize = INITIAL_WINDOW_SIZE; - m_LastWindowDropSize = 0; - m_WindowIncCounter = 0; - m_IsFirstRttSample = true; - m_IsFirstACK = true; - UpdatePacingTime (); } void Stream::ResetRoutingPath () diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 4d246453..9ac84990 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -56,7 +56,7 @@ namespace stream const int INITIAL_WINDOW_SIZE = 10; const int MIN_WINDOW_SIZE = 2; const int MAX_WINDOW_SIZE = 512; - const double RTT_EWMA_ALPHA = 0.5; + const double RTT_EWMA_ALPHA = 0.25; const double SLOWRTT_EWMA_ALPHA = 0.05; const double PREV_SPEED_KEEP_TIME_COEFF = 0.35; // 0.1 - 1 // how long will the window size stay around the previous drop level, less is longer const int MIN_RTO = 20; // in milliseconds From ca4db7aab21057aab8d3fd2e023420c9d4809bb2 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 17 Sep 2024 20:56:00 -0400 Subject: [PATCH 100/527] handle siuatuion if only one lease in remote LeaseSet --- libi2pd/Streaming.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 75dce5fa..08347623 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1460,16 +1460,19 @@ namespace stream break; } } - if (!updated && leases.size () > 1) + if (!updated) { uint32_t i = m_LocalDestination.GetRandom () % leases.size (); if (m_CurrentRemoteLease && leases[i]->tunnelID == m_CurrentRemoteLease->tunnelID) + { // make sure we don't select previous - i = (i + 1) % leases.size (); // if so, pick next + if (leases.size () > 1) + i = (i + 1) % leases.size (); // if so, pick next + else + isLeaseChanged = false; + } m_CurrentRemoteLease = leases[i]; } - else - isLeaseChanged = false; } else { From f20391d4600d41279e2b473470d98239ce7e52f4 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 17 Sep 2024 21:49:23 -0400 Subject: [PATCH 101/527] check if we connected recently to an endpoint before sending peer test --- libi2pd/SSU2.cpp | 24 ++++++++++++++++++++++++ libi2pd/SSU2.h | 8 ++++++-- libi2pd/SSU2Session.cpp | 28 +++++++++++++++------------- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index b86e3743..ebaeb741 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -210,6 +210,22 @@ namespace transport return ep.port (); } + bool SSU2Server::IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep) const + { + if (!ep.port () || ep.address ().is_unspecified ()) return false; + auto it = m_ConnectedRecently.find (ep); + if (it != m_ConnectedRecently.end ()) + return i2p::util::GetSecondsSinceEpoch () <= it->second + SSU2_HOLE_PUNCH_EXPIRATION; + return false; + } + + void SSU2Server::AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts) + { + if (!ep.port () || ep.address ().is_unspecified () || + i2p::util::GetSecondsSinceEpoch () > ts + SSU2_HOLE_PUNCH_EXPIRATION) return; + m_ConnectedRecently.try_emplace (ep, ts); + } + void SSU2Server::AdjustTimeOffset (int64_t offset, std::shared_ptr from) { if (offset) @@ -1001,6 +1017,14 @@ namespace transport it++; } + for (auto it = m_ConnectedRecently.begin (); it != m_ConnectedRecently.end (); ) + { + if (ts > it->second + SSU2_HOLE_PUNCH_EXPIRATION) + it = m_ConnectedRecently.erase (it); + else + it++; + } + m_PacketsPool.CleanUpMt (); m_SentPacketsPool.CleanUp (); m_IncompleteMessagesPool.CleanUp (); diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index fd071e8d..023f072e 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -39,6 +39,7 @@ namespace transport const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds + const int SSU2_HOLE_PUNCH_EXPIRATION = 20; // in seconds class SSU2Server: private i2p::util::RunnableServiceWithWork { @@ -72,6 +73,8 @@ namespace transport bool UsesProxy () const { return m_IsThroughProxy; }; bool IsSupported (const boost::asio::ip::address& addr) const; uint16_t GetPort (bool v4) const; + bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep) const; + void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts); std::mt19937& GetRng () { return m_Rng; } bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; } bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; @@ -160,7 +163,7 @@ namespace transport std::map > m_PendingOutgoingSessions; mutable std::mutex m_PendingOutgoingSessionsMutex; std::map > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds) - std::map > m_Relays; // we are introducer, relay tag -> session + std::unordered_map > m_Relays; // we are introducer, relay tag -> session std::list m_Introducers, m_IntroducersV6; // introducers we are connected to i2p::util::MemoryPoolMt m_PacketsPool; i2p::util::MemoryPool m_SentPacketsPool; @@ -174,7 +177,8 @@ namespace transport int64_t m_PendingTimeOffset; // during peer test std::shared_ptr m_PendingTimeOffsetFrom; std::mt19937 m_Rng; - + std::map m_ConnectedRecently; // endpoint -> last activity time in seconds + // proxy bool m_IsThroughProxy; uint8_t m_UDPRequestHeader[SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE]; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index eb662716..d98b06c3 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -265,6 +265,7 @@ namespace transport m_OnEstablished = nullptr; if (m_RelayTag) m_Server.RemoveRelay (m_RelayTag); + m_Server.AddConnectedRecently (m_RemoteEndpoint, GetLastActivityTimestamp ()); m_SentHandshakePacket.reset (nullptr); m_SessionConfirmedFragment.reset (nullptr); m_PathChallenge.reset (nullptr); @@ -281,14 +282,10 @@ namespace transport transports.PeerDisconnected (shared_from_this ()); auto remoteIdentity = GetRemoteIdentity (); if (remoteIdentity) - { LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), " (", i2p::data::GetIdentHashAbbreviation (remoteIdentity->GetIdentHash ()), ") terminated"); - } else - { LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), " terminated"); - } } } @@ -1153,7 +1150,7 @@ namespace transport if (profile) // older router? profile->Duplicated (); // mark router as duplicated in profile else - LogPrint (eLogError, "SSU2: Host mismatch between published address ", m_Address->host, + LogPrint (eLogInfo, "SSU2: Host mismatch between published address ", m_Address->host, " and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ())); return false; } @@ -2276,14 +2273,19 @@ namespace transport if (addr && m_Server.IsSupported (ep.address ()) && i2p::context.GetRouterInfo ().IsSSU2PeerTesting (ep.address ().is_v4 ())) { - // send msg 5 to Alice - auto session = std::make_shared (m_Server, r, addr); - session->SetState (eSSU2SessionStatePeerTest); - session->m_RemoteEndpoint = ep; // might be different - session->m_DestConnID = htobe64 (((uint64_t)nonce << 32) | nonce); - session->m_SourceConnID = ~session->m_DestConnID; - m_Server.AddSession (session); - session->SendPeerTest (5, newSignedData.data (), newSignedData.size (), addr->i); + if (!m_Server.IsConnectedRecently (ep)) // no alive hole punch + { + // send msg 5 to Alice + auto session = std::make_shared (m_Server, r, addr); + session->SetState (eSSU2SessionStatePeerTest); + session->m_RemoteEndpoint = ep; // might be different + session->m_DestConnID = htobe64 (((uint64_t)nonce << 32) | nonce); + session->m_SourceConnID = ~session->m_DestConnID; + m_Server.AddSession (session); + session->SendPeerTest (5, newSignedData.data (), newSignedData.size (), addr->i); + } + else + code = eSSU2PeerTestCodeCharlieAliceIsAlreadyConnected; } else code = eSSU2PeerTestCodeCharlieUnsupportedAddress; From a723405fb095d063b87a3889bad65f04c9b1b703 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Sep 2024 08:38:29 -0400 Subject: [PATCH 102/527] check max RouterInfo size --- libi2pd/NTCP2.cpp | 21 +++++++++++++-------- libi2pd/SSU2Session.cpp | 6 ++++-- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index a33d4fef..728ac01d 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -695,7 +695,7 @@ namespace transport return; } auto size = bufbe16toh (buf.data () + 1); - if (size > buf.size () - 3) + if (size > buf.size () - 3 || size > i2p::data::MAX_RI_BUFFER_SIZE + 1) { LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); Terminate (); @@ -960,14 +960,19 @@ namespace transport case eNTCP2BlkRouterInfo: { LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", (int)frame[offset]); - auto newRi = i2p::data::netdb.AddRouterInfo (frame + offset + 1, size - 1); - if (newRi) - { - auto remoteIdentity = GetRemoteIdentity (); - if (remoteIdentity && remoteIdentity->GetIdentHash () == newRi->GetIdentHash ()) - // peer's RouterInfo update - SetRemoteIdentity (newRi->GetIdentity ()); + if (size <= i2p::data::MAX_RI_BUFFER_SIZE + 1) + { + auto newRi = i2p::data::netdb.AddRouterInfo (frame + offset + 1, size - 1); + if (newRi) + { + auto remoteIdentity = GetRemoteIdentity (); + if (remoteIdentity && remoteIdentity->GetIdentHash () == newRi->GetIdentHash ()) + // peer's RouterInfo update + SetRemoteIdentity (newRi->GetIdentity ()); + } } + else + LogPrint (eLogInfo, "NTCP2: RouterInfo block is too long ", size); break; } case eNTCP2BlkI2NPMessage: diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index d98b06c3..192a2db2 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2937,13 +2937,15 @@ namespace transport i2p::data::GzipInflator inflator; uint8_t uncompressed[i2p::data::MAX_RI_BUFFER_SIZE]; size_t uncompressedSize = inflator.Inflate (buf + 2, size - 2, uncompressed, i2p::data::MAX_RI_BUFFER_SIZE); - if (uncompressedSize && uncompressedSize < i2p::data::MAX_RI_BUFFER_SIZE) + if (uncompressedSize && uncompressedSize <= i2p::data::MAX_RI_BUFFER_SIZE) ri = std::make_shared(uncompressed, uncompressedSize); else LogPrint (eLogInfo, "SSU2: RouterInfo decompression failed ", uncompressedSize); } - else + else if (size <= i2p::data::MAX_RI_BUFFER_SIZE + 2) ri = std::make_shared(buf + 2, size - 2); + else + LogPrint (eLogInfo, "SSU2: RouterInfo is too long ", size); return ri; } From ae267581707db1f51096dac2e393b4e44497492f Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Sep 2024 08:40:22 -0400 Subject: [PATCH 103/527] allocate RouterInfo's buffer from pool --- libi2pd/RouterInfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index b6abb48a..ce1ae72c 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -49,7 +49,7 @@ namespace data m_Caps (0), m_Version (0), m_Congestion (eLowCongestion) { m_Addresses = AddressesPtr(new Addresses ()); // create empty list - m_Buffer = NewBuffer (); // always RouterInfo's + m_Buffer = RouterInfo::NewBuffer (); // always RouterInfo's ReadFromFile (fullPath); } @@ -74,7 +74,7 @@ namespace data } RouterInfo::RouterInfo (const uint8_t * buf, size_t len): - RouterInfo (std::make_shared (buf, len), len) + RouterInfo (netdb.NewRouterInfoBuffer (buf, len), len) { } From 2fa4237acd2d2432294aeb4d6b2db77fa908c5f5 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Sep 2024 14:35:59 -0400 Subject: [PATCH 104/527] renew connected receintly timestamp, add endpoint to the list if hole punch is being sent --- libi2pd/SSU2.cpp | 13 ++++++++++--- libi2pd/SSU2.h | 4 ++-- libi2pd/SSU2Session.cpp | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index ebaeb741..94fc2dc3 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -210,12 +210,17 @@ namespace transport return ep.port (); } - bool SSU2Server::IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep) const + bool SSU2Server::IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep) { if (!ep.port () || ep.address ().is_unspecified ()) return false; auto it = m_ConnectedRecently.find (ep); if (it != m_ConnectedRecently.end ()) - return i2p::util::GetSecondsSinceEpoch () <= it->second + SSU2_HOLE_PUNCH_EXPIRATION; + { + if (i2p::util::GetSecondsSinceEpoch () <= it->second + SSU2_HOLE_PUNCH_EXPIRATION) + return true; + else + m_ConnectedRecently.erase (it); + } return false; } @@ -223,7 +228,9 @@ namespace transport { if (!ep.port () || ep.address ().is_unspecified () || i2p::util::GetSecondsSinceEpoch () > ts + SSU2_HOLE_PUNCH_EXPIRATION) return; - m_ConnectedRecently.try_emplace (ep, ts); + auto [it, added] = m_ConnectedRecently.try_emplace (ep, ts); + if (!added && ts > it->second) + it->second = ts; // renew timestamp of existing endpoint } void SSU2Server::AdjustTimeOffset (int64_t offset, std::shared_ptr from) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 023f072e..a650425e 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -39,7 +39,7 @@ namespace transport const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds - const int SSU2_HOLE_PUNCH_EXPIRATION = 20; // in seconds + const int SSU2_HOLE_PUNCH_EXPIRATION = 150; // in seconds class SSU2Server: private i2p::util::RunnableServiceWithWork { @@ -73,7 +73,7 @@ namespace transport bool UsesProxy () const { return m_IsThroughProxy; }; bool IsSupported (const boost::asio::ip::address& addr) const; uint16_t GetPort (bool v4) const; - bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep) const; + bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep); void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts); std::mt19937& GetRng () { return m_Rng; } bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; } diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 192a2db2..98b6c6f6 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2054,6 +2054,7 @@ namespace transport token = m_Server.GetIncomingToken (ep); isV4 = ep.address ().is_v4 (); SendHolePunch (bufbe32toh (buf + 33), ep, addr->i, token); + m_Server.AddConnectedRecently (ep, i2p::util::GetSecondsSinceEpoch ()); } else { From ac1c28cb39a3509d2f5e55b0e55aa8657b2d0487 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Sep 2024 15:19:18 -0400 Subject: [PATCH 105/527] don't send ack in case of lost packet and incoming speed limitation --- libi2pd/Streaming.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 08347623..c30c5d39 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -829,6 +829,7 @@ namespace stream // for limit inbound speed auto ts = i2p::util::GetMillisecondsSinceEpoch (); int numPackets = 0; + bool lostPackets = false; int64_t passedTime = m_PacketACKInterval * INITIAL_WINDOW_SIZE; // in microseconds // while m_LastACKSendTime == 0 if (m_LastACKSendTime) passedTime = (ts - m_LastACKSendTime)*1000; // in microseconds @@ -851,8 +852,26 @@ namespace stream for (auto it: m_SavedPackets) { auto seqn = it->GetSeqn (); - if (m_LastConfirmedReceivedSequenceNumber + numPackets < int(seqn)) break; // for limit inbound speed - if ((int)seqn > lastReceivedSeqn) lastReceivedSeqn = seqn; + // for limit inbound speed + if (m_LastConfirmedReceivedSequenceNumber + numPackets < int(seqn)) + { + if (!m_IsAckSendScheduled) + { + auto ackTimeout = m_RTT/10; + if (ackTimeout > m_AckDelay) ackTimeout = m_AckDelay; + ScheduleAck (ackTimeout); + } + if (lostPackets) + break; + else + return; + } + // for limit inbound speed + if ((int)seqn > lastReceivedSeqn) + { + lastReceivedSeqn = seqn; + lostPackets = true; // for limit inbound speed + } } } if (lastReceivedSeqn < 0) From db19c323819d8065dabd3a96d2192cead02710e1 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Sep 2024 15:42:30 -0400 Subject: [PATCH 106/527] require minimal boost 1.83 for c++20 --- build/CMakeLists.txt | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 19c51dfd..415a45da 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -125,6 +125,11 @@ if(WIN32) endif() +find_package(Boost REQUIRED COMPONENTS system filesystem program_options) +if(NOT DEFINED Boost_FOUND) + message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!") +endif() + if(WITH_UPNP) add_definitions(-DUSE_UPNP) endif() @@ -157,10 +162,12 @@ else() set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -ffunction-sections -fdata-sections") set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections") # -flto is added from above - # check for с++20 & c++17 support + # check for c++20 & c++17 support include(CheckCXXCompilerFlag) - CHECK_CXX_COMPILER_FLAG("-std=c++20" CXX20_SUPPORTED) + if(Boost_VERSION VERSION_GREATER_EQUAL "1.83") # min boost version for c++20 + CHECK_CXX_COMPILER_FLAG("-std=c++20" CXX20_SUPPORTED) + endif() CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED) @@ -285,11 +292,6 @@ else() endif() endif() -find_package(Boost REQUIRED COMPONENTS system filesystem program_options OPTIONAL_COMPONENTS atomic) -if(NOT DEFINED Boost_FOUND) - message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!") -endif() - find_package(OpenSSL REQUIRED) if(NOT DEFINED OPENSSL_FOUND) message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!") From 7ef1fdf6340ec252969e332874205b5b336956d1 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Sep 2024 18:48:18 -0400 Subject: [PATCH 107/527] exclude false position OK peer test if comes from recently connected endpoint --- libi2pd/SSU2Session.cpp | 10 ++++++---- libi2pd/SSU2Session.h | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 98b6c6f6..789b42e4 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2365,10 +2365,11 @@ namespace transport if (addr) { it->second.first->m_Address = addr; - if (it->second.first->m_State == eSSU2SessionStatePeerTestReceived) + auto state = it->second.first->m_State; + if (state == eSSU2SessionStatePeerTestReceived || state == eSSU2SessionStateVoidPeerTestReceived) { // msg 5 already received. send msg 6 - SetRouterStatus (eRouterStatusOK); + SetRouterStatus (state == eSSU2SessionStatePeerTestReceived ? eRouterStatusOK : eRouterStatusUnknown); it->second.first->m_State = eSSU2SessionStatePeerTest; it->second.first->SendPeerTest (6, buf + offset, len - offset, addr->i); } @@ -2426,14 +2427,15 @@ namespace transport case 5: // Alice from Charlie 1 if (htobe64 (((uint64_t)nonce << 32) | nonce) == m_SourceConnID) { + bool isConnectedRecently = m_Server.IsConnectedRecently (m_RemoteEndpoint); if (m_Address) { - SetRouterStatus (eRouterStatusOK); + SetRouterStatus (isConnectedRecently ? eRouterStatusUnknown : eRouterStatusOK); SendPeerTest (6, buf + offset, len - offset, m_Address->i); } else // we received msg 5 before msg 4 - m_State = eSSU2SessionStatePeerTestReceived; + m_State = isConnectedRecently ? eSSU2SessionStateVoidPeerTestReceived : eSSU2SessionStatePeerTestReceived; } else LogPrint (eLogWarning, "SSU2: Peer test 5 nonce mismatch ", nonce, " connID=", m_SourceConnID); diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index cd6793d3..eaeda949 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -114,6 +114,7 @@ namespace transport eSSU2SessionStateIntroduced, eSSU2SessionStatePeerTest, eSSU2SessionStatePeerTestReceived, // 5 before 4 + eSSU2SessionStateVoidPeerTestReceived, // 5 before 4, but from connected recently eSSU2SessionStateTokenRequestReceived }; From 715e063550f3e07751ae404d9b4a0243fe9431c0 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Sep 2024 08:02:37 -0400 Subject: [PATCH 108/527] set boost flags before finding --- build/CMakeLists.txt | 48 ++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 415a45da..534f8746 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -125,11 +125,6 @@ if(WIN32) endif() -find_package(Boost REQUIRED COMPONENTS system filesystem program_options) -if(NOT DEFINED Boost_FOUND) - message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!") -endif() - if(WITH_UPNP) add_definitions(-DUSE_UPNP) endif() @@ -161,23 +156,6 @@ else() endif() set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -ffunction-sections -fdata-sections") set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections") # -flto is added from above - - # check for c++20 & c++17 support - include(CheckCXXCompilerFlag) - - if(Boost_VERSION VERSION_GREATER_EQUAL "1.83") # min boost version for c++20 - CHECK_CXX_COMPILER_FLAG("-std=c++20" CXX20_SUPPORTED) - endif() - CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED) - - - if(CXX20_SUPPORTED) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20") - elseif(CXX17_SUPPORTED) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") - else() - message(SEND_ERROR "C++20 nor C++17 standard not seems to be supported by compiler. Too old version?") - endif() endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") @@ -292,6 +270,11 @@ else() endif() endif() +find_package(Boost REQUIRED COMPONENTS system filesystem program_options) +if(NOT DEFINED Boost_FOUND) + message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!") +endif() + find_package(OpenSSL REQUIRED) if(NOT DEFINED OPENSSL_FOUND) message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!") @@ -315,6 +298,26 @@ if(ZLIB_FOUND) link_directories(${ZLIB_ROOT}/lib) endif() +# C++ standard to use, based on compiler and version of boost +if(NOT MSVC) +# check for c++20 & c++17 support + include(CheckCXXCompilerFlag) + + if(Boost_VERSION VERSION_GREATER_EQUAL "1.83") # min boost version for c++20 + CHECK_CXX_COMPILER_FLAG("-std=c++20" CXX20_SUPPORTED) + endif() + CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED) + + + if(CXX20_SUPPORTED) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20") + elseif(CXX17_SUPPORTED) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") + else() + message(SEND_ERROR "C++20 nor C++17 standard not seems to be supported by compiler. Too old version?") + endif() +endif() + # load includes include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}) @@ -325,6 +328,7 @@ message(STATUS "Compiler vendor : ${CMAKE_CXX_COMPILER_ID}") message(STATUS "Compiler version : ${CMAKE_CXX_COMPILER_VERSION}") message(STATUS "Compiler path : ${CMAKE_CXX_COMPILER}") message(STATUS "Architecture : ${ARCHITECTURE}") +message(STATUS "Compiler flags : ${CMAKE_CXX_FLAGS}") message(STATUS "Install prefix: : ${CMAKE_INSTALL_PREFIX}") message(STATUS "Options:") message(STATUS " AESNI : ${WITH_AESNI}") From 5324197e4360b4fc462a466da0ed22aba5dc47cc Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Sep 2024 15:27:04 -0400 Subject: [PATCH 109/527] don't change router status if peer test came from recent endpoint --- libi2pd/SSU2Session.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 789b42e4..9c4345dc 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2365,12 +2365,13 @@ namespace transport if (addr) { it->second.first->m_Address = addr; - auto state = it->second.first->m_State; + auto& state = it->second.first->m_State; if (state == eSSU2SessionStatePeerTestReceived || state == eSSU2SessionStateVoidPeerTestReceived) { // msg 5 already received. send msg 6 - SetRouterStatus (state == eSSU2SessionStatePeerTestReceived ? eRouterStatusOK : eRouterStatusUnknown); - it->second.first->m_State = eSSU2SessionStatePeerTest; + if (state == eSSU2SessionStatePeerTestReceived) + SetRouterStatus (eRouterStatusOK); + state = eSSU2SessionStatePeerTest; it->second.first->SendPeerTest (6, buf + offset, len - offset, addr->i); } else @@ -2430,7 +2431,8 @@ namespace transport bool isConnectedRecently = m_Server.IsConnectedRecently (m_RemoteEndpoint); if (m_Address) { - SetRouterStatus (isConnectedRecently ? eRouterStatusUnknown : eRouterStatusOK); + if (!isConnectedRecently) + SetRouterStatus (eRouterStatusOK); SendPeerTest (6, buf + offset, len - offset, m_Address->i); } else From 9f30499984d8f854024fe751fadc284af8f74cec Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Sep 2024 21:16:16 -0400 Subject: [PATCH 110/527] implement i2p.streaming.profile to specify high or low bandwidth tunnel pools --- libi2pd/Destination.cpp | 8 ++++++-- libi2pd/Destination.h | 4 ++++ libi2pd/NetDb.cpp | 11 +++++++---- libi2pd/NetDb.hpp | 2 +- libi2pd/Tunnel.cpp | 14 ++++++++------ libi2pd/Tunnel.h | 5 +++-- libi2pd/TunnelPool.cpp | 18 ++++++++++-------- libi2pd/TunnelPool.h | 4 ++-- libi2pd_client/ClientContext.cpp | 3 +++ 9 files changed, 44 insertions(+), 25 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 05c4be00..28b23950 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -37,6 +37,7 @@ namespace client int inVar = DEFAULT_INBOUND_TUNNELS_LENGTH_VARIANCE; int outVar = DEFAULT_OUTBOUND_TUNNELS_LENGTH_VARIANCE; int numTags = DEFAULT_TAGS_TO_SEND; + bool isHighBandwidth = true; std::shared_ptr > explicitPeers; try { @@ -92,7 +93,7 @@ namespace client it = params->find (I2CP_PARAM_DONT_PUBLISH_LEASESET); if (it != params->end ()) { - // oveeride isPublic + // override isPublic m_IsPublic = (it->second != "true"); } it = params->find (I2CP_PARAM_LEASESET_TYPE); @@ -121,6 +122,9 @@ namespace client m_LeaseSetPrivKey.reset (nullptr); } } + it = params->find (I2CP_PARAM_STREAMING_PROFILE); + if (it != params->end ()) + isHighBandwidth = std::stoi (it->second) != STREAMING_PROFILE_INTERACTIVE; } } catch (std::exception & ex) @@ -128,7 +132,7 @@ namespace client LogPrint(eLogError, "Destination: Unable to parse parameters for destination: ", ex.what()); } SetNumTags (numTags); - m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty, inVar, outVar); + m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty, inVar, outVar, isHighBandwidth); if (explicitPeers) m_Pool->SetExplicitPeers (explicitPeers); if(params) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 1cd004a4..4a51a257 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -90,6 +90,10 @@ namespace client const int DEFAULT_MAX_INBOUND_SPEED = 1730000000; // no more than 1.73 Gbytes/s const char I2CP_PARAM_STREAMING_ANSWER_PINGS[] = "i2p.streaming.answerPings"; const int DEFAULT_ANSWER_PINGS = true; + const char I2CP_PARAM_STREAMING_PROFILE[] = "i2p.streaming.profile"; + const int STREAMING_PROFILE_BULK = 1; // high bandwidth + const int STREAMING_PROFILE_INTERACTIVE = 2; // low bandwidth + const int DEFAULT_STREAMING_PROFILE = STREAMING_PROFILE_BULK; typedef std::function stream)> StreamRequestComplete; diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 55e17b23..f6067ce3 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -69,7 +69,7 @@ namespace data { Reseed (); } - else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, false)) + else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, false, false)) Reseed (); // we don't have a router we can connect to. Trying to reseed auto it = m_RouterInfos.find (i2p::context.GetIdentHash ()); @@ -1130,15 +1130,18 @@ namespace data } std::shared_ptr NetDb::GetRandomRouter (std::shared_ptr compatibleWith, - bool reverse, bool endpoint) const + bool reverse, bool endpoint, bool clientTunnel) const { + bool checkIsReal = clientTunnel && i2p::tunnel::tunnels.GetPreciseTunnelCreationSuccessRate () < NETDB_TUNNEL_CREATION_RATE_THRESHOLD && // too low rate + context.GetUptime () > NETDB_CHECK_FOR_EXPIRATION_UPTIME; // after 10 minutes uptime return GetRandomRouter ( - [compatibleWith, reverse, endpoint](std::shared_ptr router)->bool + [compatibleWith, reverse, endpoint, clientTunnel, checkIsReal](std::shared_ptr router)->bool { return !router->IsHidden () && router != compatibleWith && (reverse ? (compatibleWith->IsReachableFrom (*router) && router->GetCompatibleTransports (true)): router->IsReachableFrom (*compatibleWith)) && !router->IsNAT2NATOnly (*compatibleWith) && - router->IsECIES () && !router->IsHighCongestion (false) && + router->IsECIES () && !router->IsHighCongestion (clientTunnel) && + (!checkIsReal || router->GetProfile ()->IsReal ()) && (!endpoint || (router->IsV4 () && (!reverse || router->IsPublished (true)))); // endpoint must be ipv4 and published if inbound(reverse) }); } diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 1797c04d..b84387de 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -87,7 +87,7 @@ namespace data void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr, bool direct = true); std::shared_ptr GetRandomRouter () const; - std::shared_ptr GetRandomRouter (std::shared_ptr compatibleWith, bool reverse, bool endpoint) const; + std::shared_ptr GetRandomRouter (std::shared_ptr compatibleWith, bool reverse, bool endpoint, bool clientTunnel) const; std::shared_ptr GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith, bool reverse, bool endpoint) const; std::shared_ptr GetRandomSSU2PeerTestRouter (bool v4, const std::unordered_set& excluded) const; std::shared_ptr GetRandomSSU2Introducer (bool v4, const std::unordered_set& excluded) const; diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 55c4d38c..1b63b7a7 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -411,10 +411,12 @@ namespace tunnel return tunnel; } - std::shared_ptr Tunnels::CreateTunnelPool (int numInboundHops, int numOutboundHops, - int numInboundTunnels, int numOutboundTunnels, int inboundVariance, int outboundVariance) + std::shared_ptr Tunnels::CreateTunnelPool (int numInboundHops, + int numOutboundHops, int numInboundTunnels, int numOutboundTunnels, + int inboundVariance, int outboundVariance, bool isHighBandwidth) { - auto pool = std::make_shared (numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels, inboundVariance, outboundVariance); + auto pool = std::make_shared (numInboundHops, numOutboundHops, + numInboundTunnels, numOutboundTunnels, inboundVariance, outboundVariance, isHighBandwidth); std::unique_lock l(m_PoolsMutex); m_Pools.push_back (pool); return pool; @@ -705,7 +707,7 @@ namespace tunnel auto inboundTunnel = GetNextInboundTunnel (); auto router = i2p::transport::transports.RoutesRestricted() ? i2p::transport::transports.GetRestrictedPeer() : - i2p::data::netdb.GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, true); // reachable by us + i2p::data::netdb.GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, true, false); // reachable by us if (!inboundTunnel || !router) return; LogPrint (eLogDebug, "Tunnel: Creating one hop outbound tunnel"); CreateTunnel ( @@ -765,7 +767,7 @@ namespace tunnel int obLen; i2p::config::GetOption("exploratory.outbound.length", obLen); int ibNum; i2p::config::GetOption("exploratory.inbound.quantity", ibNum); int obNum; i2p::config::GetOption("exploratory.outbound.quantity", obNum); - m_ExploratoryPool = CreateTunnelPool (ibLen, obLen, ibNum, obNum, 0, 0); + m_ExploratoryPool = CreateTunnelPool (ibLen, obLen, ibNum, obNum, 0, 0, false); m_ExploratoryPool->SetLocalDestination (i2p::context.GetSharedDestination ()); } return; @@ -777,7 +779,7 @@ namespace tunnel auto router = i2p::transport::transports.RoutesRestricted() ? i2p::transport::transports.GetRestrictedPeer() : // should be reachable by us because we send build request directly - i2p::data::netdb.GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, true); + i2p::data::netdb.GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, true, false); if (!router) { LogPrint (eLogWarning, "Tunnel: Can't find any router, skip creating tunnel"); return; diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index d3de272d..6b014af2 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -232,8 +232,9 @@ namespace tunnel void PostTunnelData (const std::vector >& msgs); void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr tunnel); void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr tunnel); - std::shared_ptr CreateTunnelPool (int numInboundHops, int numOuboundHops, - int numInboundTunnels, int numOutboundTunnels, int inboundVariance, int outboundVariance); + std::shared_ptr CreateTunnelPool (int numInboundHops, + int numOuboundHops, int numInboundTunnels, int numOutboundTunnels, + int inboundVariance, int outboundVariance, bool isHighBandwidth); void DeleteTunnelPool (std::shared_ptr pool); void StopTunnelPool (std::shared_ptr pool); diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 0a855350..e17932f9 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -41,11 +41,11 @@ namespace tunnel } TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, - int numOutboundTunnels, int inboundVariance, int outboundVariance): + int numOutboundTunnels, int inboundVariance, int outboundVariance, bool isHighBandwidth): 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_IsHighBandwidth (isHighBandwidth), m_CustomPeerSelector(nullptr), m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL) { if (m_NumInboundTunnels > TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY) @@ -549,20 +549,22 @@ namespace tunnel std::shared_ptr TunnelPool::SelectNextHop (std::shared_ptr prevHop, bool reverse, bool endpoint) const { - bool tryHighBandwidth = !IsExploratory (); + bool tryClient = !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); + hop = tryClient ? + (m_IsHighBandwidth ? + i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop, reverse, endpoint) : + i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint, true)): + i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint, false); if (hop) { if (!hop->GetProfile ()->IsBad ()) break; } - else if (tryHighBandwidth) - tryHighBandwidth = false; + else if (tryClient) + tryClient = false; else return nullptr; } diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index c19114e2..0ebfd1ac 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -62,7 +62,7 @@ namespace tunnel public: TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, - int numOutboundTunnels, int inboundVariance, int outboundVariance); + int numOutboundTunnels, int inboundVariance, int outboundVariance, bool isHighBandwidth); ~TunnelPool (); std::shared_ptr GetLocalDestination () const { return m_LocalDestination; }; @@ -146,7 +146,7 @@ namespace tunnel std::set, TunnelCreationTimeCmp> m_OutboundTunnels; mutable std::mutex m_TestsMutex; std::map, std::shared_ptr > > m_Tests; - bool m_IsActive; + bool m_IsActive, m_IsHighBandwidth; uint64_t m_NextManageTime; // in seconds std::mutex m_CustomPeerSelectorMutex; ITunnelPeerSelector * m_CustomPeerSelector; diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index b8c4e335..8cb4b67b 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -474,6 +474,7 @@ namespace client options[I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED, DEFAULT_MAX_OUTBOUND_SPEED); options[I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED, DEFAULT_MAX_INBOUND_SPEED); options[I2CP_PARAM_STREAMING_ANSWER_PINGS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_ANSWER_PINGS, isServer ? DEFAULT_ANSWER_PINGS : false); + options[I2CP_PARAM_STREAMING_PROFILE] = GetI2CPOption(section, I2CP_PARAM_STREAMING_PROFILE, DEFAULT_STREAMING_PROFILE); options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE); std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, isServer ? "4" : "0,4"); if (encType.length () > 0) options[I2CP_PARAM_LEASESET_ENCRYPTION_TYPE] = encType; @@ -519,6 +520,8 @@ namespace client options[I2CP_PARAM_LEASESET_ENCRYPTION_TYPE] = value; if (i2p::config::GetOption(prefix + I2CP_PARAM_LEASESET_PRIV_KEY, value) && !value.empty ()) options[I2CP_PARAM_LEASESET_PRIV_KEY] = value; + if (i2p::config::GetOption(prefix + I2CP_PARAM_STREAMING_PROFILE, value)) + options[I2CP_PARAM_STREAMING_PROFILE] = value; } void ClientContext::ReadTunnels () From e4962b855f14d1f0baa7a017fbd422c9ef9ca7e7 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 20 Sep 2024 10:34:55 -0400 Subject: [PATCH 111/527] pick first hop based on pool's bandwidth requirements --- libi2pd/TunnelPool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index e17932f9..5ac85d59 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -587,7 +587,7 @@ namespace tunnel else if (i2p::transport::transports.GetNumPeers () > 100 || (inbound && i2p::transport::transports.GetNumPeers () > 25)) { - auto r = i2p::transport::transports.GetRandomPeer (!IsExploratory ()); + auto r = i2p::transport::transports.GetRandomPeer (m_IsHighBandwidth); if (r && r->IsECIES () && !r->GetProfile ()->IsBad () && (numHops > 1 || (r->IsV4 () && (!inbound || r->IsPublished (true))))) // first inbound must be published ipv4 { From c8958d71a227d26a2736281790b03fe20627ce7f Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 21 Sep 2024 12:59:11 -0400 Subject: [PATCH 112/527] pick routers with any bandwidth if limited connectivity --- libi2pd/TunnelPool.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 5ac85d59..5af42373 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -549,12 +549,12 @@ namespace tunnel std::shared_ptr TunnelPool::SelectNextHop (std::shared_ptr prevHop, bool reverse, bool endpoint) const { - bool tryClient = !IsExploratory (); + bool tryClient = !IsExploratory () && !i2p::context.IsLimitedConnectivity (); std::shared_ptr hop; for (int i = 0; i < TUNNEL_POOL_MAX_HOP_SELECTION_ATTEMPTS; i++) { hop = tryClient ? - (m_IsHighBandwidth ? + (m_IsHighBandwidth ? i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop, reverse, endpoint) : i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint, true)): i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint, false); @@ -587,7 +587,7 @@ namespace tunnel else if (i2p::transport::transports.GetNumPeers () > 100 || (inbound && i2p::transport::transports.GetNumPeers () > 25)) { - auto r = i2p::transport::transports.GetRandomPeer (m_IsHighBandwidth); + auto r = i2p::transport::transports.GetRandomPeer (m_IsHighBandwidth && !i2p::context.IsLimitedConnectivity ()); if (r && r->IsECIES () && !r->GetProfile ()->IsBad () && (numHops > 1 || (r->IsV4 () && (!inbound || r->IsPublished (true))))) // first inbound must be published ipv4 { From fd2b15fe81a94d36e2019a08c7f52106fa925cb1 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 21 Sep 2024 17:58:14 -0400 Subject: [PATCH 113/527] don't drop too old router if low uptime --- libi2pd/NetDb.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index f6067ce3..24269015 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -295,7 +295,8 @@ namespace data { auto mts = i2p::util::GetMillisecondsSinceEpoch (); isValid = mts + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL > r->GetTimestamp () && // from future - mts < r->GetTimestamp () + NETDB_MAX_EXPIRATION_TIMEOUT*1000LL; // too old + (mts < r->GetTimestamp () + NETDB_MAX_EXPIRATION_TIMEOUT*1000LL || // too old + context.GetUptime () < NETDB_CHECK_FOR_EXPIRATION_UPTIME/10); // enough uptime } if (isValid) { From f733f0a63625ad5a234b7d3038f47aaaebf5116f Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 21 Sep 2024 19:04:03 -0400 Subject: [PATCH 114/527] added i2p.streaming.maxOutboundSpeed, i2p.streaming.maxInboundSpeed and i2p.streaming.profile to HTTP and SOCKS proxy configs --- libi2pd/Config.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index a3fe63c7..d644023c 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -120,6 +120,10 @@ namespace config { ("httpproxy.i2cp.leaseSetType", value()->default_value("3"), "Local destination's LeaseSet type") ("httpproxy.i2cp.leaseSetEncType", value()->default_value("0,4"), "Local destination's LeaseSet encryption type") ("httpproxy.i2cp.leaseSetPrivKey", value()->default_value(""), "LeaseSet private key") + ("httpproxy.i2p.streaming.maxOutboundSpeed", value()->default_value(1730000000), "Max outbound speed of HTTP proxy stream in bytes/sec") + ("httpproxy.i2p.streaming.maxInboundSpeed", value()->default_value(1730000000), "Max inbound speed of HTTP proxy stream in bytes/sec") + ("httpproxy.i2p.streaming.profile", value()->default_value(1), "HTTP Proxy bandwidth usage profile. 1 - bulk(high), 2- interactive(low)") + ; options_description socksproxy("SOCKS Proxy options"); @@ -144,6 +148,9 @@ namespace config { ("socksproxy.i2cp.leaseSetType", value()->default_value("3"), "Local destination's LeaseSet type") ("socksproxy.i2cp.leaseSetEncType", value()->default_value("0,4"), "Local destination's LeaseSet encryption type") ("socksproxy.i2cp.leaseSetPrivKey", value()->default_value(""), "LeaseSet private key") + ("socksproxy.i2p.streaming.maxOutboundSpeed", value()->default_value(1730000000), "Max outbound speed of SOCKS proxy stream in bytes/sec") + ("socksproxy.i2p.streaming.maxInboundSpeed", value()->default_value(1730000000), "Max inbound speed of SOCKS proxy stream in bytes/sec") + ("socksproxy.i2p.streaming.profile", value()->default_value(1), "SOCKS Proxy bandwidth usage profile. 1 - bulk(high), 2- interactive(low)") ; options_description sam("SAM bridge options"); From 018fa0ec00b1c79adc270b8b8ceb236d66dd1608 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 21 Sep 2024 19:48:45 -0400 Subject: [PATCH 115/527] added i2p.streaming.maxOutboundSpeed, i2p.streaming.maxInboundSpeed and i2p.streaming.profile to HTTP and SOCKS proxy configs --- libi2pd/Config.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index d644023c..4efcb16e 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -120,9 +120,9 @@ namespace config { ("httpproxy.i2cp.leaseSetType", value()->default_value("3"), "Local destination's LeaseSet type") ("httpproxy.i2cp.leaseSetEncType", value()->default_value("0,4"), "Local destination's LeaseSet encryption type") ("httpproxy.i2cp.leaseSetPrivKey", value()->default_value(""), "LeaseSet private key") - ("httpproxy.i2p.streaming.maxOutboundSpeed", value()->default_value(1730000000), "Max outbound speed of HTTP proxy stream in bytes/sec") - ("httpproxy.i2p.streaming.maxInboundSpeed", value()->default_value(1730000000), "Max inbound speed of HTTP proxy stream in bytes/sec") - ("httpproxy.i2p.streaming.profile", value()->default_value(1), "HTTP Proxy bandwidth usage profile. 1 - bulk(high), 2- interactive(low)") + ("httpproxy.i2p.streaming.maxOutboundSpeed", value()->default_value("1730000000"), "Max outbound speed of HTTP proxy stream in bytes/sec") + ("httpproxy.i2p.streaming.maxInboundSpeed", value()->default_value("1730000000"), "Max inbound speed of HTTP proxy stream in bytes/sec") + ("httpproxy.i2p.streaming.profile", value()->default_value("1"), "HTTP Proxy bandwidth usage profile. 1 - bulk(high), 2- interactive(low)") ; @@ -148,9 +148,9 @@ namespace config { ("socksproxy.i2cp.leaseSetType", value()->default_value("3"), "Local destination's LeaseSet type") ("socksproxy.i2cp.leaseSetEncType", value()->default_value("0,4"), "Local destination's LeaseSet encryption type") ("socksproxy.i2cp.leaseSetPrivKey", value()->default_value(""), "LeaseSet private key") - ("socksproxy.i2p.streaming.maxOutboundSpeed", value()->default_value(1730000000), "Max outbound speed of SOCKS proxy stream in bytes/sec") - ("socksproxy.i2p.streaming.maxInboundSpeed", value()->default_value(1730000000), "Max inbound speed of SOCKS proxy stream in bytes/sec") - ("socksproxy.i2p.streaming.profile", value()->default_value(1), "SOCKS Proxy bandwidth usage profile. 1 - bulk(high), 2- interactive(low)") + ("socksproxy.i2p.streaming.maxOutboundSpeed", value()->default_value("1730000000"), "Max outbound speed of SOCKS proxy stream in bytes/sec") + ("socksproxy.i2p.streaming.maxInboundSpeed", value()->default_value("1730000000"), "Max inbound speed of SOCKS proxy stream in bytes/sec") + ("socksproxy.i2p.streaming.profile", value()->default_value("1"), "SOCKS Proxy bandwidth usage profile. 1 - bulk(high), 2- interactive(low)") ; options_description sam("SAM bridge options"); From 9d1e5268125f91b20a6a741be1fc8cbf024f3d0b Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 22 Sep 2024 17:22:08 -0400 Subject: [PATCH 116/527] separate SSU2PeerTestSession for peer tests msgs 5,6 and 7 --- libi2pd/SSU2Session.cpp | 107 ++++++++++++++++++++++------------------ libi2pd/SSU2Session.h | 79 ++++++++++++++++++----------- 2 files changed, 111 insertions(+), 75 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 9c4345dc..53ed899a 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -18,6 +18,12 @@ namespace i2p { namespace transport { + static inline void CreateNonce (uint64_t seqn, uint8_t * nonce) + { + memset (nonce, 0, 4); + htole64buf (nonce + 4, seqn); + } + void SSU2IncompleteMessage::AttachNextFragment (const uint8_t * fragment, size_t fragmentSize) { if (msg->len + fragmentSize > msg->maxLen) @@ -227,11 +233,9 @@ namespace transport RAND_bytes ((uint8_t *)&nonce, 4); auto ts = i2p::util::GetMillisecondsSinceEpoch (); // session for message 5 - auto session = std::make_shared (m_Server); - session->SetState (eSSU2SessionStatePeerTest); + auto session = std::make_shared (m_Server, + htobe64 (((uint64_t)nonce << 32) | nonce), 0, shared_from_this ()); m_PeerTests.emplace (nonce, std::make_pair (session, ts/1000)); - session->m_SourceConnID = htobe64 (((uint64_t)nonce << 32) | nonce); - session->m_DestConnID = ~session->m_SourceConnID; m_Server.AddSession (session); // peer test block auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); @@ -1456,39 +1460,8 @@ namespace transport bool SSU2Session::ProcessPeerTest (uint8_t * buf, size_t len) { - // we are Alice or Charlie - Header header; - memcpy (header.buf, buf, 16); - header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 24)); - header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12)); - if (header.h.type != eSSU2PeerTest) - { - LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2PeerTest); - return false; - } - if (len < 48) - { - LogPrint (eLogWarning, "SSU2: PeerTest message too short ", len); - return false; - } - uint8_t nonce[12] = {0}; - uint64_t headerX[2]; // sourceConnID, token - i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); - m_DestConnID = headerX[0]; - // decrypt and handle payload - uint8_t * payload = buf + 32; - CreateNonce (be32toh (header.h.packetNum), nonce); - uint8_t h[32]; - memcpy (h, header.buf, 16); - memcpy (h + 16, &headerX, 16); - if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32, - i2p::context.GetSSU2IntroKey (), nonce, payload, len - 48, false)) - { - LogPrint (eLogWarning, "SSU2: PeerTest AEAD verification failed "); - return false; - } - HandlePayload (payload, len - 48); - return true; + LogPrint (eLogWarning, "SSU2: Unexpected peer test message for this session type"); + return false; } uint32_t SSU2Session::SendData (const uint8_t * buf, size_t len, uint8_t flags) @@ -2277,11 +2250,10 @@ namespace transport if (!m_Server.IsConnectedRecently (ep)) // no alive hole punch { // send msg 5 to Alice - auto session = std::make_shared (m_Server, r, addr); - session->SetState (eSSU2SessionStatePeerTest); + auto session = std::make_shared (m_Server, + 0, htobe64 (((uint64_t)nonce << 32) | nonce), shared_from_this ()); + session->m_Address = addr; session->m_RemoteEndpoint = ep; // might be different - session->m_DestConnID = htobe64 (((uint64_t)nonce << 32) | nonce); - session->m_SourceConnID = ~session->m_DestConnID; m_Server.AddSession (session); session->SendPeerTest (5, newSignedData.data (), newSignedData.size (), addr->i); } @@ -2954,12 +2926,6 @@ namespace transport return ri; } - void SSU2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) - { - memset (nonce, 0, 4); - htole64buf (nonce + 4, seqn); - } - bool SSU2Session::UpdateReceivePacketNum (uint32_t packetNum) { if (packetNum <= m_ReceivePacketNum) return false; // duplicate @@ -3148,5 +3114,52 @@ namespace transport Resend (i2p::util::GetMillisecondsSinceEpoch ()); // than right time to resend } + SSU2PeerTestSession::SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, + uint64_t destConnID, std::shared_ptr mainSession): SSU2Session (server), + m_MainSession (mainSession) + { + if (!sourceConnID) sourceConnID = ~destConnID; + if (!destConnID) destConnID = ~sourceConnID; + SetSourceConnID (sourceConnID); + SetDestConnID (destConnID); + SetState (eSSU2SessionStatePeerTest); + } + + bool SSU2PeerTestSession::ProcessPeerTest (uint8_t * buf, size_t len) + { + // we are Alice or Charlie, msgs 5,6,7 + Header header; + memcpy (header.buf, buf, 16); + header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 24)); + header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12)); + if (header.h.type != eSSU2PeerTest) + { + LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2PeerTest); + return false; + } + if (len < 48) + { + LogPrint (eLogWarning, "SSU2: PeerTest message too short ", len); + return false; + } + uint8_t nonce[12] = {0}; + uint64_t headerX[2]; // sourceConnID, token + i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); + SetDestConnID (headerX[0]); + // decrypt and handle payload + uint8_t * payload = buf + 32; + CreateNonce (be32toh (header.h.packetNum), nonce); + uint8_t h[32]; + memcpy (h, header.buf, 16); + memcpy (h + 16, &headerX, 16); + if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32, + i2p::context.GetSSU2IntroKey (), nonce, payload, len - 48, false)) + { + LogPrint (eLogWarning, "SSU2: PeerTest AEAD verification failed "); + return false; + } + HandlePayload (payload, len - 48); + return true; + } } } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index eaeda949..a247a9e6 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -207,36 +207,40 @@ namespace transport class SSU2Server; class SSU2Session: public TransportSession, public std::enable_shared_from_this { - union Header - { - uint64_t ll[2]; - uint8_t buf[16]; - struct + protected: + + union Header { - uint64_t connID; - uint32_t packetNum; - uint8_t type; - uint8_t flags[3]; - } h; - }; + uint64_t ll[2]; + uint8_t buf[16]; + struct + { + uint64_t connID; + uint32_t packetNum; + uint8_t type; + uint8_t flags[3]; + } h; + }; - struct HandshakePacket - { - Header header; - uint8_t headerX[48]; // part1 for SessionConfirmed - uint8_t payload[SSU2_MAX_PACKET_SIZE*2]; - size_t payloadSize = 0; - uint64_t sendTime = 0; // in milliseconds - bool isSecondFragment = false; // for SessionConfirmed - }; + private: + + struct HandshakePacket + { + Header header; + uint8_t headerX[48]; // part1 for SessionConfirmed + uint8_t payload[SSU2_MAX_PACKET_SIZE*2]; + size_t payloadSize = 0; + uint64_t sendTime = 0; // in milliseconds + bool isSecondFragment = false; // for SessionConfirmed + }; - typedef std::function OnEstablished; + typedef std::function OnEstablished; public: SSU2Session (SSU2Server& server, std::shared_ptr in_RemoteRouter = nullptr, std::shared_ptr addr = nullptr); - ~SSU2Session (); + virtual ~SSU2Session (); void SetRemoteEndpoint (const boost::asio::ip::udp::endpoint& ep) { m_RemoteEndpoint = ep; }; const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () const { return m_RemoteEndpoint; }; @@ -271,9 +275,16 @@ namespace transport bool ProcessSessionConfirmed (uint8_t * buf, size_t len); bool ProcessRetry (uint8_t * buf, size_t len); bool ProcessHolePunch (uint8_t * buf, size_t len); - bool ProcessPeerTest (uint8_t * buf, size_t len); + virtual bool ProcessPeerTest (uint8_t * buf, size_t len); void ProcessData (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from); + protected: + + void SetSourceConnID (uint64_t sourceConnID) { m_SourceConnID = sourceConnID; } + void SetDestConnID (uint64_t destConnID) { m_DestConnID = destConnID; } + + void HandlePayload (const uint8_t * buf, size_t len); + private: void Terminate (); @@ -303,7 +314,6 @@ namespace transport void SendPathResponse (const uint8_t * data, size_t len); void SendPathChallenge (); - void HandlePayload (const uint8_t * buf, size_t len); void HandleDateTime (const uint8_t * buf, size_t len); void HandleRouterInfo (const uint8_t * buf, size_t len); void HandleAck (const uint8_t * buf, size_t len); @@ -318,7 +328,6 @@ namespace transport bool GetTestingState () const; void SetTestingState(bool testing) const; std::shared_ptr ExtractRouterInfo (const uint8_t * buf, size_t size); - void CreateNonce (uint64_t seqn, uint8_t * nonce); bool UpdateReceivePacketNum (uint32_t packetNum); // for Ack, returns false if duplicate void HandleFirstFragment (const uint8_t * buf, size_t len); void HandleFollowOnFragment (const uint8_t * buf, size_t len); @@ -341,7 +350,7 @@ namespace transport size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice size_t CreateTerminationBlock (uint8_t * buf, size_t len); - + private: SSU2Server& m_Server; @@ -359,8 +368,8 @@ namespace transport std::set m_OutOfSequencePackets; // packet nums > receive packet num std::map > m_SentPackets; // packetNum -> packet std::unordered_map > m_IncompleteMessages; // msgID -> I2NP - std::map, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice - std::map, uint64_t > > m_PeerTests; // same as for relay sessions + std::unordered_map, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice + std::unordered_map, uint64_t > > m_PeerTests; // same as for relay sessions std::list > m_SendQueue; i2p::I2NPMessagesHandler m_Handler; bool m_IsDataReceived; @@ -378,6 +387,20 @@ namespace transport uint64_t m_LastResendTime, m_LastResendAttemptTime; // in milliseconds }; + class SSU2PeerTestSession: public SSU2Session // for PeerTest msgs 5,6,7 + { + public: + + SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID, + std::shared_ptr mainSession); + + bool ProcessPeerTest (uint8_t * buf, size_t len) override; + + private: + + std::weak_ptr m_MainSession; + }; + inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) { uint64_t data = 0; From 11bca5c3cd91ca2504dd885eca54ac70b0c43f59 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 22 Sep 2024 18:02:12 -0400 Subject: [PATCH 117/527] don't initialize Noise state for peer test sessions --- libi2pd/SSU2Session.cpp | 14 +++++++++----- libi2pd/SSU2Session.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 53ed899a..399f5e71 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -85,7 +85,7 @@ namespace transport } SSU2Session::SSU2Session (SSU2Server& server, std::shared_ptr in_RemoteRouter, - std::shared_ptr addr): + std::shared_ptr addr, bool noise): TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT), m_Server (server), m_Address (addr), m_RemoteTransports (0), m_RemotePeerTestTransports (0), m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), @@ -99,11 +99,13 @@ namespace transport m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32), // min size m_LastResendTime (0), m_LastResendAttemptTime (0) { - m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState); + if (noise) + m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState); if (in_RemoteRouter && m_Address) { // outgoing - InitNoiseXKState1 (*m_NoiseState, m_Address->s); + if (noise) + InitNoiseXKState1 (*m_NoiseState, m_Address->s); m_RemoteEndpoint = boost::asio::ip::udp::endpoint (m_Address->host, m_Address->port); m_RemoteTransports = in_RemoteRouter->GetCompatibleTransports (false); if (in_RemoteRouter->IsSSU2PeerTesting (true)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V4; @@ -114,7 +116,8 @@ namespace transport else { // incoming - InitNoiseXKState1 (*m_NoiseState, i2p::context.GetSSU2StaticPublicKey ()); + if (noise) + InitNoiseXKState1 (*m_NoiseState, i2p::context.GetSSU2StaticPublicKey ()); } } @@ -3115,7 +3118,8 @@ namespace transport } SSU2PeerTestSession::SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, - uint64_t destConnID, std::shared_ptr mainSession): SSU2Session (server), + uint64_t destConnID, std::shared_ptr mainSession): + SSU2Session (server, nullptr, nullptr, false), m_MainSession (mainSession) { if (!sourceConnID) sourceConnID = ~destConnID; diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index a247a9e6..59e3e577 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -239,7 +239,7 @@ namespace transport public: SSU2Session (SSU2Server& server, std::shared_ptr in_RemoteRouter = nullptr, - std::shared_ptr addr = nullptr); + std::shared_ptr addr = nullptr, bool noise = true); virtual ~SSU2Session (); void SetRemoteEndpoint (const boost::asio::ip::udp::endpoint& ep) { m_RemoteEndpoint = ep; }; From 2c594dc67af1be7796aa0e8cf7b9e0ee8300dc25 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 22 Sep 2024 20:25:41 -0400 Subject: [PATCH 118/527] moved peer test 5-7 to SSU2PeerTestSession --- libi2pd/SSU2Session.cpp | 82 ++++++++++++++++++++++++++--------------- libi2pd/SSU2Session.h | 16 ++++++-- 2 files changed, 65 insertions(+), 33 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 399f5e71..7aa6af40 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2165,6 +2165,7 @@ namespace transport void SSU2Session::HandlePeerTest (const uint8_t * buf, size_t len) { + // msgs 1-4 if (len < 3) return; uint8_t msg = buf[0]; size_t offset = 3; // points to signed data @@ -2400,35 +2401,6 @@ namespace transport LogPrint (eLogWarning, "SSU2: Unknown peer test 4 nonce ", nonce); break; } - case 5: // Alice from Charlie 1 - if (htobe64 (((uint64_t)nonce << 32) | nonce) == m_SourceConnID) - { - bool isConnectedRecently = m_Server.IsConnectedRecently (m_RemoteEndpoint); - if (m_Address) - { - if (!isConnectedRecently) - SetRouterStatus (eRouterStatusOK); - SendPeerTest (6, buf + offset, len - offset, m_Address->i); - } - else - // we received msg 5 before msg 4 - m_State = isConnectedRecently ? eSSU2SessionStateVoidPeerTestReceived : eSSU2SessionStatePeerTestReceived; - } - else - LogPrint (eLogWarning, "SSU2: Peer test 5 nonce mismatch ", nonce, " connID=", m_SourceConnID); - break; - case 6: // Charlie from Alice - if (m_Address) - SendPeerTest (7, buf + offset, len - offset, m_Address->i); - else - LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6"); - m_Server.RemoveSession (~htobe64 (((uint64_t)nonce << 32) | nonce)); - break; - case 7: // Alice from Charlie 2 - if (m_Address->IsV6 ()) - i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2 - m_Server.RemoveSession (htobe64 (((uint64_t)nonce << 32) | nonce)); - break; default: LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", buf[0]); } @@ -3165,5 +3137,57 @@ namespace transport HandlePayload (payload, len - 48); return true; } + + void SSU2PeerTestSession::HandlePeerTest (const uint8_t * buf, size_t len) + { + // msgs 5-7 + if (len < 8) return; + uint8_t msg = buf[0]; + size_t offset = 3; // points to signed data after msg + code + flag + uint32_t nonce = bufbe32toh (buf + offset + 1); // 1 - ver + switch (msg) // msg + { + case 5: // Alice from Charlie 1 + { + if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ()) + { + bool isConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ()); + auto addr = GetAddress (); + if (addr) + { + if (!isConnectedRecently) + SetRouterStatus (eRouterStatusOK); + SendPeerTest (6, buf + offset, len - offset, addr->i); + } + else + // we received msg 5 before msg 4 + SetState (isConnectedRecently ? eSSU2SessionStateVoidPeerTestReceived : eSSU2SessionStatePeerTestReceived); + } + else + LogPrint (eLogWarning, "SSU2: Peer test 5 nonce mismatch ", nonce, " connID=", GetSourceConnID ()); + break; + } + case 6: // Charlie from Alice + { + auto addr = GetAddress (); + if (addr) + SendPeerTest (7, buf + offset, len - offset, addr->i); + else + LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6"); + GetServer ().RemoveSession (~htobe64 (((uint64_t)nonce << 32) | nonce)); + break; + } + case 7: // Alice from Charlie 2 + { + auto addr = GetAddress (); + if (addr && addr->IsV6 ()) + i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2 + GetServer ().RemoveSession (htobe64 (((uint64_t)nonce << 32) | nonce)); + break; + } + default: + LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", msg); + } + } } } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 59e3e577..5066f1a8 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -280,10 +280,17 @@ namespace transport protected: + SSU2Server& GetServer () { return m_Server; } + RouterStatus GetRouterStatus () const; + void SetRouterStatus (RouterStatus status) const; + + uint64_t GetSourceConnID () const { return m_SourceConnID; } void SetSourceConnID (uint64_t sourceConnID) { m_SourceConnID = sourceConnID; } + uint64_t GetDestConnID () const { return m_DestConnID; } void SetDestConnID (uint64_t destConnID) { m_DestConnID = destConnID; } void HandlePayload (const uint8_t * buf, size_t len); + void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message private: @@ -310,7 +317,6 @@ namespace transport void SendQuickAck (); void SendTermination (); void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey, uint64_t token); - void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message void SendPathResponse (const uint8_t * data, size_t len); void SendPathChallenge (); @@ -323,8 +329,6 @@ namespace transport size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); std::shared_ptr FindLocalAddress () const; void AdjustMaxPayloadSize (); - RouterStatus GetRouterStatus () const; - void SetRouterStatus (RouterStatus status) const; bool GetTestingState () const; void SetTestingState(bool testing) const; std::shared_ptr ExtractRouterInfo (const uint8_t * buf, size_t size); @@ -334,7 +338,7 @@ namespace transport void HandleRelayRequest (const uint8_t * buf, size_t len); void HandleRelayIntro (const uint8_t * buf, size_t len, int attempts = 0); void HandleRelayResponse (const uint8_t * buf, size_t len); - void HandlePeerTest (const uint8_t * buf, size_t len); + virtual void HandlePeerTest (const uint8_t * buf, size_t len); void HandleI2NPMsg (std::shared_ptr&& msg); size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); @@ -395,6 +399,10 @@ namespace transport std::shared_ptr mainSession); bool ProcessPeerTest (uint8_t * buf, size_t len) override; + + private: + + void HandlePeerTest (const uint8_t * buf, size_t len) override; private: From 5073c9637eebf0c3ec85177cf84c6d5ee28ab0d5 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 22 Sep 2024 21:07:44 -0400 Subject: [PATCH 119/527] implement httpproxy.senduseragent --- libi2pd/Config.cpp | 1 + libi2pd_client/ClientContext.cpp | 8 ++++++-- libi2pd_client/HTTPProxy.cpp | 15 +++++++++------ libi2pd_client/HTTPProxy.h | 12 +++++++----- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 4efcb16e..ab237613 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -117,6 +117,7 @@ namespace config { ("httpproxy.latency.max", value()->default_value("0"), "HTTP proxy max latency for tunnels") ("httpproxy.outproxy", value()->default_value(""), "HTTP proxy upstream out proxy url") ("httpproxy.addresshelper", value()->default_value(true), "Enable or disable addresshelper") + ("httpproxy.senduseragent", value()->default_value(false), "Pass through user's User-Agent if enabled. Disabled by deafult") ("httpproxy.i2cp.leaseSetType", value()->default_value("3"), "Local destination's LeaseSet type") ("httpproxy.i2cp.leaseSetEncType", value()->default_value("0,4"), "Local destination's LeaseSet encryption type") ("httpproxy.i2cp.leaseSetPrivKey", value()->default_value(""), "LeaseSet private key") diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 8cb4b67b..cf72d204 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -666,7 +666,9 @@ namespace client // http proxy std::string outproxy = section.second.get("outproxy", ""); bool addresshelper = section.second.get("addresshelper", true); - auto tun = std::make_shared(name, address, port, outproxy, addresshelper, localDestination); + bool senduseragent = section.second.get("senduseragent", false); + auto tun = std::make_shared(name, address, port, + outproxy, addresshelper, senduseragent, localDestination); clientTunnel = tun; clientEndpoint = tun->GetLocalEndpoint (); } @@ -882,6 +884,7 @@ namespace client uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort); std::string httpOutProxyURL; i2p::config::GetOption("httpproxy.outproxy", httpOutProxyURL); bool httpAddresshelper; i2p::config::GetOption("httpproxy.addresshelper", httpAddresshelper); + bool httpSendUserAgent; i2p::config::GetOption("httpproxy.senduseragent", httpSendUserAgent); if (httpAddresshelper) i2p::config::GetOption("addressbook.enabled", httpAddresshelper); // addresshelper is not supported without address book i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType); @@ -901,7 +904,8 @@ namespace client } try { - m_HttpProxy = new i2p::proxy::HTTPProxy("HTTP Proxy", httpProxyAddr, httpProxyPort, httpOutProxyURL, httpAddresshelper, localDestination); + m_HttpProxy = new i2p::proxy::HTTPProxy("HTTP Proxy", httpProxyAddr, httpProxyPort, + httpOutProxyURL, httpAddresshelper, httpSendUserAgent, localDestination); m_HttpProxy->Start(); } catch (std::exception& e) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 30a4e181..4f96f940 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -80,7 +80,7 @@ namespace proxy { void AsyncSockRead(); static bool ExtractAddressHelper(i2p::http::URL& url, std::string& jump, bool& confirm); static bool VerifyAddressHelper (std::string_view jump); - static void SanitizeHTTPRequest(i2p::http::HTTPReq& req); + void SanitizeHTTPRequest(i2p::http::HTTPReq& req); void SentHTTPFailed(const boost::system::error_code & ecode); void HandleStreamRequestComplete (std::shared_ptr stream); /* error helpers */ @@ -110,7 +110,7 @@ namespace proxy { std::shared_ptr m_proxysock; boost::asio::ip::tcp::resolver m_proxy_resolver; std::string m_OutproxyUrl, m_Response; - bool m_Addresshelper; + bool m_Addresshelper, m_SendUserAgent; i2p::http::URL m_ProxyURL; i2p::http::URL m_RequestURL; int m_req_len; @@ -126,7 +126,8 @@ namespace proxy { m_proxysock(std::make_shared(parent->GetService())), m_proxy_resolver(parent->GetService()), m_OutproxyUrl(parent->GetOutproxyURL()), - m_Addresshelper(parent->GetHelperSupport()) {} + m_Addresshelper(parent->GetHelperSupport()), + m_SendUserAgent (parent->GetSendUserAgent ()) {} ~HTTPReqHandler() { Terminate(); } void Handle () { AsyncSockRead(); } /* overload */ }; @@ -315,7 +316,8 @@ namespace proxy { req.RemoveHeader("X-Forwarded"); req.RemoveHeader("Proxy-"); // Proxy-* /* replace headers */ - req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)"); + if (!m_SendUserAgent) + req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)"); /** * i2pd PR #1816: @@ -751,9 +753,10 @@ namespace proxy { Done (shared_from_this()); } - HTTPProxy::HTTPProxy(const std::string& name, const std::string& address, uint16_t port, const std::string & outproxy, bool addresshelper, std::shared_ptr localDestination): + HTTPProxy::HTTPProxy(const std::string& name, const std::string& address, uint16_t port, + const std::string & outproxy, bool addresshelper, bool senduseragent, std::shared_ptr localDestination): TCPIPAcceptor (address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()), - m_Name (name), m_OutproxyUrl (outproxy), m_Addresshelper (addresshelper) + m_Name (name), m_OutproxyUrl (outproxy), m_Addresshelper (addresshelper), m_SendUserAgent (senduseragent) { } diff --git a/libi2pd_client/HTTPProxy.h b/libi2pd_client/HTTPProxy.h index d819a53c..507a87e2 100644 --- a/libi2pd_client/HTTPProxy.h +++ b/libi2pd_client/HTTPProxy.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 * @@ -15,13 +15,15 @@ namespace proxy { { public: - HTTPProxy(const std::string& name, const std::string& address, uint16_t port, const std::string & outproxy, bool addresshelper, std::shared_ptr localDestination); + HTTPProxy(const std::string& name, const std::string& address, uint16_t port, const std::string & outproxy, + bool addresshelper, bool senduseragent, std::shared_ptr localDestination); HTTPProxy(const std::string& name, const std::string& address, uint16_t port, std::shared_ptr localDestination = nullptr) : - HTTPProxy(name, address, port, "", true, localDestination) {} ; + HTTPProxy(name, address, port, "", true, false, localDestination) {} ; ~HTTPProxy() {}; std::string GetOutproxyURL() const { return m_OutproxyUrl; } - bool GetHelperSupport() { return m_Addresshelper; } + bool GetHelperSupport() const { return m_Addresshelper; } + bool GetSendUserAgent () const { return m_SendUserAgent; } protected: @@ -33,7 +35,7 @@ namespace proxy { std::string m_Name; std::string m_OutproxyUrl; - bool m_Addresshelper; + bool m_Addresshelper, m_SendUserAgent; }; } // http } // i2p From 9968afc03812a914f68f1452ad8a25db6bee7290 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 22 Sep 2024 21:27:09 -0400 Subject: [PATCH 120/527] check senduseragent for outproxy. Update User-Agent for clearnet --- libi2pd_client/HTTPProxy.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 4f96f940..dba65815 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -553,9 +553,9 @@ namespace proxy { std::string origURI = m_ClientRequest.uri; // TODO: what do we need to change uri for? m_ClientRequest.uri = m_ClientRequestURL.to_string(); - /* update User-Agent to ESR version of Firefox, same as Tor Browser below version 8, for non-HTTPS connections */ - if(m_ClientRequest.method != "CONNECT") - m_ClientRequest.UpdateHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:60.0) Gecko/20100101 Firefox/60.0"); + /* update User-Agent to ESR version of Firefox, same as Tor Browser below version 13, for non-HTTPS connections */ + if(m_ClientRequest.method != "CONNECT" && !m_SendUserAgent) + m_ClientRequest.UpdateHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0"); m_ClientRequest.write(m_ClientRequestBuffer); m_ClientRequestBuffer << m_recv_buf.substr(m_req_len); From 2dfc9003a73586c70a1f6fea148becc40a6e9275 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Sep 2024 14:16:24 -0400 Subject: [PATCH 121/527] separate and move own peer test to SSU2Server --- libi2pd/SSU2.cpp | 27 +++++++++++++++++++++++++ libi2pd/SSU2.h | 4 ++++ libi2pd/SSU2Session.cpp | 44 +++++++++++++++++++++-------------------- libi2pd/SSU2Session.h | 8 ++++---- 4 files changed, 58 insertions(+), 25 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 94fc2dc3..5e2533f4 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -154,6 +154,8 @@ namespace transport m_Relays.clear (); m_Introducers.clear (); m_IntroducersV6.clear (); + m_ConnectedRecently.clear (); + m_RequestedPeerTests.clear (); } void SSU2Server::SetLocalAddress (const boost::asio::ip::address& localAddress) @@ -572,6 +574,23 @@ namespace transport return nullptr; } + bool SSU2Server::AddRequestedPeerTest (uint32_t nonce, std::shared_ptr session, uint64_t ts) + { + return m_RequestedPeerTests.emplace (nonce, std::pair{ session, ts }).second; + } + + std::shared_ptr SSU2Server::GetRequestedPeerTest (uint32_t nonce) + { + auto it = m_RequestedPeerTests.find (nonce); + if (it != m_RequestedPeerTests.end ()) + { + auto s = it->second.first.lock (); + m_RequestedPeerTests.erase (it); + return s; + } + return nullptr; + } + void SSU2Server::ProcessNextPacket (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { if (len < 24) return; @@ -1031,6 +1050,14 @@ namespace transport else it++; } + + for (auto it = m_RequestedPeerTests.begin (); it != m_RequestedPeerTests.end ();) + { + if (ts > it->second.second + SSU2_PEER_TEST_EXPIRATION_TIMEOUT) + it = m_RequestedPeerTests.erase (it); + else + it++; + } m_PacketsPool.CleanUpMt (); m_SentPacketsPool.CleanUp (); diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index a650425e..913cc747 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -94,6 +94,9 @@ namespace transport void RemoveRelay (uint32_t tag); std::shared_ptr FindRelaySession (uint32_t tag); + bool AddRequestedPeerTest (uint32_t nonce, std::shared_ptr session, uint64_t ts); + std::shared_ptr GetRequestedPeerTest (uint32_t nonce); + void Send (const uint8_t * header, size_t headerLen, const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to); void Send (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, @@ -178,6 +181,7 @@ namespace transport std::shared_ptr m_PendingTimeOffsetFrom; std::mt19937 m_Rng; std::map m_ConnectedRecently; // endpoint -> last activity time in seconds + std::unordered_map, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp) // proxy bool m_IsThroughProxy; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 7aa6af40..307c82f2 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -237,8 +237,8 @@ namespace transport auto ts = i2p::util::GetMillisecondsSinceEpoch (); // session for message 5 auto session = std::make_shared (m_Server, - htobe64 (((uint64_t)nonce << 32) | nonce), 0, shared_from_this ()); - m_PeerTests.emplace (nonce, std::make_pair (session, ts/1000)); + htobe64 (((uint64_t)nonce << 32) | nonce), 0); + m_Server.AddRequestedPeerTest (nonce, session, ts/1000); m_Server.AddSession (session); // peer test block auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); @@ -2255,7 +2255,7 @@ namespace transport { // send msg 5 to Alice auto session = std::make_shared (m_Server, - 0, htobe64 (((uint64_t)nonce << 32) | nonce), shared_from_this ()); + 0, htobe64 (((uint64_t)nonce << 32) | nonce)); session->m_Address = addr; session->m_RemoteEndpoint = ep; // might be different m_Server.AddSession (session); @@ -2318,15 +2318,15 @@ namespace transport } case 4: // Alice from Bob { - auto it = m_PeerTests.find (nonce); - if (it != m_PeerTests.end ()) + auto session = m_Server.GetRequestedPeerTest (nonce); + if (session) { if (buf[1] == eSSU2PeerTestCodeAccept) { if (GetRouterStatus () == eRouterStatusUnknown) SetTestingState (true); auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie - if (r && it->second.first) + if (r) { uint8_t asz = buf[offset + 9]; SignedData s; @@ -2336,19 +2336,19 @@ namespace transport s.Insert (buf + offset, asz + 10); // ver, nonce, ts, asz, Alice's endpoint if (s.Verify (r->GetIdentity (), buf + offset + asz + 10)) { - it->second.first->SetRemoteIdentity (r->GetIdentity ()); + session->SetRemoteIdentity (r->GetIdentity ()); auto addr = r->GetSSU2Address (m_Address->IsV4 ()); if (addr) { - it->second.first->m_Address = addr; - auto& state = it->second.first->m_State; + session->m_Address = addr; + auto& state = session->m_State; if (state == eSSU2SessionStatePeerTestReceived || state == eSSU2SessionStateVoidPeerTestReceived) { // msg 5 already received. send msg 6 if (state == eSSU2SessionStatePeerTestReceived) SetRouterStatus (eRouterStatusOK); state = eSSU2SessionStatePeerTest; - it->second.first->SendPeerTest (6, buf + offset, len - offset, addr->i); + session->SendPeerTest (6, buf + offset, len - offset, addr->i); } else { @@ -2371,20 +2371,19 @@ namespace transport else { LogPrint (eLogWarning, "SSU2: Peer test 4 address not found"); - it->second.first->Done (); + session->Done (); } } else { LogPrint (eLogWarning, "SSU2: Peer test 4 signature verification failed"); - it->second.first->Done (); + session->Done (); } } else { LogPrint (eLogWarning, "SSU2: Peer test 4 router not found"); - if (it->second.first) - it->second.first->Done (); + session->Done (); } } else @@ -2393,9 +2392,8 @@ namespace transport i2p::data::GetIdentHashAbbreviation (buf[1] < 64 ? GetRemoteIdentity ()->GetIdentHash () : i2p::data::IdentHash (buf + 3))); if (GetTestingState ()) SetRouterStatus (eRouterStatusUnknown); - it->second.first->Done (); + session->Done (); } - m_PeerTests.erase (it); } else LogPrint (eLogWarning, "SSU2: Unknown peer test 4 nonce ", nonce); @@ -3089,10 +3087,8 @@ namespace transport Resend (i2p::util::GetMillisecondsSinceEpoch ()); // than right time to resend } - SSU2PeerTestSession::SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, - uint64_t destConnID, std::shared_ptr mainSession): - SSU2Session (server, nullptr, nullptr, false), - m_MainSession (mainSession) + SSU2PeerTestSession::SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID): + SSU2Session (server, nullptr, nullptr, false), m_MsgNumReceived (0) { if (!sourceConnID) sourceConnID = ~destConnID; if (!destConnID) destConnID = ~sourceConnID; @@ -3143,6 +3139,10 @@ namespace transport // msgs 5-7 if (len < 8) return; uint8_t msg = buf[0]; + if (msg < m_MsgNumReceived) + { + LogPrint (eLogInfo, "SSU2: PeerTest msg num ", msg, " received after ", m_MsgNumReceived, ". Ignored"); + } size_t offset = 3; // points to signed data after msg + code + flag uint32_t nonce = bufbe32toh (buf + offset + 1); // 1 - ver switch (msg) // msg @@ -3185,9 +3185,11 @@ namespace transport GetServer ().RemoveSession (htobe64 (((uint64_t)nonce << 32) | nonce)); break; } - default: + default: LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", msg); + return; } + m_MsgNumReceived = msg; } } } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 5066f1a8..13d0f262 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -395,18 +395,18 @@ namespace transport { public: - SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID, - std::shared_ptr mainSession); + SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID); + uint8_t GetMsgNumReceived () const { return m_MsgNumReceived; } bool ProcessPeerTest (uint8_t * buf, size_t len) override; private: void HandlePeerTest (const uint8_t * buf, size_t len) override; - + private: - std::weak_ptr m_MainSession; + uint8_t m_MsgNumReceived; }; inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) From 189d7179c0245242742e5481825a566ff14f738a Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Sep 2024 15:34:14 -0400 Subject: [PATCH 122/527] check if msg 5 was received instead state --- libi2pd/SSU2Session.cpp | 28 +++++++++++++++------------- libi2pd/SSU2Session.h | 6 +++--- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 307c82f2..2142ba0d 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2341,14 +2341,18 @@ namespace transport if (addr) { session->m_Address = addr; - auto& state = session->m_State; - if (state == eSSU2SessionStatePeerTestReceived || state == eSSU2SessionStateVoidPeerTestReceived) + if (session->GetMsgNumReceived () >= 5) { - // msg 5 already received. send msg 6 - if (state == eSSU2SessionStatePeerTestReceived) - SetRouterStatus (eRouterStatusOK); - state = eSSU2SessionStatePeerTest; - session->SendPeerTest (6, buf + offset, len - offset, addr->i); + // msg 5 already received + if (session->GetMsgNumReceived () == 5) + { + if (!session->IsConnectedRecently ()) + SetRouterStatus (eRouterStatusOK); + // send msg 6 + session->SendPeerTest (6, buf + offset, len - offset, addr->i); + } + else + LogPrint (eLogWarning, "SSU2: PeerTest 4 received, but msg ", session->GetMsgNumReceived (), " already received"); } else { @@ -3088,7 +3092,8 @@ namespace transport } SSU2PeerTestSession::SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID): - SSU2Session (server, nullptr, nullptr, false), m_MsgNumReceived (0) + SSU2Session (server, nullptr, nullptr, false), + m_MsgNumReceived (0), m_IsConnectedRecently (false) { if (!sourceConnID) sourceConnID = ~destConnID; if (!destConnID) destConnID = ~sourceConnID; @@ -3151,17 +3156,14 @@ namespace transport { if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ()) { - bool isConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ()); + m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ()); auto addr = GetAddress (); if (addr) { - if (!isConnectedRecently) + if (!m_IsConnectedRecently) SetRouterStatus (eRouterStatusOK); SendPeerTest (6, buf + offset, len - offset, addr->i); } - else - // we received msg 5 before msg 4 - SetState (isConnectedRecently ? eSSU2SessionStateVoidPeerTestReceived : eSSU2SessionStatePeerTestReceived); } else LogPrint (eLogWarning, "SSU2: Peer test 5 nonce mismatch ", nonce, " connID=", GetSourceConnID ()); diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 13d0f262..1449305a 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -113,8 +113,6 @@ namespace transport eSSU2SessionStateFailed, eSSU2SessionStateIntroduced, eSSU2SessionStatePeerTest, - eSSU2SessionStatePeerTestReceived, // 5 before 4 - eSSU2SessionStateVoidPeerTestReceived, // 5 before 4, but from connected recently eSSU2SessionStateTokenRequestReceived }; @@ -397,7 +395,8 @@ namespace transport SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID); - uint8_t GetMsgNumReceived () const { return m_MsgNumReceived; } + uint8_t GetMsgNumReceived () const { return m_MsgNumReceived; } + bool IsConnectedRecently () const { return m_IsConnectedRecently; } bool ProcessPeerTest (uint8_t * buf, size_t len) override; private: @@ -407,6 +406,7 @@ namespace transport private: uint8_t m_MsgNumReceived; + bool m_IsConnectedRecently; }; inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) From 816771dd00e6b6ffe2e0793ff3925b23b36962b3 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Sep 2024 18:18:26 -0400 Subject: [PATCH 123/527] fixed build for gcc 8-9 --- build/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 534f8746..954f5de9 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -209,6 +209,10 @@ if(WITH_THREADSANITIZER) endif() endif() +if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0 AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) # gcc 8-9 + list(APPEND CMAKE_REQUIRED_LIBRARIES "stdc++fs") +endif() + # Use std::atomic instead of GCC builtins on macOS PowerPC: # For more information refer to: https://github.com/PurpleI2P/i2pd/issues/1726#issuecomment-1306335111 # This has been fixed in Boost 1.81, nevertheless we retain the setting for the sake of compatibility. From 5cd02484946c7594ef349c7dc7243a58622cefec Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Sep 2024 20:24:33 -0400 Subject: [PATCH 124/527] set router status to uknown if peer test msg 5 came from recently connected peer --- libi2pd/SSU2Session.cpp | 5 ++++- libi2pd/SSU2Session.h | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 2142ba0d..2fde1092 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2362,6 +2362,7 @@ namespace transport if (GetRouterStatus () != eRouterStatusFirewalled && addr->IsPeerTesting ()) { SetRouterStatus (eRouterStatusFirewalled); + session->SetStatusChanged (); if (m_Address->IsV4 ()) m_Server.RescheduleIntroducersUpdateTimer (); else @@ -3093,7 +3094,7 @@ namespace transport SSU2PeerTestSession::SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID): SSU2Session (server, nullptr, nullptr, false), - m_MsgNumReceived (0), m_IsConnectedRecently (false) + m_MsgNumReceived (0), m_IsConnectedRecently (false), m_IsStatusChanged (false) { if (!sourceConnID) sourceConnID = ~destConnID; if (!destConnID) destConnID = ~sourceConnID; @@ -3162,6 +3163,8 @@ namespace transport { if (!m_IsConnectedRecently) SetRouterStatus (eRouterStatusOK); + else if (m_IsStatusChanged && GetRouterStatus () == eRouterStatusFirewalled) + SetRouterStatus (eRouterStatusUnknown); SendPeerTest (6, buf + offset, len - offset, addr->i); } } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 1449305a..71c73101 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -397,6 +397,7 @@ namespace transport uint8_t GetMsgNumReceived () const { return m_MsgNumReceived; } bool IsConnectedRecently () const { return m_IsConnectedRecently; } + void SetStatusChanged () { m_IsStatusChanged = true; } bool ProcessPeerTest (uint8_t * buf, size_t len) override; private: @@ -406,7 +407,7 @@ namespace transport private: uint8_t m_MsgNumReceived; - bool m_IsConnectedRecently; + bool m_IsConnectedRecently, m_IsStatusChanged; }; inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) From 74f0330730021d76b2a6c19d9662bf41f1ca01f3 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 24 Sep 2024 14:37:27 -0400 Subject: [PATCH 125/527] moved SendPeerTest for msgs 5,6,7 to SSU2PeerTestSession --- libi2pd/SSU2Session.cpp | 98 ++++++++++++++++++++++------------------- libi2pd/SSU2Session.h | 16 ++++--- 2 files changed, 63 insertions(+), 51 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 2fde1092..45dedc16 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1425,42 +1425,6 @@ namespace transport return true; } - void SSU2Session::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey) - { - Header header; - uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE]; - // fill packet - header.h.connID = m_DestConnID; // dest id - RAND_bytes (header.buf + 8, 4); // random packet num - header.h.type = eSSU2PeerTest; - header.h.flags[0] = 2; // ver - header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID - header.h.flags[2] = 0; // flag - memcpy (h, header.buf, 16); - memcpy (h + 16, &m_SourceConnID, 8); // source id - // payload - payload[0] = eSSU2BlkDateTime; - htobe16buf (payload + 1, 4); - htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); - size_t payloadSize = 7; - if (msg == 6 || msg == 7) - payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, m_RemoteEndpoint); - payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, - msg, eSSU2PeerTestCodeAccept, nullptr, signedData, signedDataLen); - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - // encrypt - uint8_t n[12]; - CreateNonce (be32toh (header.h.packetNum), n); - i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, introKey, n, payload, payloadSize + 16, true); - payloadSize += 16; - header.ll[0] ^= CreateHeaderMask (introKey, payload + (payloadSize - 24)); - header.ll[1] ^= CreateHeaderMask (introKey, payload + (payloadSize - 12)); - memset (n, 0, 12); - i2p::crypto::ChaCha20 (h + 16, 16, introKey, n, h + 16); - // send - m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint); - } - bool SSU2Session::ProcessPeerTest (uint8_t * buf, size_t len) { LogPrint (eLogWarning, "SSU2: Unexpected peer test message for this session type"); @@ -2256,10 +2220,9 @@ namespace transport // send msg 5 to Alice auto session = std::make_shared (m_Server, 0, htobe64 (((uint64_t)nonce << 32) | nonce)); - session->m_Address = addr; session->m_RemoteEndpoint = ep; // might be different m_Server.AddSession (session); - session->SendPeerTest (5, newSignedData.data (), newSignedData.size (), addr->i); + session->SendPeerTest (5, newSignedData.data (), newSignedData.size (), addr); } else code = eSSU2PeerTestCodeCharlieAliceIsAlreadyConnected; @@ -2340,7 +2303,6 @@ namespace transport auto addr = r->GetSSU2Address (m_Address->IsV4 ()); if (addr) { - session->m_Address = addr; if (session->GetMsgNumReceived () >= 5) { // msg 5 already received @@ -2349,7 +2311,7 @@ namespace transport if (!session->IsConnectedRecently ()) SetRouterStatus (eRouterStatusOK); // send msg 6 - session->SendPeerTest (6, buf + offset, len - offset, addr->i); + session->SendPeerTest (6, buf + offset, len - offset, addr); } else LogPrint (eLogWarning, "SSU2: PeerTest 4 received, but msg ", session->GetMsgNumReceived (), " already received"); @@ -3158,14 +3120,13 @@ namespace transport if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ()) { m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ()); - auto addr = GetAddress (); - if (addr) + if (GetAddress ()) { if (!m_IsConnectedRecently) SetRouterStatus (eRouterStatusOK); else if (m_IsStatusChanged && GetRouterStatus () == eRouterStatusFirewalled) SetRouterStatus (eRouterStatusUnknown); - SendPeerTest (6, buf + offset, len - offset, addr->i); + SendPeerTest (6, buf + offset, len - offset); } } else @@ -3174,9 +3135,8 @@ namespace transport } case 6: // Charlie from Alice { - auto addr = GetAddress (); - if (addr) - SendPeerTest (7, buf + offset, len - offset, addr->i); + if (GetAddress ()) + SendPeerTest (7, buf + offset, len - offset); else LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6"); GetServer ().RemoveSession (~htobe64 (((uint64_t)nonce << 32) | nonce)); @@ -3195,6 +3155,52 @@ namespace transport return; } m_MsgNumReceived = msg; + } + + void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen) + { + auto addr = GetAddress (); + if (!addr) return; + Header header; + uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE]; + // fill packet + header.h.connID = GetDestConnID (); // dest id + RAND_bytes (header.buf + 8, 4); // random packet num + header.h.type = eSSU2PeerTest; + header.h.flags[0] = 2; // ver + header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID + header.h.flags[2] = 0; // flag + memcpy (h, header.buf, 16); + htobuf64 (h + 16, GetSourceConnID ()); // source id + // payload + payload[0] = eSSU2BlkDateTime; + htobe16buf (payload + 1, 4); + htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); + size_t payloadSize = 7; + if (msg == 6 || msg == 7) + payloadSize += CreateAddressBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, GetRemoteEndpoint ()); + payloadSize += CreatePeerTestBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, + msg, eSSU2PeerTestCodeAccept, nullptr, signedData, signedDataLen); + payloadSize += CreatePaddingBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize); + // encrypt + uint8_t n[12]; + CreateNonce (be32toh (header.h.packetNum), n); + i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, addr->i, n, payload, payloadSize + 16, true); + payloadSize += 16; + header.ll[0] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 24)); + header.ll[1] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 12)); + memset (n, 0, 12); + i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16); + // send + GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ()); + } + + void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, + std::shared_ptr addr) + { + if (!addr) return; + SetAddress (addr); + SendPeerTest (msg, signedData, signedDataLen); } } } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 71c73101..eaf727cc 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -281,14 +281,19 @@ namespace transport SSU2Server& GetServer () { return m_Server; } RouterStatus GetRouterStatus () const; void SetRouterStatus (RouterStatus status) const; + size_t GetMaxPayloadSize () const { return m_MaxPayloadSize; } uint64_t GetSourceConnID () const { return m_SourceConnID; } void SetSourceConnID (uint64_t sourceConnID) { m_SourceConnID = sourceConnID; } uint64_t GetDestConnID () const { return m_DestConnID; } void SetDestConnID (uint64_t destConnID) { m_DestConnID = destConnID; } + void SetAddress (std::shared_ptr addr) { m_Address = addr; } void HandlePayload (const uint8_t * buf, size_t len); - void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message + + size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); + size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0); + size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); private: @@ -339,17 +344,14 @@ namespace transport virtual void HandlePeerTest (const uint8_t * buf, size_t len); void HandleI2NPMsg (std::shared_ptr&& msg); - size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr r); size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr riBuffer); size_t CreateAckBlock (uint8_t * buf, size_t len); - size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0); size_t CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr&& msg); size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg); size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg, uint8_t& fragmentNum, uint32_t msgID); size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen); size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4); - size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice size_t CreateTerminationBlock (uint8_t * buf, size_t len); @@ -398,12 +400,16 @@ namespace transport uint8_t GetMsgNumReceived () const { return m_MsgNumReceived; } bool IsConnectedRecently () const { return m_IsConnectedRecently; } void SetStatusChanged () { m_IsStatusChanged = true; } + + void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, + std::shared_ptr addr); bool ProcessPeerTest (uint8_t * buf, size_t len) override; private: + void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen); // PeerTest message void HandlePeerTest (const uint8_t * buf, size_t len) override; - + private: uint8_t m_MsgNumReceived; From edb2ba710732056a541767cbb5664e0b4d540852 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 24 Sep 2024 15:20:10 -0400 Subject: [PATCH 126/527] set address when peer test msg 4 received --- libi2pd/SSU2Session.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 45dedc16..7d5763a2 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2318,6 +2318,7 @@ namespace transport } else { + session->m_Address = addr; if (GetTestingState ()) { SetTestingState (false); From 0912de5b7703fe9b0fd7adf1d6a60976aa376fac Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 24 Sep 2024 20:03:15 -0400 Subject: [PATCH 127/527] don't connect peer test session. Use weak_ptr for seesions by hash --- libi2pd/SSU2.cpp | 84 +++++++++++++++++++++++------------------ libi2pd/SSU2.h | 2 +- libi2pd/SSU2Session.cpp | 15 +++++++- libi2pd/SSU2Session.h | 8 ++-- 4 files changed, 67 insertions(+), 42 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 5e2533f4..2005294b 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -450,7 +450,8 @@ namespace transport if (session) { m_Sessions.emplace (session->GetConnID (), session); - AddSessionByRouterHash (session); + if (session->GetState () != eSSU2SessionStatePeerTest) + AddSessionByRouterHash (session); } } @@ -459,13 +460,16 @@ namespace transport auto it = m_Sessions.find (connID); if (it != m_Sessions.end ()) { - auto ident = it->second->GetRemoteIdentity (); - if (ident) - { - auto it1 = m_SessionsByRouterHash.find (ident->GetIdentHash ()); - if (it1 != m_SessionsByRouterHash.end () && it->second == it1->second) - m_SessionsByRouterHash.erase (it1); - } + if (it->second->GetState () != eSSU2SessionStatePeerTest) + { + auto ident = it->second->GetRemoteIdentity (); + if (ident) + { + auto it1 = m_SessionsByRouterHash.find (ident->GetIdentHash ()); + if (it1 != m_SessionsByRouterHash.end () && it->second == it1->second.lock ()) + m_SessionsByRouterHash.erase (it1); + } + } if (m_LastSession == it->second) m_LastSession = nullptr; m_Sessions.erase (it); @@ -480,16 +484,20 @@ namespace transport if (ident) { auto ret = m_SessionsByRouterHash.emplace (ident->GetIdentHash (), session); - if (!ret.second && ret.first->second != session) + if (!ret.second) { - // session already exists - LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " already exists"); - // move unsent msgs to new session - ret.first->second->MoveSendQueue (session); - // terminate existing - GetService ().post (std::bind (&SSU2Session::RequestTermination, ret.first->second, eSSU2TerminationReasonReplacedByNewSession)); - // update session - ret.first->second = session; + auto oldSession = ret.first->second.lock (); + if (oldSession != session) + { + // session already exists + LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " already exists"); + // move unsent msgs to new session + oldSession->MoveSendQueue (session); + // terminate existing + GetService ().post (std::bind (&SSU2Session::RequestTermination, oldSession, eSSU2TerminationReasonReplacedByNewSession)); + // update session + ret.first->second = session; + } } } } @@ -506,7 +514,7 @@ namespace transport { auto it = m_SessionsByRouterHash.find (ident); if (it != m_SessionsByRouterHash.end ()) - return it->second; + return it->second.lock (); return nullptr; } @@ -761,11 +769,9 @@ namespace transport if (it != m_SessionsByRouterHash.end ()) { // session with router found, trying to send peer test if requested - if (peerTest && it->second->IsEstablished ()) - { - auto session = it->second; + auto session = it->second.lock (); + if (peerTest && session && session->IsEstablished ()) GetService ().post ([session]() { session->SendPeerTest (); }); - } return false; } // check is no pending session @@ -825,11 +831,15 @@ namespace transport auto it1 = m_SessionsByRouterHash.find (it.iH); if (it1 != m_SessionsByRouterHash.end ()) { - auto addr = it1->second->GetAddress (); - if (addr && addr->IsIntroducer ()) + auto s = it1->second.lock (); + if (s) { - it1->second->Introduce (session, it.iTag); - return; + auto addr = s->GetAddress (); + if (addr && addr->IsIntroducer ()) + { + s->Introduce (session, it.iTag); + return; + } } } else @@ -936,17 +946,19 @@ namespace transport if (!router) return false; auto addr = v4 ? router->GetSSU2V4Address () : router->GetSSU2V6Address (); if (!addr) return false; + std::shared_ptr session; auto it = m_SessionsByRouterHash.find (router->GetIdentHash ()); if (it != m_SessionsByRouterHash.end ()) + session = it->second.lock (); + if (session) { - auto remoteAddr = it->second->GetAddress (); + auto remoteAddr = session->GetAddress (); if (!remoteAddr || !remoteAddr->IsPeerTesting () || - (v4 && !remoteAddr->IsV4 ()) || (!v4 && !remoteAddr->IsV6 ())) return false; - auto s = it->second; - if (s->IsEstablished ()) - GetService ().post ([s]() { s->SendPeerTest (); }); + (v4 && !remoteAddr->IsV4 ()) || (!v4 && !remoteAddr->IsV6 ())) return false; + if (session->IsEstablished ()) + GetService ().post ([session]() { session->SendPeerTest (); }); else - s->SetOnEstablished ([s]() { s->SendPeerTest (); }); + session->SetOnEstablished ([session]() { session->SendPeerTest (); }); return true; } else @@ -997,7 +1009,7 @@ namespace transport for (auto it = m_SessionsByRouterHash.begin (); it != m_SessionsByRouterHash.begin ();) { - if (it->second && it->second->GetState () == eSSU2SessionStateTerminated) + if (it->second.expired ()) it = m_SessionsByRouterHash.erase (it); else it++; @@ -1183,7 +1195,7 @@ namespace transport auto it1 = m_SessionsByRouterHash.find (it); if (it1 != m_SessionsByRouterHash.end ()) { - session = it1->second; + session = it1->second.lock (); excluded.insert (it); } if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing () && // still session with introducer? @@ -1217,8 +1229,8 @@ namespace transport auto it1 = m_SessionsByRouterHash.find (it); if (it1 != m_SessionsByRouterHash.end ()) { - auto session = it1->second; - if (session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ()) + auto session = it1->second.lock (); + if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ()) { session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); if (std::find (newList.begin (), newList.end (), it) == newList.end ()) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 913cc747..54eca83f 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -162,7 +162,7 @@ namespace transport boost::asio::ip::udp::socket m_SocketV4, m_SocketV6; boost::asio::ip::address m_AddressV4, m_AddressV6; std::unordered_map > m_Sessions; - std::unordered_map > m_SessionsByRouterHash; + std::unordered_map > m_SessionsByRouterHash; std::map > m_PendingOutgoingSessions; mutable std::mutex m_PendingOutgoingSessionsMutex; std::map > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 7d5763a2..7a7154a9 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -3140,7 +3140,7 @@ namespace transport SendPeerTest (7, buf + offset, len - offset); else LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6"); - GetServer ().RemoveSession (~htobe64 (((uint64_t)nonce << 32) | nonce)); + GetServer ().RemoveSession (GetConnID ()); break; } case 7: // Alice from Charlie 2 @@ -3148,7 +3148,7 @@ namespace transport auto addr = GetAddress (); if (addr && addr->IsV6 ()) i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2 - GetServer ().RemoveSession (htobe64 (((uint64_t)nonce << 32) | nonce)); + GetServer ().RemoveSession (GetConnID ()); break; } default: @@ -3203,5 +3203,16 @@ namespace transport SetAddress (addr); SendPeerTest (msg, signedData, signedDataLen); } + + void SSU2PeerTestSession::Connect () + { + LogPrint (eLogError, "SSU2: Can't connect peer test session"); + } + + bool SSU2PeerTestSession::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) + { + LogPrint (eLogError, "SSU2: Can't handle incoming message in peer test session"); + return false; + } } } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index eaf727cc..d261bc6d 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -248,7 +248,7 @@ namespace transport void SetOnEstablished (OnEstablished e) { m_OnEstablished = e; }; OnEstablished GetOnEstablished () const { return m_OnEstablished; }; - void Connect (); + virtual void Connect (); bool Introduce (std::shared_ptr session, uint32_t relayTag); void WaitForIntroduction (); void SendPeerTest (); // Alice, Data message @@ -268,7 +268,7 @@ namespace transport SSU2SessionState GetState () const { return m_State; }; void SetState (SSU2SessionState state) { m_State = state; }; - bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len); + virtual bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len); bool ProcessSessionCreated (uint8_t * buf, size_t len); bool ProcessSessionConfirmed (uint8_t * buf, size_t len); bool ProcessRetry (uint8_t * buf, size_t len); @@ -404,7 +404,9 @@ namespace transport void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, std::shared_ptr addr); bool ProcessPeerTest (uint8_t * buf, size_t len) override; - + void Connect () override; // outgoing + bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) override; // incoming + private: void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen); // PeerTest message From 262a803d106d41782a4f2fd1429d78102a0b9a92 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 24 Sep 2024 20:57:04 -0400 Subject: [PATCH 128/527] make sure we are done with session before remving it --- libi2pd/SSU2.cpp | 5 +++++ libi2pd/SSU2.h | 1 + libi2pd/SSU2Session.cpp | 6 +++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 2005294b..cdc127b1 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -476,6 +476,11 @@ namespace transport } } + void SSU2Server::RequestRemoveSession (uint64_t connID) + { + GetService ().post ([connID, this]() { RemoveSession (connID); }); + } + void SSU2Server::AddSessionByRouterHash (std::shared_ptr session) { if (session) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 54eca83f..84a13075 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -82,6 +82,7 @@ namespace transport void AddSession (std::shared_ptr session); void RemoveSession (uint64_t connID); + void RequestRemoveSession (uint64_t connID); void AddSessionByRouterHash (std::shared_ptr session); bool AddPendingOutgoingSession (std::shared_ptr session); void RemovePendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 7a7154a9..ce3f1637 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -224,7 +224,7 @@ namespace transport // connect m_State = eSSU2SessionStateTokenReceived; m_Server.AddPendingOutgoingSession (shared_from_this ()); - m_Server.RemoveSession (oldConnID); + m_Server.RequestRemoveSession (oldConnID); Connect (); } } @@ -3140,7 +3140,7 @@ namespace transport SendPeerTest (7, buf + offset, len - offset); else LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6"); - GetServer ().RemoveSession (GetConnID ()); + GetServer ().RequestRemoveSession (GetConnID ()); break; } case 7: // Alice from Charlie 2 @@ -3148,7 +3148,7 @@ namespace transport auto addr = GetAddress (); if (addr && addr->IsV6 ()) i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2 - GetServer ().RemoveSession (GetConnID ()); + GetServer ().RequestRemoveSession (GetConnID ()); break; } default: From 67763248cc088b179ca51ae728890e10c24bc0ec Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 24 Sep 2024 22:06:44 -0400 Subject: [PATCH 129/527] add peer test session endpoint to connected recently after msg 6 and 7 --- libi2pd/SSU2Session.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index ce3f1637..bc47690d 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -3064,6 +3064,7 @@ namespace transport SetSourceConnID (sourceConnID); SetDestConnID (destConnID); SetState (eSSU2SessionStatePeerTest); + SetTerminationTimeout (SSU2_PEER_TEST_EXPIRATION_TIMEOUT); } bool SSU2PeerTestSession::ProcessPeerTest (uint8_t * buf, size_t len) @@ -3140,6 +3141,7 @@ namespace transport SendPeerTest (7, buf + offset, len - offset); else LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6"); + GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ()); GetServer ().RequestRemoveSession (GetConnID ()); break; } @@ -3148,6 +3150,7 @@ namespace transport auto addr = GetAddress (); if (addr && addr->IsV6 ()) i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2 + GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ()); GetServer ().RequestRemoveSession (GetConnID ()); break; } From 98669eff4fe0a59b8e2c12651b9d5410d1c4a80e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 Sep 2024 11:13:01 -0400 Subject: [PATCH 130/527] delete session by hash from table if expired or terminated --- libi2pd/SSU2.cpp | 12 ++++++++++-- libi2pd/SSU2.h | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index cdc127b1..17bc1912 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -515,11 +515,19 @@ namespace transport return m_PendingOutgoingSessions.emplace (session->GetRemoteEndpoint (), session).second; } - std::shared_ptr SSU2Server::FindSession (const i2p::data::IdentHash& ident) const + std::shared_ptr SSU2Server::FindSession (const i2p::data::IdentHash& ident) { auto it = m_SessionsByRouterHash.find (ident); if (it != m_SessionsByRouterHash.end ()) - return it->second.lock (); + { + if (!it->second.expired ()) + { + auto s = it->second.lock (); + if (s && s->GetState () != eSSU2SessionStateTerminated) + return s; + } + m_SessionsByRouterHash.erase (it); + } return nullptr; } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 84a13075..2c5e8cc6 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -86,7 +86,7 @@ namespace transport void AddSessionByRouterHash (std::shared_ptr session); bool AddPendingOutgoingSession (std::shared_ptr session); void RemovePendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep); - std::shared_ptr FindSession (const i2p::data::IdentHash& ident) const; + std::shared_ptr FindSession (const i2p::data::IdentHash& ident); std::shared_ptr FindPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) const; std::shared_ptr GetRandomPeerTestSession (i2p::data::RouterInfo::CompatibleTransports remoteTransports, const i2p::data::IdentHash& excluded); From 32ad4b4858535472116b11de6981cc8cd21f67ed Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 Sep 2024 14:34:52 -0400 Subject: [PATCH 131/527] fixed possible race conditions with m_SessionsByRouterHash --- libi2pd/SSU2.cpp | 155 +++++++++++++++++++++++------------------------ libi2pd/SSU2.h | 1 + 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 17bc1912..b5b9d25c 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -465,6 +465,7 @@ namespace transport auto ident = it->second->GetRemoteIdentity (); if (ident) { + std::lock_guard l(m_SessionsByRouterHashMutex); auto it1 = m_SessionsByRouterHash.find (ident->GetIdentHash ()); if (it1 != m_SessionsByRouterHash.end () && it->second == it1->second.lock ()) m_SessionsByRouterHash.erase (it1); @@ -488,22 +489,26 @@ namespace transport auto ident = session->GetRemoteIdentity (); if (ident) { - auto ret = m_SessionsByRouterHash.emplace (ident->GetIdentHash (), session); - if (!ret.second) + std::shared_ptr oldSession; { - auto oldSession = ret.first->second.lock (); - if (oldSession != session) - { - // session already exists - LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " already exists"); - // move unsent msgs to new session - oldSession->MoveSendQueue (session); - // terminate existing - GetService ().post (std::bind (&SSU2Session::RequestTermination, oldSession, eSSU2TerminationReasonReplacedByNewSession)); + std::lock_guard l(m_SessionsByRouterHashMutex); + auto ret = m_SessionsByRouterHash.emplace (ident->GetIdentHash (), session); + if (!ret.second) + { + oldSession = ret.first->second.lock (); // update session ret.first->second = session; } - } + } + if (oldSession && oldSession != session) + { + // session already exists + LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " already exists"); + // move unsent msgs to new session + oldSession->MoveSendQueue (session); + // terminate existing + GetService ().post (std::bind (&SSU2Session::RequestTermination, oldSession, eSSU2TerminationReasonReplacedByNewSession)); + } } } } @@ -511,12 +516,13 @@ namespace transport bool SSU2Server::AddPendingOutgoingSession (std::shared_ptr session) { if (!session) return false; - std::unique_lock l(m_PendingOutgoingSessionsMutex); + std::lock_guard l(m_PendingOutgoingSessionsMutex); return m_PendingOutgoingSessions.emplace (session->GetRemoteEndpoint (), session).second; } std::shared_ptr SSU2Server::FindSession (const i2p::data::IdentHash& ident) { + std::lock_guard l(m_SessionsByRouterHashMutex); auto it = m_SessionsByRouterHash.find (ident); if (it != m_SessionsByRouterHash.end ()) { @@ -533,7 +539,7 @@ namespace transport std::shared_ptr SSU2Server::FindPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) const { - std::unique_lock l(m_PendingOutgoingSessionsMutex); + std::lock_guard l(m_PendingOutgoingSessionsMutex); auto it = m_PendingOutgoingSessions.find (ep); if (it != m_PendingOutgoingSessions.end ()) return it->second; @@ -542,7 +548,7 @@ namespace transport void SSU2Server::RemovePendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) { - std::unique_lock l(m_PendingOutgoingSessionsMutex); + std::lock_guard l(m_PendingOutgoingSessionsMutex); m_PendingOutgoingSessions.erase (ep); } @@ -681,7 +687,7 @@ namespace transport if (it1->second->GetState () == eSSU2SessionStateSessionRequestSent && it1->second->ProcessSessionCreated (buf, len)) { - std::unique_lock l(m_PendingOutgoingSessionsMutex); + std::lock_guard l(m_PendingOutgoingSessionsMutex); m_PendingOutgoingSessions.erase (it1); // we are done with that endpoint } else @@ -778,13 +784,12 @@ namespace transport if (router && address) { // check if no session - auto it = m_SessionsByRouterHash.find (router->GetIdentHash ()); - if (it != m_SessionsByRouterHash.end ()) + auto existingSession = FindSession (router->GetIdentHash ()); + if (existingSession) { // session with router found, trying to send peer test if requested - auto session = it->second.lock (); - if (peerTest && session && session->IsEstablished ()) - GetService ().post ([session]() { session->SendPeerTest (); }); + if (peerTest && existingSession->IsEstablished ()) + GetService ().post ([existingSession]() { existingSession->SendPeerTest (); }); return false; } // check is no pending session @@ -841,19 +846,15 @@ namespace transport { if (it.iTag && ts < it.iExp) { - auto it1 = m_SessionsByRouterHash.find (it.iH); - if (it1 != m_SessionsByRouterHash.end ()) + auto s = FindSession (it.iH); + if (s) { - auto s = it1->second.lock (); - if (s) + auto addr = s->GetAddress (); + if (addr && addr->IsIntroducer ()) { - auto addr = s->GetAddress (); - if (addr && addr->IsIntroducer ()) - { - s->Introduce (session, it.iTag); - return; - } - } + s->Introduce (session, it.iTag); + return; + } } else indices.push_back(i); @@ -959,10 +960,7 @@ namespace transport if (!router) return false; auto addr = v4 ? router->GetSSU2V4Address () : router->GetSSU2V6Address (); if (!addr) return false; - std::shared_ptr session; - auto it = m_SessionsByRouterHash.find (router->GetIdentHash ()); - if (it != m_SessionsByRouterHash.end ()) - session = it->second.lock (); + auto session = FindSession (router->GetIdentHash ()); if (session) { auto remoteAddr = session->GetAddress (); @@ -992,17 +990,20 @@ namespace transport if (ecode != boost::asio::error::operation_aborted) { auto ts = i2p::util::GetSecondsSinceEpoch (); - for (auto it = m_PendingOutgoingSessions.begin (); it != m_PendingOutgoingSessions.end ();) + { - if (it->second->IsTerminationTimeoutExpired (ts)) + std::lock_guard l(m_PendingOutgoingSessionsMutex); + for (auto it = m_PendingOutgoingSessions.begin (); it != m_PendingOutgoingSessions.end ();) { - //it->second->Terminate (); - std::unique_lock l(m_PendingOutgoingSessionsMutex); - it = m_PendingOutgoingSessions.erase (it); + if (it->second->IsTerminationTimeoutExpired (ts)) + { + //it->second->Terminate (); + it = m_PendingOutgoingSessions.erase (it); + } + else + it++; } - else - it++; - } + } for (auto it: m_Sessions) { @@ -1020,14 +1021,6 @@ namespace transport it.second->CleanUp (ts); } - for (auto it = m_SessionsByRouterHash.begin (); it != m_SessionsByRouterHash.begin ();) - { - if (it->second.expired ()) - it = m_SessionsByRouterHash.erase (it); - else - it++; - } - ScheduleTermination (); } } @@ -1083,6 +1076,17 @@ namespace transport else it++; } + + { + std::lock_guard l(m_SessionsByRouterHashMutex); + for (auto it = m_SessionsByRouterHash.begin (); it != m_SessionsByRouterHash.begin ();) + { + if (it->second.expired ()) + it = m_SessionsByRouterHash.erase (it); + else + it++; + } + } m_PacketsPool.CleanUpMt (); m_SentPacketsPool.CleanUp (); @@ -1204,27 +1208,26 @@ namespace transport std::unordered_set excluded; for (const auto& it : introducers) { - std::shared_ptr session; - auto it1 = m_SessionsByRouterHash.find (it); - if (it1 != m_SessionsByRouterHash.end ()) - { - session = it1->second.lock (); + std::shared_ptr session = FindSession (it); + if (session) excluded.insert (it); - } - if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing () && // still session with introducer? - ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION) + if (session) { - session->SendKeepAlive (); - if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION) - newList.push_back (it); - else + if (session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing () && // still session with introducer? + ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION) { - impliedList.push_back (it); // keep in introducers list, but not publish - session = nullptr; - } + session->SendKeepAlive (); + if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION) + newList.push_back (it); + else + { + impliedList.push_back (it); // keep in introducers list, but not publish + session = nullptr; + } + } + else + session = nullptr; } - else - session = nullptr; if (!session) i2p::context.RemoveSSU2Introducer (it, v4); @@ -1239,16 +1242,12 @@ namespace transport impliedList.clear (); for (auto& it : introducers) { - auto it1 = m_SessionsByRouterHash.find (it); - if (it1 != m_SessionsByRouterHash.end ()) + auto session = FindSession (it); + if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ()) { - auto session = it1->second.lock (); - if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ()) - { - session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); - if (std::find (newList.begin (), newList.end (), it) == newList.end ()) - sessions.push_back (session); - } + session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); + if (std::find (newList.begin (), newList.end (), it) == newList.end ()) + sessions.push_back (session); } } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 2c5e8cc6..06541010 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -164,6 +164,7 @@ namespace transport boost::asio::ip::address m_AddressV4, m_AddressV6; std::unordered_map > m_Sessions; std::unordered_map > m_SessionsByRouterHash; + mutable std::mutex m_SessionsByRouterHashMutex; std::map > m_PendingOutgoingSessions; mutable std::mutex m_PendingOutgoingSessionsMutex; std::map > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds) From 75b1c144b4b5260b505bb6444f64cbd79d0e801f Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 26 Sep 2024 08:48:17 -0400 Subject: [PATCH 132/527] drop too short follow on SSU2 packets --- libi2pd/SSU2.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index b5b9d25c..4293c2d5 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -377,7 +377,10 @@ namespace transport if (!ec) { i2p::transport::transports.UpdateReceivedBytes (packet->len); - packets.push_back (packet); + if (packet->len >= SSU2_MIN_RECEIVED_PACKET_SIZE) + packets.push_back (packet); + else // drop too short packets + m_PacketsPool.ReleaseMt (packet); moreBytes = socket.available(ec); if (ec) break; } From a06cce0aaf3fcf4326dc51625c38df8453422e19 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 26 Sep 2024 15:54:29 -0400 Subject: [PATCH 133/527] eliminate extra copy of vector of SSU2 packets --- libi2pd/SSU2.cpp | 9 ++++++--- libi2pd/SSU2.h | 2 +- libi2pd/util.h | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 4293c2d5..80ddbed4 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -391,7 +391,10 @@ namespace transport break; } } - GetService ().post (std::bind (&SSU2Server::HandleReceivedPackets, this, packets)); + GetService ().post ([packets = std::move (packets), this]() mutable + { + HandleReceivedPackets (std::move (packets)); + }); } else GetService ().post (std::bind (&SSU2Server::HandleReceivedPacket, this, packet)); @@ -435,7 +438,7 @@ namespace transport } } - void SSU2Server::HandleReceivedPackets (std::vector packets) + void SSU2Server::HandleReceivedPackets (std::vector&& packets) { if (m_IsThroughProxy) for (auto& packet: packets) @@ -443,7 +446,7 @@ namespace transport else for (auto& packet: packets) ProcessNextPacket (packet->buf, packet->len, packet->from); - m_PacketsPool.ReleaseMt (packets); + m_PacketsPool.ReleaseMt (std::move (packets)); if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) m_LastSession->FlushData (); } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 06541010..381b90c8 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -126,7 +126,7 @@ namespace transport void HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred, Packet * packet, boost::asio::ip::udp::socket& socket); void HandleReceivedPacket (Packet * packet); - void HandleReceivedPackets (std::vector packets); + void HandleReceivedPackets (std::vector&& packets); void ProcessNextPacket (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void ScheduleTermination (); diff --git a/libi2pd/util.h b/libi2pd/util.h index e2037212..dbc69c25 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.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 * @@ -132,7 +132,7 @@ namespace util } templateclass C, typename... R> - void ReleaseMt(const C& c) + void ReleaseMt(C&& c) { std::lock_guard l(m_Mutex); for (auto& it: c) From c3a1631319cb770bef735a5d28ce96f2ea44ba87 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 26 Sep 2024 18:38:17 -0400 Subject: [PATCH 134/527] use weak_ptr for Bob's peer tests and relay tags --- libi2pd/SSU2.cpp | 15 +++++++------ libi2pd/SSU2.h | 3 ++- libi2pd/SSU2Session.cpp | 48 ++++++++++++++++++++++------------------- libi2pd/SSU2Session.h | 2 +- 4 files changed, 38 insertions(+), 30 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 80ddbed4..6378d7b8 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -370,7 +370,7 @@ namespace transport { std::vector packets; packets.push_back (packet); - while (moreBytes && packets.size () < 32) + while (moreBytes && packets.size () < SSU2_MAX_NUM_PACKETS_PER_BATCH) { packet = m_PacketsPool.AcquireMt (); packet->len = socket.receive_from (boost::asio::buffer (packet->buf, SSU2_MAX_PACKET_SIZE), packet->from, 0, ec); @@ -599,10 +599,13 @@ namespace transport auto it = m_Relays.find (tag); if (it != m_Relays.end ()) { - if (it->second->IsEstablished ()) - return it->second; - else - m_Relays.erase (it); + if (!it->second.expired ()) + { + auto s = it->second.lock (); + if (s && s->IsEstablished ()) + return s; + } + m_Relays.erase (it); } return nullptr; } @@ -1045,7 +1048,7 @@ namespace transport auto ts = i2p::util::GetSecondsSinceEpoch (); for (auto it = m_Relays.begin (); it != m_Relays.begin ();) { - if (it->second && it->second->GetState () == eSSU2SessionStateTerminated) + if (it->second.expired ()) it = m_Relays.erase (it); else it++; diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 381b90c8..bae33aa2 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -40,6 +40,7 @@ namespace transport const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds const int SSU2_HOLE_PUNCH_EXPIRATION = 150; // in seconds + const size_t SSU2_MAX_NUM_PACKETS_PER_BATCH = 32; class SSU2Server: private i2p::util::RunnableServiceWithWork { @@ -168,7 +169,7 @@ namespace transport std::map > m_PendingOutgoingSessions; mutable std::mutex m_PendingOutgoingSessionsMutex; std::map > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds) - std::unordered_map > m_Relays; // we are introducer, relay tag -> session + std::unordered_map > m_Relays; // we are introducer, relay tag -> session std::list m_Introducers, m_IntroducersV6; // introducers we are connected to i2p::util::MemoryPoolMt m_PacketsPool; i2p::util::MemoryPool m_SentPacketsPool; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index bc47690d..e9994b9f 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2252,27 +2252,31 @@ namespace transport case 3: // Bob from Charlie { auto it = m_PeerTests.find (nonce); - if (it != m_PeerTests.end () && it->second.first) + if (it != m_PeerTests.end ()) { - uint8_t payload[SSU2_MAX_PACKET_SIZE]; - // Charlie's RouterInfo - auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); - if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; - size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; - if (!payloadSize && r) - it->second.first->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); - if (payloadSize + len + 16 > m_MaxPayloadSize) - { - // doesn't fit one message, send RouterInfo in separate message - it->second.first->SendData (payload, payloadSize); - payloadSize = 0; - } - // PeerTest to Alice - payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize, 4, - (SSU2PeerTestCode)buf[1], GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); - if (payloadSize < m_MaxPayloadSize) - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - it->second.first->SendData (payload, payloadSize); + auto aliceSession = it->second.first.lock (); + if (aliceSession && aliceSession->IsEstablished ()) + { + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + // Charlie's RouterInfo + auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); + if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; + size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; + if (!payloadSize && r) + aliceSession->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); + if (payloadSize + len + 16 > m_MaxPayloadSize) + { + // doesn't fit one message, send RouterInfo in separate message + aliceSession->SendData (payload, payloadSize); + payloadSize = 0; + } + // PeerTest to Alice + payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize, 4, + (SSU2PeerTestCode)buf[1], GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); + if (payloadSize < m_MaxPayloadSize) + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); + aliceSession->SendData (payload, payloadSize); + } m_PeerTests.erase (it); } else @@ -3028,9 +3032,9 @@ namespace transport } for (auto it = m_PeerTests.begin (); it != m_PeerTests.end ();) { - if (ts > it->second.second + SSU2_PEER_TEST_EXPIRATION_TIMEOUT) + if (ts > it->second.second + SSU2_PEER_TEST_EXPIRATION_TIMEOUT || it->second.first.expired ()) { - LogPrint (eLogWarning, "SSU2: Peer test nonce ", it->first, " was not responded in ", SSU2_PEER_TEST_EXPIRATION_TIMEOUT, " seconds, deleted"); + LogPrint (eLogWarning, "SSU2: Peer test nonce ", it->first, " was not responded in ", SSU2_PEER_TEST_EXPIRATION_TIMEOUT, " seconds or session invalid. Deleted"); it = m_PeerTests.erase (it); } else diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index d261bc6d..fdd7cc8e 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -373,7 +373,7 @@ namespace transport std::map > m_SentPackets; // packetNum -> packet std::unordered_map > m_IncompleteMessages; // msgID -> I2NP std::unordered_map, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice - std::unordered_map, uint64_t > > m_PeerTests; // same as for relay sessions + std::unordered_map, uint64_t > > m_PeerTests; // nonce->(Alice, timestamp). We are Bob std::list > m_SendQueue; i2p::I2NPMessagesHandler m_Handler; bool m_IsDataReceived; From 64e4b3871a99989cd5f731e50fa0904698251148 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 27 Sep 2024 13:32:20 -0400 Subject: [PATCH 135/527] update introducer's iTag is session to introducer was replaced to new one --- libi2pd/RouterContext.cpp | 6 ++++++ libi2pd/RouterContext.h | 1 + libi2pd/RouterInfo.cpp | 18 ++++++++++++++++++ libi2pd/RouterInfo.h | 1 + libi2pd/SSU2.cpp | 33 +++++++++++++++++++++------------ libi2pd/SSU2.h | 2 +- 6 files changed, 48 insertions(+), 13 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index f9548139..1efb25db 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -557,6 +557,12 @@ namespace i2p UpdateRouterInfo (); } + void RouterContext::UpdateSSU2Introducer (const i2p::data::IdentHash& h, bool v4, uint32_t iTag, uint32_t iExp) + { + if (m_RouterInfo.UpdateSSU2Introducer (h, v4, iTag, iExp)) + UpdateRouterInfo (); + } + void RouterContext::ClearSSU2Introducers (bool v4) { auto addr = m_RouterInfo.GetSSU2Address (v4); diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 03f1d10d..c620f8b1 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -154,6 +154,7 @@ namespace garlic void PublishSSU2Address (int port, bool publish, bool v4, bool v6); bool AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4); void RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4); + void UpdateSSU2Introducer (const i2p::data::IdentHash& h, bool v4, uint32_t iTag, uint32_t iExp); void ClearSSU2Introducers (bool v4); bool IsUnreachable () const; void SetUnreachable (bool v4, bool v6); diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index ce1ae72c..2da40ae8 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1554,5 +1554,23 @@ namespace data } return false; } + + bool LocalRouterInfo::UpdateSSU2Introducer (const IdentHash& h, bool v4, uint32_t iTag, uint32_t iExp) + { + auto addresses = GetAddresses (); + if (!addresses) return false; + auto addr = (*addresses)[v4 ? eSSU2V4Idx : eSSU2V6Idx]; + if (addr) + { + for (auto& it: addr->ssu->introducers) + if (h == it.iH) + { + it.iTag = iTag; + it.iExp = iExp; + return true; + } + } + return false; + } } } diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 68d6b0f0..72521797 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -380,6 +380,7 @@ namespace data bool AddSSU2Introducer (const Introducer& introducer, bool v4); bool RemoveSSU2Introducer (const IdentHash& h, bool v4); + bool UpdateSSU2Introducer (const IdentHash& h, bool v4, uint32_t iTag, uint32_t iExp); private: diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 6378d7b8..d661c33b 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1212,14 +1212,14 @@ namespace transport void SSU2Server::UpdateIntroducers (bool v4) { uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - std::list newList, impliedList; + std::list > newList, impliedList; auto& introducers = v4 ? m_Introducers : m_IntroducersV6; std::unordered_set excluded; - for (const auto& it : introducers) + for (const auto& [ident, tag] : introducers) { - std::shared_ptr session = FindSession (it); + std::shared_ptr session = FindSession (ident); if (session) - excluded.insert (it); + excluded.insert (ident); if (session) { if (session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing () && // still session with introducer? @@ -1227,19 +1227,27 @@ namespace transport { session->SendKeepAlive (); if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION) - newList.push_back (it); + { + newList.push_back ({ident, session->GetRelayTag ()}); + if (tag != session->GetRelayTag ()) + { + LogPrint (eLogDebug, "SSU2: Introducer session to ", session->GetIdentHashBase64() , " was replaced. iTag ", tag, "->", session->GetRelayTag ()); + i2p::context.UpdateSSU2Introducer (ident, v4, session->GetRelayTag (), + session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION); + } + } else { - impliedList.push_back (it); // keep in introducers list, but not publish + impliedList.push_back ({ident, session->GetRelayTag ()}); // keep in introducers list, but not publish session = nullptr; - } + } } else session = nullptr; } if (!session) - i2p::context.RemoveSSU2Introducer (it, v4); + i2p::context.RemoveSSU2Introducer (ident, v4); } if (newList.size () < SSU2_MAX_NUM_INTRODUCERS) { @@ -1249,13 +1257,14 @@ namespace transport // bump creation time for previous introducers if no new sessions found LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing"); impliedList.clear (); - for (auto& it : introducers) + for (const auto& [ident, tag] : introducers) { - auto session = FindSession (it); + auto session = FindSession (ident); if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ()) { session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); - if (std::find (newList.begin (), newList.end (), it) == newList.end ()) + if (std::find_if (newList.begin (), newList.end (), + [&ident](const auto& s){ return ident == s.first; }) == newList.end ()) sessions.push_back (session); } } @@ -1276,7 +1285,7 @@ namespace transport { LogPrint (eLogDebug, "SSU2: Introducer added ", it->GetRelayTag (), " at ", i2p::data::GetIdentHashAbbreviation (it->GetRemoteIdentity ()->GetIdentHash ())); - newList.push_back (it->GetRemoteIdentity ()->GetIdentHash ()); + newList.push_back ({ it->GetRemoteIdentity ()->GetIdentHash (), tag }); if (newList.size () >= SSU2_MAX_NUM_INTRODUCERS) break; } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index bae33aa2..36b946c5 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -170,7 +170,7 @@ namespace transport mutable std::mutex m_PendingOutgoingSessionsMutex; std::map > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds) std::unordered_map > m_Relays; // we are introducer, relay tag -> session - std::list m_Introducers, m_IntroducersV6; // introducers we are connected to + std::list > m_Introducers, m_IntroducersV6; // introducers we are connected to i2p::util::MemoryPoolMt m_PacketsPool; i2p::util::MemoryPool m_SentPacketsPool; i2p::util::MemoryPool m_IncompleteMessagesPool; From 62b811c2c150dd502bde36f9960a8ece112c992c Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 28 Sep 2024 09:49:45 -0400 Subject: [PATCH 136/527] use memory pool for SSU2 received packets arrays --- libi2pd/SSU2.cpp | 36 ++++++++++++++++++++++++------------ libi2pd/SSU2.h | 18 +++++++++++++++++- libi2pd/util.h | 12 ++++++++++-- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index d661c33b..ec36d6fb 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -368,9 +368,9 @@ namespace transport size_t moreBytes = socket.available (ec); if (!ec && moreBytes) { - std::vector packets; - packets.push_back (packet); - while (moreBytes && packets.size () < SSU2_MAX_NUM_PACKETS_PER_BATCH) + auto packets = m_PacketsArrayPool.AcquireMt (); + packets->AddPacket (packet); + while (moreBytes && packets->numPackets < SSU2_MAX_NUM_PACKETS_PER_BATCH) { packet = m_PacketsPool.AcquireMt (); packet->len = socket.receive_from (boost::asio::buffer (packet->buf, SSU2_MAX_PACKET_SIZE), packet->from, 0, ec); @@ -378,7 +378,13 @@ namespace transport { i2p::transport::transports.UpdateReceivedBytes (packet->len); if (packet->len >= SSU2_MIN_RECEIVED_PACKET_SIZE) - packets.push_back (packet); + { + if (!packets->AddPacket (packet)) + { + LogPrint (eLogError, "SSU2: Received packets array is full"); + m_PacketsPool.ReleaseMt (packet); + } + } else // drop too short packets m_PacketsPool.ReleaseMt (packet); moreBytes = socket.available(ec); @@ -391,10 +397,7 @@ namespace transport break; } } - GetService ().post ([packets = std::move (packets), this]() mutable - { - HandleReceivedPackets (std::move (packets)); - }); + GetService ().post (std::bind (&SSU2Server::HandleReceivedPackets, this, packets)); } else GetService ().post (std::bind (&SSU2Server::HandleReceivedPacket, this, packet)); @@ -438,15 +441,23 @@ namespace transport } } - void SSU2Server::HandleReceivedPackets (std::vector&& packets) + void SSU2Server::HandleReceivedPackets (Packets * packets) { + if (!packets) return; if (m_IsThroughProxy) - for (auto& packet: packets) + for (size_t i = 0; i < packets->numPackets; i++) + { + auto& packet = (*packets)[i]; ProcessNextPacketFromProxy (packet->buf, packet->len); + } else - for (auto& packet: packets) + for (size_t i = 0; i < packets->numPackets; i++) + { + auto& packet = (*packets)[i]; ProcessNextPacket (packet->buf, packet->len, packet->from); - m_PacketsPool.ReleaseMt (std::move (packets)); + } + m_PacketsPool.ReleaseMt (packets->data (), packets->numPackets); + m_PacketsArrayPool.ReleaseMt (packets); if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) m_LastSession->FlushData (); } @@ -1098,6 +1109,7 @@ namespace transport } m_PacketsPool.CleanUpMt (); + m_PacketsArrayPool.CleanUpMt (); m_SentPacketsPool.CleanUp (); m_IncompleteMessagesPool.CleanUp (); m_FragmentsPool.CleanUp (); diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 36b946c5..97ef879f 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "util.h" @@ -51,6 +52,20 @@ namespace transport boost::asio::ip::udp::endpoint from; }; + struct Packets: public std::array + { + size_t numPackets = 0; + bool AddPacket (Packet *p) + { + if (p && numPackets < size ()) + { + data()[numPackets] = p; numPackets++; + return true; + } + return false; + } + }; + class ReceiveService: public i2p::util::RunnableService { public: @@ -127,7 +142,7 @@ namespace transport void HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred, Packet * packet, boost::asio::ip::udp::socket& socket); void HandleReceivedPacket (Packet * packet); - void HandleReceivedPackets (std::vector&& packets); + void HandleReceivedPackets (Packets * packets); void ProcessNextPacket (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void ScheduleTermination (); @@ -172,6 +187,7 @@ namespace transport std::unordered_map > m_Relays; // we are introducer, relay tag -> session std::list > m_Introducers, m_IntroducersV6; // introducers we are connected to i2p::util::MemoryPoolMt m_PacketsPool; + i2p::util::MemoryPoolMt m_PacketsArrayPool; i2p::util::MemoryPool m_SentPacketsPool; i2p::util::MemoryPool m_IncompleteMessagesPool; i2p::util::MemoryPool m_FragmentsPool; diff --git a/libi2pd/util.h b/libi2pd/util.h index dbc69c25..e39a9259 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -131,14 +131,22 @@ namespace util this->Release (t); } + void ReleaseMt (T * * arr, size_t num) + { + if (!arr || !num) return; + std::lock_guard l(m_Mutex); + for (size_t i = 0; i < num; i++) + this->Release (arr[i]); + } + templateclass C, typename... R> - void ReleaseMt(C&& c) + void ReleaseMt(const C& c) { std::lock_guard l(m_Mutex); for (auto& it: c) this->Release (it); } - + template std::shared_ptr AcquireSharedMt (TArgs&&... args) { From abbe1fea64d669720b94dfb083204b284e8bdfd6 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 28 Sep 2024 16:20:59 -0400 Subject: [PATCH 137/527] fixed clang build error --- libi2pd/SSU2.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index ec36d6fb..86cd335f 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1269,14 +1269,14 @@ namespace transport // bump creation time for previous introducers if no new sessions found LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing"); impliedList.clear (); - for (const auto& [ident, tag] : introducers) + for (const auto& it : introducers) { - auto session = FindSession (ident); + auto session = FindSession (it.first); if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ()) { session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); if (std::find_if (newList.begin (), newList.end (), - [&ident](const auto& s){ return ident == s.first; }) == newList.end ()) + [&ident = it.first](const auto& s){ return ident == s.first; }) == newList.end ()) sessions.push_back (session); } } From 15cd4feade93a217313a234deb0d40459280972d Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 28 Sep 2024 22:05:25 -0400 Subject: [PATCH 138/527] move Bob's peer tests from SSU2 session to server --- libi2pd/SSU2.cpp | 29 +++++++++++++++++++ libi2pd/SSU2.h | 4 +++ libi2pd/SSU2Session.cpp | 62 +++++++++++++++-------------------------- libi2pd/SSU2Session.h | 1 - 4 files changed, 56 insertions(+), 40 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 86cd335f..01680216 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -152,6 +152,7 @@ namespace transport m_SessionsByRouterHash.clear (); m_PendingOutgoingSessions.clear (); m_Relays.clear (); + m_PeerTests.clear (); m_Introducers.clear (); m_IntroducersV6.clear (); m_ConnectedRecently.clear (); @@ -621,6 +622,23 @@ namespace transport return nullptr; } + bool SSU2Server::AddPeerTest (uint32_t nonce, std::shared_ptr aliceSession, uint64_t ts) + { + return m_PeerTests.emplace (nonce, std::pair{ aliceSession, ts }).second; + } + + std::shared_ptr SSU2Server::GetPeerTest (uint32_t nonce) + { + auto it = m_PeerTests.find (nonce); + if (it != m_PeerTests.end ()) + { + auto s = it->second.first.lock (); + m_PeerTests.erase (it); + return s; + } + return nullptr; + } + bool SSU2Server::AddRequestedPeerTest (uint32_t nonce, std::shared_ptr session, uint64_t ts) { return m_RequestedPeerTests.emplace (nonce, std::pair{ session, ts }).second; @@ -1065,6 +1083,17 @@ namespace transport it++; } + for (auto it = m_PeerTests.begin (); it != m_PeerTests.end ();) + { + if (ts > it->second.second + SSU2_PEER_TEST_EXPIRATION_TIMEOUT || it->second.first.expired ()) + { + LogPrint (eLogInfo, "SSU2: Peer test nonce ", it->first, " was not responded in ", SSU2_PEER_TEST_EXPIRATION_TIMEOUT, " seconds or session invalid. Deleted"); + it = m_PeerTests.erase (it); + } + else + it++; + } + for (auto it = m_IncomingTokens.begin (); it != m_IncomingTokens.end (); ) { if (ts > it->second.second) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 97ef879f..06267ad4 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -111,6 +111,9 @@ namespace transport void RemoveRelay (uint32_t tag); std::shared_ptr FindRelaySession (uint32_t tag); + bool AddPeerTest (uint32_t nonce, std::shared_ptr aliceSession, uint64_t ts); + std::shared_ptr GetPeerTest (uint32_t nonce); + bool AddRequestedPeerTest (uint32_t nonce, std::shared_ptr session, uint64_t ts); std::shared_ptr GetRequestedPeerTest (uint32_t nonce); @@ -185,6 +188,7 @@ namespace transport mutable std::mutex m_PendingOutgoingSessionsMutex; std::map > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds) std::unordered_map > m_Relays; // we are introducer, relay tag -> session + std::unordered_map, uint64_t > > m_PeerTests; // nonce->(Alice, timestamp). We are Bob std::list > m_Introducers, m_IntroducersV6; // introducers we are connected to i2p::util::MemoryPoolMt m_PacketsPool; i2p::util::MemoryPoolMt m_PacketsArrayPool; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index e9994b9f..027c6d9a 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -283,7 +283,6 @@ namespace transport m_SentPackets.clear (); m_IncompleteMessages.clear (); m_RelaySessions.clear (); - m_PeerTests.clear (); m_ReceivedI2NPMsgIDs.clear (); m_Server.RemoveSession (m_SourceConnID); transports.PeerDisconnected (shared_from_this ()); @@ -2145,7 +2144,7 @@ namespace transport GetRemoteIdentity ()->GetIdentHash ()); if (session) // session with Charlie { - session->m_PeerTests.emplace (nonce, std::make_pair (shared_from_this (), i2p::util::GetSecondsSinceEpoch ())); + m_Server.AddPeerTest (nonce, shared_from_this (), ts/1000); auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); // Alice's RouterInfo auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); @@ -2251,34 +2250,29 @@ namespace transport } case 3: // Bob from Charlie { - auto it = m_PeerTests.find (nonce); - if (it != m_PeerTests.end ()) - { - auto aliceSession = it->second.first.lock (); - if (aliceSession && aliceSession->IsEstablished ()) - { - uint8_t payload[SSU2_MAX_PACKET_SIZE]; - // Charlie's RouterInfo - auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); - if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; - size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; - if (!payloadSize && r) - aliceSession->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); - if (payloadSize + len + 16 > m_MaxPayloadSize) - { - // doesn't fit one message, send RouterInfo in separate message - aliceSession->SendData (payload, payloadSize); - payloadSize = 0; - } - // PeerTest to Alice - payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize, 4, - (SSU2PeerTestCode)buf[1], GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); - if (payloadSize < m_MaxPayloadSize) - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); + auto aliceSession = m_Server.GetPeerTest (nonce); + if (aliceSession && aliceSession->IsEstablished ()) + { + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + // Charlie's RouterInfo + auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); + if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; + size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; + if (!payloadSize && r) + aliceSession->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); + if (payloadSize + len + 16 > m_MaxPayloadSize) + { + // doesn't fit one message, send RouterInfo in separate message aliceSession->SendData (payload, payloadSize); - } - m_PeerTests.erase (it); - } + payloadSize = 0; + } + // PeerTest to Alice + payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize, 4, + (SSU2PeerTestCode)buf[1], GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); + if (payloadSize < m_MaxPayloadSize) + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); + aliceSession->SendData (payload, payloadSize); + } else LogPrint (eLogWarning, "SSU2: Unknown peer test 3 nonce ", nonce); break; @@ -3030,16 +3024,6 @@ namespace transport else ++it; } - for (auto it = m_PeerTests.begin (); it != m_PeerTests.end ();) - { - if (ts > it->second.second + SSU2_PEER_TEST_EXPIRATION_TIMEOUT || it->second.first.expired ()) - { - LogPrint (eLogWarning, "SSU2: Peer test nonce ", it->first, " was not responded in ", SSU2_PEER_TEST_EXPIRATION_TIMEOUT, " seconds or session invalid. Deleted"); - it = m_PeerTests.erase (it); - } - else - ++it; - } if (m_PathChallenge) RequestTermination (eSSU2TerminationReasonNormalClose); } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index fdd7cc8e..caa16c01 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -373,7 +373,6 @@ namespace transport std::map > m_SentPackets; // packetNum -> packet std::unordered_map > m_IncompleteMessages; // msgID -> I2NP std::unordered_map, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice - std::unordered_map, uint64_t > > m_PeerTests; // nonce->(Alice, timestamp). We are Bob std::list > m_SendQueue; i2p::I2NPMessagesHandler m_Handler; bool m_IsDataReceived; From 6ebb019e15fe796f3b5776f422964a24f7770cac Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 29 Sep 2024 15:02:18 -0400 Subject: [PATCH 139/527] resend peer test msgs 5 and 6 --- libi2pd/SSU2Session.cpp | 59 ++++++++++++++++++++++++++++++++++++----- libi2pd/SSU2Session.h | 14 ++++++++-- 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 027c6d9a..1ad80fae 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -3045,7 +3045,8 @@ namespace transport SSU2PeerTestSession::SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID): SSU2Session (server, nullptr, nullptr, false), - m_MsgNumReceived (0), m_IsConnectedRecently (false), m_IsStatusChanged (false) + m_MsgNumReceived (0), m_NumResends (0),m_IsConnectedRecently (false), m_IsStatusChanged (false), + m_PeerTestResendTimer (server.GetService ()) { if (!sourceConnID) sourceConnID = ~destConnID; if (!destConnID) destConnID = ~sourceConnID; @@ -3097,9 +3098,10 @@ namespace transport // msgs 5-7 if (len < 8) return; uint8_t msg = buf[0]; - if (msg < m_MsgNumReceived) + if (msg <= m_MsgNumReceived) { - LogPrint (eLogInfo, "SSU2: PeerTest msg num ", msg, " received after ", m_MsgNumReceived, ". Ignored"); + LogPrint (eLogDebug, "SSU2: PeerTest msg num ", msg, " received after ", m_MsgNumReceived, ". Ignored"); + return; } size_t offset = 3; // points to signed data after msg + code + flag uint32_t nonce = bufbe32toh (buf + offset + 1); // 1 - ver @@ -3125,6 +3127,7 @@ namespace transport } case 6: // Charlie from Alice { + m_PeerTestResendTimer.cancel (); // no more msg 5 resends if (GetAddress ()) SendPeerTest (7, buf + offset, len - offset); else @@ -3135,6 +3138,7 @@ namespace transport } case 7: // Alice from Charlie 2 { + m_PeerTestResendTimer.cancel (); // no more msg 6 resends auto addr = GetAddress (); if (addr && addr->IsV6 ()) i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2 @@ -3149,7 +3153,7 @@ namespace transport m_MsgNumReceived = msg; } - void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen) + void SSU2PeerTestSession::SendPeerTest (uint8_t msg) { auto addr = GetAddress (); if (!addr) return; @@ -3172,7 +3176,7 @@ namespace transport if (msg == 6 || msg == 7) payloadSize += CreateAddressBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, GetRemoteEndpoint ()); payloadSize += CreatePeerTestBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, - msg, eSSU2PeerTestCodeAccept, nullptr, signedData, signedDataLen); + msg, eSSU2PeerTestCodeAccept, nullptr, m_SignedData.data (), m_SignedData.size ()); payloadSize += CreatePaddingBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize); // encrypt uint8_t n[12]; @@ -3187,12 +3191,26 @@ namespace transport GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ()); } + void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen) + { +#if __cplusplus >= 202002L // C++20 + m_SignedData.assign (signedData, signedData + signedDataLen); +#else + m_SignedData.resize (signedDataLen); + memcpy (m_SignedData.data (), signedData, signedDataLen); +#endif + SendPeerTest (msg); + // schedule resend for msgs 5 or 6 + if (msg == 5 || msg == 6) + ScheduleResend (); + } + void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, std::shared_ptr addr) { if (!addr) return; SetAddress (addr); - SendPeerTest (msg, signedData, signedDataLen); + SendPeerTest (msg, signedData, signedDataLen); } void SSU2PeerTestSession::Connect () @@ -3205,5 +3223,34 @@ namespace transport LogPrint (eLogError, "SSU2: Can't handle incoming message in peer test session"); return false; } + + void SSU2PeerTestSession::ScheduleResend () + { + if (m_NumResends < SSU2_PEER_TEST_MAX_NUM_RESENDS) + { + m_PeerTestResendTimer.expires_from_now (boost::posix_time::milliseconds( + SSU2_PEER_TEST_RESEND_INTERVAL + GetServer ().GetRng ()() % SSU2_PEER_TEST_RESEND_INTERVAL_VARIANCE)); + std::weak_ptr s(std::static_pointer_cast(shared_from_this ())); + m_PeerTestResendTimer.async_wait ([s](const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + auto s1 = s.lock (); + if (s1) + { + int msg = 0; + if (s1->m_MsgNumReceived < 6) + msg = (s1->m_MsgNumReceived == 5) ? 6 : 5; + if (msg) // 5 or 6 + { + s1->SendPeerTest (msg); + s1->ScheduleResend (); + } + } + } + }); + m_NumResends++; + } + } } } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index caa16c01..6811d3a7 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -390,6 +390,11 @@ namespace transport uint64_t m_LastResendTime, m_LastResendAttemptTime; // in milliseconds }; + + const int SSU2_PEER_TEST_RESEND_INTERVAL = 3000; // in milliseconds + const int SSU2_PEER_TEST_RESEND_INTERVAL_VARIANCE = 2000; // in milliseconds + const int SSU2_PEER_TEST_MAX_NUM_RESENDS = 3; + class SSU2PeerTestSession: public SSU2Session // for PeerTest msgs 5,6,7 { public: @@ -409,12 +414,17 @@ namespace transport private: void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen); // PeerTest message + void SendPeerTest (uint8_t msg); // send or resend m_SignedData void HandlePeerTest (const uint8_t * buf, size_t len) override; - + + void ScheduleResend (); + private: - uint8_t m_MsgNumReceived; + uint8_t m_MsgNumReceived, m_NumResends; bool m_IsConnectedRecently, m_IsStatusChanged; + std::vector m_SignedData; // for resends + boost::asio::deadline_timer m_PeerTestResendTimer; }; inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) From c2234599cd1ba9d3548d9f880c9f13106ce5ec2a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 29 Sep 2024 17:11:54 -0400 Subject: [PATCH 140/527] exclude boost_system from linking because it's headers only now --- Makefile.mingw | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile.mingw b/Makefile.mingw index 8db38e8f..339cec4e 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -17,7 +17,6 @@ ifeq ($(USE_UPNP),yes) endif LDLIBS += \ - $(MINGW_PREFIX)/lib/libboost_system-mt.a \ $(MINGW_PREFIX)/lib/libboost_program_options-mt.a \ $(MINGW_PREFIX)/lib/libssl.a \ $(MINGW_PREFIX)/lib/libcrypto.a \ From ba41f7107d69ab1f2df5c1013f04dea580145530 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 29 Sep 2024 18:17:49 -0400 Subject: [PATCH 141/527] resend peer test responses --- libi2pd/SSU2Session.cpp | 45 ++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 1ad80fae..8874feea 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2171,11 +2171,14 @@ namespace transport else { // Charlie not found, send error back to Alice - uint8_t payload[SSU2_MAX_PACKET_SIZE], zeroHash[32] = {0}; - size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 4, + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); + uint8_t zeroHash[32] = {0}; + packet->payloadSize = CreatePeerTestBlock (packet->payload, m_MaxPayloadSize, 4, eSSU2PeerTestCodeBobNoCharlieAvailable, zeroHash, buf + offset, len - offset); - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - SendData (payload, payloadSize); + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + uint32_t packetNum = SendData (packet->payload, packet->payloadSize); + packet->sendTime = ts; + m_SentPackets.emplace (packetNum, packet); } break; } @@ -2241,11 +2244,13 @@ namespace transport else code = eSSU2PeerTestCodeCharlieAliceIsUnknown; // send msg 3 back to Bob - uint8_t payload[SSU2_MAX_PACKET_SIZE]; - size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 3, + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); + packet->payloadSize = CreatePeerTestBlock (packet->payload, m_MaxPayloadSize, 3, code, nullptr, newSignedData.data (), newSignedData.size ()); - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - SendData (payload, payloadSize); + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + uint32_t packetNum = SendData (packet->payload, packet->payloadSize); + packet->sendTime = ts; + m_SentPackets.emplace (packetNum, packet); break; } case 3: // Bob from Charlie @@ -2253,25 +2258,29 @@ namespace transport auto aliceSession = m_Server.GetPeerTest (nonce); if (aliceSession && aliceSession->IsEstablished ()) { - uint8_t payload[SSU2_MAX_PACKET_SIZE]; + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); // Charlie's RouterInfo auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; - size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; - if (!payloadSize && r) + packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; + if (!packet->payloadSize && r) aliceSession->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); - if (payloadSize + len + 16 > m_MaxPayloadSize) + if (packet->payloadSize + len + 16 > m_MaxPayloadSize) { // doesn't fit one message, send RouterInfo in separate message - aliceSession->SendData (payload, payloadSize); - payloadSize = 0; + uint32_t packetNum = aliceSession->SendData (packet->payload, packet->payloadSize); + packet->sendTime = ts; + aliceSession->m_SentPackets.emplace (packetNum, packet); + packet = m_Server.GetSentPacketsPool ().AcquireShared (); } // PeerTest to Alice - payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize, 4, + packet->payloadSize += CreatePeerTestBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize, 4, (SSU2PeerTestCode)buf[1], GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); - if (payloadSize < m_MaxPayloadSize) - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - aliceSession->SendData (payload, payloadSize); + if (packet->payloadSize < m_MaxPayloadSize) + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + uint32_t packetNum = aliceSession->SendData (packet->payload, packet->payloadSize); + packet->sendTime = ts; + aliceSession->m_SentPackets.emplace (packetNum, packet); } else LogPrint (eLogWarning, "SSU2: Unknown peer test 3 nonce ", nonce); From 5466983b36873db9bd23cbce73d9f2c1e6e83b9b Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 29 Sep 2024 20:57:18 -0400 Subject: [PATCH 142/527] resend relay messages --- libi2pd/SSU2Session.cpp | 58 +++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 8874feea..288d11e1 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -174,36 +174,38 @@ namespace transport // create nonce uint32_t nonce; RAND_bytes ((uint8_t *)&nonce, 4); - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::GetMillisecondsSinceEpoch (); // payload - uint8_t payload[SSU2_MAX_PACKET_SIZE]; - size_t payloadSize = 0; + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); + uint8_t * payload = packet->payload; payload[0] = eSSU2BlkRelayRequest; payload[3] = 0; // flag htobe32buf (payload + 4, nonce); htobe32buf (payload + 8, relayTag); - htobe32buf (payload + 12, ts); + htobe32buf (payload + 12, ts/1000); payload[16] = 2; // ver size_t asz = CreateEndpoint (payload + 18, m_MaxPayloadSize - 18, boost::asio::ip::udp::endpoint (localAddress->host, localAddress->port)); if (!asz) return false; payload[17] = asz; - payloadSize += asz + 18; + packet->payloadSize = asz + 18; SignedData s; s.Insert ((const uint8_t *)"RelayRequestData", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash s.Insert (session->GetRemoteIdentity ()->GetIdentHash (), 32); // chash s.Insert (payload + 4, 14 + asz); // nonce, relay tag, timestamp, ver, asz and Alice's endpoint - s.Sign (i2p::context.GetPrivateKeys (), payload + payloadSize); - payloadSize += i2p::context.GetIdentity ()->GetSignatureLen (); - htobe16buf (payload + 1, payloadSize - 3); // size - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); + s.Sign (i2p::context.GetPrivateKeys (), payload + packet->payloadSize); + packet->payloadSize += i2p::context.GetIdentity ()->GetSignatureLen (); + htobe16buf (payload + 1, packet->payloadSize - 3); // size + packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); // send - m_RelaySessions.emplace (nonce, std::make_pair (session, ts)); + m_RelaySessions.emplace (nonce, std::make_pair (session, ts/1000)); session->m_SourceConnID = htobe64 (((uint64_t)nonce << 32) | nonce); session->m_DestConnID = ~session->m_SourceConnID; m_Server.AddSession (session); - SendData (payload, payloadSize); - + int32_t packetNum = SendData (packet->payload, packet->payloadSize); + packet->sendTime = ts; + m_SentPackets.emplace (packetNum, packet); + return true; } @@ -1945,27 +1947,31 @@ namespace transport SendData (payload, payloadSize); return; } + auto mts = i2p::util::GetMillisecondsSinceEpoch (); session->m_RelaySessions.emplace (bufbe32toh (buf + 1), // nonce - std::make_pair (shared_from_this (), i2p::util::GetSecondsSinceEpoch ()) ); + std::make_pair (shared_from_this (), mts/1000) ); // send relay intro to Charlie auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); // Alice's RI if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; if (!r) LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found"); - uint8_t payload[SSU2_MAX_PACKET_SIZE]; - size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; - if (!payloadSize && r) + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); + packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; + if (!packet->payloadSize && r) session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); - payloadSize += CreateRelayIntroBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, buf + 1, len -1); - if (payloadSize < m_MaxPayloadSize) - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - session->SendData (payload, payloadSize); + packet->payloadSize += CreateRelayIntroBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, buf + 1, len -1); + if (packet->payloadSize < m_MaxPayloadSize) + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize); + packet->sendTime = mts; + session->m_SentPackets.emplace (packetNum, packet); } void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len, int attempts) { // we are Charlie + auto mts = i2p::util::GetMillisecondsSinceEpoch (); SSU2RelayResponseCode code = eSSU2RelayResponseCodeAccept; uint64_t token = 0; bool isV4 = false; @@ -1993,7 +1999,7 @@ namespace transport token = m_Server.GetIncomingToken (ep); isV4 = ep.address ().is_v4 (); SendHolePunch (bufbe32toh (buf + 33), ep, addr->i, token); - m_Server.AddConnectedRecently (ep, i2p::util::GetSecondsSinceEpoch ()); + m_Server.AddConnectedRecently (ep, mts/1000); } else { @@ -2038,11 +2044,13 @@ namespace transport code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; } // send relay response to Bob - uint8_t payload[SSU2_MAX_PACKET_SIZE]; - size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize, + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); + packet->payloadSize = CreateRelayResponseBlock (packet->payload, m_MaxPayloadSize, code, bufbe32toh (buf + 33), token, isV4); - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - SendData (payload, payloadSize); + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + uint32_t packetNum = SendData (packet->payload, packet->payloadSize); + packet->sendTime = mts; + m_SentPackets.emplace (packetNum, packet); } void SSU2Session::HandleRelayResponse (const uint8_t * buf, size_t len) From 237d9474d87331df1ccac2c9fd66b2f4f252570f Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 29 Sep 2024 21:43:47 -0400 Subject: [PATCH 143/527] fixed incomplete response --- daemon/HTTPServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 7a6656dc..21c7b6c6 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -1480,7 +1480,7 @@ namespace http { reply.body = content; m_SendBuffer = reply.to_string(); - boost::asio::async_write (*m_Socket, boost::asio::buffer(m_SendBuffer), + boost::asio::async_write (*m_Socket, boost::asio::buffer(m_SendBuffer), boost::asio::transfer_all (), std::bind (&HTTPConnection::Terminate, shared_from_this (), std::placeholders::_1)); } From d5213505882207784cdde04f626541fb2f8742e3 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 29 Sep 2024 22:15:03 -0400 Subject: [PATCH 144/527] resend relay response --- libi2pd/SSU2Session.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 288d11e1..ac0a828c 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2078,13 +2078,16 @@ namespace transport if (it->second.first && it->second.first->IsEstablished ()) { // we are Bob, message from Charlie - uint8_t payload[SSU2_MAX_PACKET_SIZE]; + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); + uint8_t * payload = packet->payload; payload[0] = eSSU2BlkRelayResponse; htobe16buf (payload + 1, len); memcpy (payload + 3, buf, len); // forward to Alice as is - size_t payloadSize = len + 3; - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - it->second.first->SendData (payload, payloadSize); + packet->payloadSize = len + 3; + packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + uint32_t packetNum = it->second.first->SendData (packet->payload, packet->payloadSize); + packet->sendTime = i2p::util::GetMillisecondsSinceEpoch (); + it->second.first->m_SentPackets.emplace (packetNum, packet); } else { From 0f5e8d842428c365b6346d43f201f78cd592434a Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Sep 2024 14:54:20 -0400 Subject: [PATCH 145/527] don't print warning if duplicated nonce or peer test --- libi2pd/SSU2Session.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index ac0a828c..81367e4b 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2127,14 +2127,14 @@ namespace transport } else { - LogPrint (eLogInfo, "SSU2: RelayResponse status code=", (int)buf[1]); + LogPrint (eLogInfo, "SSU2: RelayResponse status code=", (int)buf[1], " nonce=", bufbe32toh (buf + 2)); it->second.first->Done (); } } m_RelaySessions.erase (it); } else - LogPrint (eLogWarning, "SSU2: RelayResponse unknown nonce ", bufbe32toh (buf + 2)); + LogPrint (eLogDebug, "SSU2: RelayResponse unknown nonce ", bufbe32toh (buf + 2)); } void SSU2Session::HandlePeerTest (const uint8_t * buf, size_t len) @@ -2294,7 +2294,7 @@ namespace transport aliceSession->m_SentPackets.emplace (packetNum, packet); } else - LogPrint (eLogWarning, "SSU2: Unknown peer test 3 nonce ", nonce); + LogPrint (eLogDebug, "SSU2: Unknown peer test 3 nonce ", nonce); break; } case 4: // Alice from Bob @@ -2382,7 +2382,7 @@ namespace transport } } else - LogPrint (eLogWarning, "SSU2: Unknown peer test 4 nonce ", nonce); + LogPrint (eLogDebug, "SSU2: Unknown peer test 4 nonce ", nonce); break; } default: From 98e93468a65175a4f2b6f0d068573c5522fe9465 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Sep 2024 18:12:42 -0400 Subject: [PATCH 146/527] send ack to relay messages --- libi2pd/SSU2Session.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 81367e4b..47af9844 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1570,14 +1570,17 @@ namespace transport case eSSU2BlkRelayRequest: LogPrint (eLogDebug, "SSU2: RelayRequest"); HandleRelayRequest (buf + offset, size); + m_IsDataReceived = true; break; case eSSU2BlkRelayResponse: LogPrint (eLogDebug, "SSU2: RelayResponse"); HandleRelayResponse (buf + offset, size); + m_IsDataReceived = true; break; case eSSU2BlkRelayIntro: LogPrint (eLogDebug, "SSU2: RelayIntro"); HandleRelayIntro (buf + offset, size); + m_IsDataReceived = true; break; case eSSU2BlkPeerTest: LogPrint (eLogDebug, "SSU2: PeerTest msg=", (int)buf[offset], " code=", (int)buf[offset+1]); From e1e530b4a91e944fb001dc15b6adbaea9bbf603f Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Sep 2024 18:27:13 -0400 Subject: [PATCH 147/527] never send Ack to HolePunch and PeerTest messages --- libi2pd/SSU2Session.cpp | 2 ++ libi2pd/SSU2Session.h | 1 + 2 files changed, 3 insertions(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 47af9844..fc11f556 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1420,6 +1420,7 @@ namespace transport return false; } HandlePayload (payload, len - 48); + m_IsDataReceived = false; // connect to Charlie ConnectAfterIntroduction (); @@ -3113,6 +3114,7 @@ namespace transport return false; } HandlePayload (payload, len - 48); + SetIsDataReceived (false); return true; } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 6811d3a7..49bd3be6 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -282,6 +282,7 @@ namespace transport RouterStatus GetRouterStatus () const; void SetRouterStatus (RouterStatus status) const; size_t GetMaxPayloadSize () const { return m_MaxPayloadSize; } + void SetIsDataReceived (bool dataReceived) { m_IsDataReceived = dataReceived; }; uint64_t GetSourceConnID () const { return m_SourceConnID; } void SetSourceConnID (uint64_t sourceConnID) { m_SourceConnID = sourceConnID; } From 600f36539fd2c0060ae3db3624469980097ddfc8 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Sep 2024 22:38:42 -0400 Subject: [PATCH 148/527] don't change ConnIDs of just introduced session. Let Charlie recognize SessionRequest --- libi2pd/SSU2Session.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index fc11f556..d5423fae 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -219,15 +219,22 @@ namespace transport { if (m_State == eSSU2SessionStateIntroduced) { - // create new connID - uint64_t oldConnID = GetConnID (); - RAND_bytes ((uint8_t *)&m_DestConnID, 8); - RAND_bytes ((uint8_t *)&m_SourceConnID, 8); - // connect + // we are Alice + // keep ConnIDs used for introduction, because Charlie waits for SessionRequest from us m_State = eSSU2SessionStateTokenReceived; - m_Server.AddPendingOutgoingSession (shared_from_this ()); - m_Server.RequestRemoveSession (oldConnID); - Connect (); + // move session to pending outgoing + if (m_Server.AddPendingOutgoingSession (shared_from_this ())) + { + m_Server.RemoveSession (GetConnID ()); + // connect + LogPrint (eLogDebug, "SSU2: Connecting after introduction to ", GetIdentHashBase64()); + Connect (); + } + else + { + LogPrint (eLogError, "SSU2: Session ", GetConnID (), " is already pending"); + m_Server.RequestRemoveSession (GetConnID ()); + } } } From eed48c43fd90e094ca00b4e0c4bd30a70c1d2051 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 1 Oct 2024 15:29:48 -0400 Subject: [PATCH 149/527] don't change Firewalled status to Unknown if peer test error --- libi2pd/SSU2Session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index d5423fae..93fc2102 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2387,7 +2387,7 @@ namespace transport { LogPrint (eLogInfo, "SSU2: Peer test 4 error code ", (int)buf[1], " from ", i2p::data::GetIdentHashAbbreviation (buf[1] < 64 ? GetRemoteIdentity ()->GetIdentHash () : i2p::data::IdentHash (buf + 3))); - if (GetTestingState ()) + if (GetTestingState () && GetRouterStatus () != eRouterStatusFirewalled) SetRouterStatus (eRouterStatusUnknown); session->Done (); } From d5c40bb6bebeaf9ff9088c833c599ce6385f7433 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 1 Oct 2024 18:21:07 -0400 Subject: [PATCH 150/527] send keep-alive for newly selected introducer session --- libi2pd/SSU2.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 01680216..f6c6226b 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1327,6 +1327,7 @@ namespace transport LogPrint (eLogDebug, "SSU2: Introducer added ", it->GetRelayTag (), " at ", i2p::data::GetIdentHashAbbreviation (it->GetRemoteIdentity ()->GetIdentHash ())); newList.push_back ({ it->GetRemoteIdentity ()->GetIdentHash (), tag }); + it->SendKeepAlive (); if (newList.size () >= SSU2_MAX_NUM_INTRODUCERS) break; } } From 8c292727dae0f81d40758d697fcf563037b83565 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 1 Oct 2024 20:35:46 -0400 Subject: [PATCH 151/527] introducer duration variance --- libi2pd/SSU2.cpp | 4 +++- libi2pd/SSU2.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index f6c6226b..a32eb1f4 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1267,7 +1267,9 @@ namespace transport ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION) { session->SendKeepAlive (); - if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION) + if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION || + ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION + + m_Rng () % SSU2_TO_INTRODUCER_SESSION_DURATION_VARIANCE) { newList.push_back ({ident, session->GetRelayTag ()}); if (tag != session->GetRelayTag ()) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 06267ad4..996c0979 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -35,7 +35,8 @@ namespace transport const uint64_t SSU2_SOCKET_MAX_BUFFER_SIZE = 4 * 1024 * 1024; 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_DURATION = 3480; // 58 minutes + const int SSU2_TO_INTRODUCER_SESSION_DURATION_VARIANCE = 330; // 5 minutes const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds From 514be6d0480756b8c53336e475b84153295de5a1 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 1 Oct 2024 21:26:54 -0400 Subject: [PATCH 152/527] introducer expiration time variance --- libi2pd/SSU2.cpp | 7 ++++--- libi2pd/SSU2.h | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index a32eb1f4..1076a2de 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1267,9 +1267,7 @@ namespace transport ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION) { session->SendKeepAlive (); - if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION || - ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION + - m_Rng () % SSU2_TO_INTRODUCER_SESSION_DURATION_VARIANCE) + if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION) { newList.push_back ({ident, session->GetRelayTag ()}); if (tag != session->GetRelayTag ()) @@ -1316,6 +1314,9 @@ namespace transport for (const auto& it : sessions) { uint32_t tag = it->GetRelayTag (); + auto extraTime = std::min ((int)(ts - it->GetCreationTime ()), SSU2_TO_INTRODUCER_SESSION_EXPIRATION_VARIANCE); + if( extraTime > 1) + it->SetCreationTime (it->GetCreationTime () + m_Rng () % extraTime); uint32_t exp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION; if (!tag || ts + SSU2_TO_INTRODUCER_SESSION_DURATION/2 > exp) continue; // don't pick too old session for introducer diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 996c0979..93d7e8e2 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -35,9 +35,9 @@ namespace transport const uint64_t SSU2_SOCKET_MAX_BUFFER_SIZE = 4 * 1024 * 1024; 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 = 3480; // 58 minutes - const int SSU2_TO_INTRODUCER_SESSION_DURATION_VARIANCE = 330; // 5 minutes + const int SSU2_TO_INTRODUCER_SESSION_DURATION = 3680; // 1 hour const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes + const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION_VARIANCE = 120; // 2 minutes const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds From 1fb45c4b0d450d96ce54cbf33b22ce9b0c319274 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 2 Oct 2024 08:27:49 -0400 Subject: [PATCH 153/527] don't send HolePunch or PeerTest 5 to unspecified address --- libi2pd/SSU2Session.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 93fc2102..950ed2af 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2002,7 +2002,9 @@ namespace transport boost::asio::ip::udp::endpoint ep; if (ExtractEndpoint (buf + 47, asz, ep)) { - auto addr = ep.address ().is_v6 () ? r->GetSSU2V6Address () : r->GetSSU2V4Address (); + std::shared_ptr addr; + if (!ep.address ().is_unspecified () && ep.port ()) + addr = ep.address ().is_v6 () ? r->GetSSU2V6Address () : r->GetSSU2V4Address (); if (addr) { if (m_Server.IsSupported (ep.address ())) @@ -2234,7 +2236,7 @@ namespace transport { boost::asio::ip::udp::endpoint ep; std::shared_ptr addr; - if (ExtractEndpoint (buf + offset + 10, asz, ep)) + if (ExtractEndpoint (buf + offset + 10, asz, ep) && !ep.address ().is_unspecified () && ep.port ()) addr = r->GetSSU2Address (ep.address ().is_v4 ()); if (addr && m_Server.IsSupported (ep.address ()) && i2p::context.GetRouterInfo ().IsSSU2PeerTesting (ep.address ().is_v4 ())) From dc4cd34893b1332c76c2c90136bc0debcd608ede Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 2 Oct 2024 08:45:44 -0400 Subject: [PATCH 154/527] handle immediate ack requsted flag in data message. set it in keep-alive --- libi2pd/SSU2Session.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 950ed2af..d8171174 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -268,7 +268,7 @@ namespace transport { uint8_t payload[20]; size_t payloadSize = CreatePaddingBlock (payload, 20, 8); - SendData (payload, payloadSize); + SendData (payload, payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); } } @@ -1503,6 +1503,7 @@ namespace transport return; } UpdateNumReceivedBytes (len); + if (header.h.flags[0] & SSU2_FLAG_IMMEDIATE_ACK_REQUESTED) m_IsDataReceived = true; if (!packetNum || UpdateReceivePacketNum (packetNum)) HandlePayload (payload, payloadSize); } From 34f1ba5bd96238d7f21be3ff598fffce462d8a93 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 2 Oct 2024 12:45:12 -0400 Subject: [PATCH 155/527] don't send invalid local address in RelayRequest --- libi2pd/SSU2Session.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index d8171174..6ce3a5e1 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -170,7 +170,12 @@ namespace transport if (!session || !relayTag) return false; // find local address to introduce auto localAddress = session->FindLocalAddress (); - if (!localAddress) return false; + if (!localAddress || localAddress->host.is_unspecified () || !localAddress->port) + { + // can't introduce invalid endpoint + LogPrint (eLogWarning, "SSU2: Can't find local address to introduce"); + return false; + } // create nonce uint32_t nonce; RAND_bytes ((uint8_t *)&nonce, 4); From 7f3a04a72f81e078cc8f3f30960a36fede7b05fa Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 3 Oct 2024 18:44:09 -0400 Subject: [PATCH 156/527] select random introducer session. don't update creation time --- libi2pd/SSU2.cpp | 45 +++++++++++++++++---------------------------- libi2pd/SSU2.h | 5 ++--- 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 1076a2de..87d45d04 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1222,31 +1222,25 @@ namespace transport } std::vector > SSU2Server::FindIntroducers (int maxNumIntroducers, - bool v4, const std::unordered_set& excluded) const + bool v4, const std::unordered_set& excluded) { std::vector > ret; - if (maxNumIntroducers <= 0) return ret; - auto newer = [](const std::shared_ptr& s1, const std::shared_ptr& s2) -> bool - { - auto t1 = s1->GetCreationTime (), t2 = s2->GetCreationTime (); - return (t1 != t2) ? (t1 > t2) : (s1->GetConnID () > s2->GetConnID ()); - }; - std::set, decltype (newer)> introducers(newer); + if (maxNumIntroducers <= 0 || m_Sessions.empty ()) return ret; + + std::vector > eligible; + eligible.reserve (m_Sessions.size ()/2); + auto ts = i2p::util::GetSecondsSinceEpoch (); for (const auto& s : m_Sessions) { if (s.second->IsEstablished () && (s.second->GetRelayTag () && s.second->IsOutgoing ()) && + ts < s.second->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION/2 && !excluded.count (s.second->GetRemoteIdentity ()->GetIdentHash ()) && ((v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V4)) || (!v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V6)))) - introducers.insert (s.second); + eligible.push_back (s.second); } - int i = 0; - for (auto it: introducers) - { - ret.push_back (it); - i++; - if (i >= maxNumIntroducers) break; - } + + std::sample (eligible.begin(), eligible.end(), std::back_inserter(ret), maxNumIntroducers, m_Rng); return ret; } @@ -1293,33 +1287,28 @@ namespace transport if (newList.size () < SSU2_MAX_NUM_INTRODUCERS) { auto sessions = FindIntroducers (SSU2_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded); - if (sessions.empty () && !introducers.empty ()) + if (sessions.empty () && !impliedList.empty ()) { - // bump creation time for previous introducers if no new sessions found LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing"); - impliedList.clear (); - for (const auto& it : introducers) + for (const auto& it : impliedList) { auto session = FindSession (it.first); - if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ()) + if (session) { - session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); if (std::find_if (newList.begin (), newList.end (), [&ident = it.first](const auto& s){ return ident == s.first; }) == newList.end ()) sessions.push_back (session); } } + impliedList.clear (); } for (const auto& it : sessions) { - uint32_t tag = it->GetRelayTag (); - auto extraTime = std::min ((int)(ts - it->GetCreationTime ()), SSU2_TO_INTRODUCER_SESSION_EXPIRATION_VARIANCE); - if( extraTime > 1) - it->SetCreationTime (it->GetCreationTime () + m_Rng () % extraTime); + uint32_t tag = it->GetRelayTag (); uint32_t exp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION; - if (!tag || ts + SSU2_TO_INTRODUCER_SESSION_DURATION/2 > exp) - continue; // don't pick too old session for introducer + if (!tag && ts >= exp) + continue; // don't publish expired introducer i2p::data::RouterInfo::Introducer introducer; introducer.iTag = tag; introducer.iH = it->GetRemoteIdentity ()->GetIdentHash (); diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 93d7e8e2..2b97bd25 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -35,9 +35,8 @@ namespace transport const uint64_t SSU2_SOCKET_MAX_BUFFER_SIZE = 4 * 1024 * 1024; 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 = 3680; // 1 hour + const int SSU2_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes - const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION_VARIANCE = 120; // 2 minutes const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds @@ -160,7 +159,7 @@ namespace transport void ConnectThroughIntroducer (std::shared_ptr session); std::vector > FindIntroducers (int maxNumIntroducers, - bool v4, const std::unordered_set& excluded) const; + bool v4, const std::unordered_set& excluded); void UpdateIntroducers (bool v4); void ScheduleIntroducersUpdateTimer (); void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4); From bce9630ff804862b5bc387ac562d422e8e493f5c Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 4 Oct 2024 08:26:32 -0400 Subject: [PATCH 157/527] try to create new sessions with introducers if existing are about to expire --- libi2pd/SSU2.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 87d45d04..5f2cb0cf 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1284,6 +1284,7 @@ namespace transport if (!session) i2p::context.RemoveSSU2Introducer (ident, v4); } + int numOldSessions = 0; if (newList.size () < SSU2_MAX_NUM_INTRODUCERS) { auto sessions = FindIntroducers (SSU2_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded); @@ -1297,7 +1298,10 @@ namespace transport { if (std::find_if (newList.begin (), newList.end (), [&ident = it.first](const auto& s){ return ident == s.first; }) == newList.end ()) + { sessions.push_back (session); + numOldSessions++; + } } } impliedList.clear (); @@ -1326,9 +1330,17 @@ namespace transport } introducers = newList; - if (introducers.size () < SSU2_MAX_NUM_INTRODUCERS) + if (introducers.size () < SSU2_MAX_NUM_INTRODUCERS || numOldSessions) { - for (auto i = introducers.size (); i < SSU2_MAX_NUM_INTRODUCERS; i++) + // we need to create more sessions with relay tag + + // exclude all existing sessions + excluded.clear (); + for (const auto& [ident, s] : m_SessionsByRouterHash) + excluded.insert (ident); + + // sesssion about to expire are not counted + for (auto i = introducers.size (); i < SSU2_MAX_NUM_INTRODUCERS + numOldSessions; i++) { auto introducer = i2p::data::netdb.GetRandomSSU2Introducer (v4, excluded); if (introducer) From 4436c49cccbcd19d1db7368f261650faa11840d0 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 4 Oct 2024 11:30:56 -0400 Subject: [PATCH 158/527] temporary disable RelayResponse resend through introducer session --- libi2pd/SSU2Session.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 6ce3a5e1..bf363f1e 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2067,9 +2067,11 @@ namespace transport packet->payloadSize = CreateRelayResponseBlock (packet->payload, m_MaxPayloadSize, code, bufbe32toh (buf + 33), token, isV4); packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); - uint32_t packetNum = SendData (packet->payload, packet->payloadSize); - packet->sendTime = mts; - m_SentPackets.emplace (packetNum, packet); + /*uint32_t packetNum = */SendData (packet->payload, packet->payloadSize); + // for some reason Bob never ack this RelayResponse + // TODO: unccomend line below once the problem is resolved + //packet->sendTime = mts; + //m_SentPackets.emplace (packetNum, packet); } void SSU2Session::HandleRelayResponse (const uint8_t * buf, size_t len) From 58245bf1214f4e87dfc21b3c1b6d7210bfe02b21 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 4 Oct 2024 14:06:02 -0400 Subject: [PATCH 159/527] temporary disable RelayRespond resend from Bob because it might be not acked --- libi2pd/SSU2Session.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index bf363f1e..6213c614 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1982,6 +1982,7 @@ namespace transport packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize); packet->sendTime = mts; + // Charlie always responds with RelayResponse session->m_SentPackets.emplace (packetNum, packet); } @@ -2068,8 +2069,8 @@ namespace transport code, bufbe32toh (buf + 33), token, isV4); packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); /*uint32_t packetNum = */SendData (packet->payload, packet->payloadSize); - // for some reason Bob never ack this RelayResponse - // TODO: unccomend line below once the problem is resolved + // sometimes Bob doesn't ack this RelayResponse + // TODO: uncomment line below once the problem is resolved //packet->sendTime = mts; //m_SentPackets.emplace (packetNum, packet); } @@ -2106,9 +2107,11 @@ namespace transport memcpy (payload + 3, buf, len); // forward to Alice as is packet->payloadSize = len + 3; packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); - uint32_t packetNum = it->second.first->SendData (packet->payload, packet->payloadSize); - packet->sendTime = i2p::util::GetMillisecondsSinceEpoch (); - it->second.first->m_SentPackets.emplace (packetNum, packet); + /*uint32_t packetNum = */it->second.first->SendData (packet->payload, packet->payloadSize); + // sometimes Alice doesn't ack this RelayResponse + // TODO: uncomment line below once the problem is resolved + //packet->sendTime = i2p::util::GetMillisecondsSinceEpoch (); + //it->second.first->m_SentPackets.emplace (packetNum, packet); } else { From 0710f62948dec5d991caef70aa0021c58a6e5308 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 4 Oct 2024 20:44:58 -0400 Subject: [PATCH 160/527] fixed potential race condition --- libi2pd/SSU2.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 5f2cb0cf..1a1965e1 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1336,8 +1336,11 @@ namespace transport // exclude all existing sessions excluded.clear (); - for (const auto& [ident, s] : m_SessionsByRouterHash) - excluded.insert (ident); + { + std::lock_guard l(m_SessionsByRouterHashMutex); + for (const auto& [ident, s] : m_SessionsByRouterHash) + excluded.insert (ident); + } // sesssion about to expire are not counted for (auto i = introducers.size (); i < SSU2_MAX_NUM_INTRODUCERS + numOldSessions; i++) From e4c8cc300db80df406536ace58d51aff152403b4 Mon Sep 17 00:00:00 2001 From: r4sas Date: Sun, 6 Oct 2024 14:28:33 +0300 Subject: [PATCH 161/527] [gha] disable winxp build (it is broken in MSYS2) Signed-off-by: r4sas --- .github/workflows/build-windows.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 536d16e0..b026cc21 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -108,6 +108,7 @@ jobs: path: build/i2pd.exe build-xp: + if: false name: XP runs-on: windows-latest @@ -220,7 +221,7 @@ jobs: id: cache-boost with: path: MINGW-packages/mingw-w64-boost/*.zst - key: winxp-winpthreads-${{ steps.version-boost.outputs.version }} + key: winxp-boost-${{ steps.version-boost.outputs.version }} - name: Build WinXP-capable boost package if: steps.cache-boost.outputs.cache-hit != 'true' run: | From cc05f9c5d9d7efcdeb843b0bb6b29eb16b5caa15 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 6 Oct 2024 07:34:18 -0400 Subject: [PATCH 162/527] 2.54.0 --- ChangeLog | 38 ++++++++++++++++++++++++++++++++++++++ contrib/rpm/i2pd-git.spec | 5 ++++- contrib/rpm/i2pd.spec | 5 ++++- debian/changelog | 6 ++++++ libi2pd/version.h | 6 +++--- 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 13b8bf50..2f568e64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,44 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.54.0] - 2024-10-06 +### Added +- Maintain recently connected routers list to avoid false-positive peer test +- Limited connectivity mode(through proxy) +- "i2p.streaming.profile" tunnel's param to let tunnel select also low-bandwidth routers +- Limit stream's inbound speed +- Periodic ack requests in ratchets session +- Set congestion cap G immediately if through proxy +- Show tunnel's routers bandwidth caps in web console +- Handle immediate ack requsted flag in SSU2 data packets +- Resend and ack peer test and relay messages +- "senduseragent" HTTP proxy's param to pass through user's User-Agent +### Changed +- Exclude 'N' routers from high-bandwidth routers for client tunnels +- C++11 support has been dropped, the minimal requirement is C++17 now, C++20 for some compilers +- Removed dependency from boost::date_time and boost::filesystem +- Set default i2cp.leaseSetEncType to 0,4 and to 4 for server tunnels +- Handle i2cp.inboundlimit and i2cp.outboundlimit params in I2CP +- Publish LeaseSet with new timestamp update if tunnel was replaced in the same second +- Increase max number of generated tags to 800 per tagset +- Routing path expiration by time instead num attempts +- Save timestamp from epoch instead local time to profiles +- Update introducer's iTag if session to introducer was replaced to new one +- RTT, window size and number of NACKs calculation for streaming +- Don't select same peer for tunnel too often +- Use WinApi for data path UTF-8 conversion for Windows +### Fixed +- Jump link crash if address book is disabled +- Race condition if connect through an introducer +- "Date" header in I2PControl response +- Incomplete response from web console +- AEAD verification with LibreSSL +- Number of generated tags and new keys for follow-on tagsets +- Expired leases in LeaseSet +- Attempts to send HolePunch to 0.0.0.0 +- Incorrect options size in quick ack streaming packet +- Low bandwidth router appeared as first peer in high-bandwidth client tunnel + ## [2.53.1] - 2024-07-29 ### Changed - I2CP performance improvement diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 862c618d..6853a504 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -1,7 +1,7 @@ %define git_hash %(git rev-parse HEAD | cut -c -7) Name: i2pd-git -Version: 2.53.1 +Version: 2.54.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -148,6 +148,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Sun Oct 6 2024 orignal - 2.54.0 +- update to 2.54.0 + * Tue Jul 30 2024 orignal - 2.53.1 - update to 2.53.1 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 6b999798..ece180f0 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.53.1 +Version: 2.54.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git @@ -146,6 +146,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Sun Oct 6 2024 orignal - 2.54.0 +- update to 2.54.0 + * Tue Jul 30 2024 orignal - 2.53.1 - update to 2.53.1 diff --git a/debian/changelog b/debian/changelog index c5da4628..0fe779da 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.54.0-1) unstable; urgency=medium + + * updated to version 2.54.0/0.9.64 + +-- orignal Sun, 6 Oct 2024 16:00:00 +0000 + i2pd (2.53.1-1) unstable; urgency=medium * updated to version 2.53.1 diff --git a/libi2pd/version.h b/libi2pd/version.h index f3e487c2..40d07845 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -18,8 +18,8 @@ #define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 53 -#define I2PD_VERSION_MICRO 1 +#define I2PD_VERSION_MINOR 54 +#define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #ifdef GITVER #define I2PD_VERSION XSTRINGIZE(GITVER) @@ -33,7 +33,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 63 +#define I2P_VERSION_MICRO 64 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) #define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) From dc48fb0180fb3a4d8b45c42a77e8384fa19c85f4 Mon Sep 17 00:00:00 2001 From: r4sas Date: Sun, 6 Oct 2024 14:36:02 +0300 Subject: [PATCH 163/527] [rpm] try to fix Fedora ELN build Signed-off-by: r4sas --- contrib/rpm/i2pd-git.spec | 2 +- contrib/rpm/i2pd.spec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 6853a504..05158bc9 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -24,7 +24,7 @@ BuildRequires: openssl-devel BuildRequires: miniupnpc-devel BuildRequires: systemd-units -%if 0%{?fedora} > 40 || 0%{?eln} +%if 0%{?fedora} == 41 BuildRequires: openssl-devel-engine %endif diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index ece180f0..4b1e573b 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -22,7 +22,7 @@ BuildRequires: openssl-devel BuildRequires: miniupnpc-devel BuildRequires: systemd-units -%if 0%{?fedora} > 40 || 0%{?eln} +%if 0%{?fedora} == 41 BuildRequires: openssl-devel-engine %endif From 0d224dfc54feeb0ce959167f60473f5c4af592ef Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 6 Oct 2024 07:42:59 -0400 Subject: [PATCH 164/527] 2.54.0 --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 2f568e64..b3559fb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,7 +10,7 @@ - Periodic ack requests in ratchets session - Set congestion cap G immediately if through proxy - Show tunnel's routers bandwidth caps in web console -- Handle immediate ack requsted flag in SSU2 data packets +- Handle immediate ack requested flag in SSU2 data packets - Resend and ack peer test and relay messages - "senduseragent" HTTP proxy's param to pass through user's User-Agent ### Changed From d7c4d0ff3eeb63ab3348ba850e087fc8a8e29bfd Mon Sep 17 00:00:00 2001 From: r4sas Date: Sun, 6 Oct 2024 16:36:52 +0300 Subject: [PATCH 165/527] [gha] xp build again Signed-off-by: r4sas --- .github/workflows/build-windows.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index b026cc21..d587ba05 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -108,7 +108,6 @@ jobs: path: build/i2pd.exe build-xp: - if: false name: XP runs-on: windows-latest @@ -129,8 +128,11 @@ jobs: cache: true update: true - - name: Clone MinGW packages repository - run: git clone https://github.com/msys2/MINGW-packages + - name: Clone MinGW packages repository and revert boost to 1.85.0 + run: | + git clone https://github.com/msys2/MINGW-packages + cd MINGW-packages + git checkout 4cbb366edf2f268ac3146174b40ce38604646fc5 mingw-w64-boost # headers - name: Get headers package version @@ -212,16 +214,17 @@ jobs: run: pacman --noconfirm -U MINGW-packages/mingw-w64-openssl/mingw-w64-i686-*-any.pkg.tar.zst # Boost - - name: Get boost package version - id: version-boost - run: | - echo "version=$(pacman -Si mingw-w64-i686-boost | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT + #- name: Get boost package version + # id: version-boost + # run: | + # echo "version=$(pacman -Si mingw-w64-i686-boost | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT - name: Cache boost package uses: actions/cache@v4 id: cache-boost with: path: MINGW-packages/mingw-w64-boost/*.zst - key: winxp-boost-${{ steps.version-boost.outputs.version }} + key: winxp-boost-1.85.0+crt-${{ steps.version-headers.outputs.version }}+ossl-${{ steps.version-openssl.outputs.version }} + # Rebuild package if packages above has changed - name: Build WinXP-capable boost package if: steps.cache-boost.outputs.cache-hit != 'true' run: | From 905c6debf2a7f7e651a7916e646a2aee25ba57c7 Mon Sep 17 00:00:00 2001 From: r4sas Date: Sun, 6 Oct 2024 20:03:22 +0300 Subject: [PATCH 166/527] [win32] use boost filesystem for gcc builds Signed-off-by: r4sas --- Makefile.linux | 2 +- Makefile.mingw | 11 ++++++----- Win32/Win32NetState.cpp | 2 +- Win32/Win32NetState.h | 2 +- libi2pd/FS.cpp | 8 ++++---- libi2pd/FS.h | 4 +++- 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Makefile.linux b/Makefile.linux index 2955d301..aa67626a 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -15,7 +15,7 @@ ifeq ($(shell expr match $(CXX) 'clang'),5) NEEDED_CXXFLAGS += -std=c++17 else ifeq ($(shell expr match ${CXXVER} "7"),1) # gcc 7 NEEDED_CXXFLAGS += -std=c++17 - LDLIBS = -lboost_filesystem + LDLIBS = -lboost_filesystem else ifeq ($(shell expr match ${CXXVER} "[8-9]"),1) # gcc 8 - 9 NEEDED_CXXFLAGS += -std=c++17 LDLIBS = -lstdc++fs diff --git a/Makefile.mingw b/Makefile.mingw index 339cec4e..fc92e9b0 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -7,7 +7,7 @@ CXXFLAGS := $(CXX_DEBUG) -fPIC -msse INCFLAGS := -I$(DAEMON_SRC_DIR) -IWin32 LDFLAGS := ${LD_DEBUG} -static -fPIC -msse -NEEDED_CXXFLAGS += -std=c++17 +NEEDED_CXXFLAGS += -std=c++20 DEFINES += -DWIN32_LEAN_AND_MEAN # UPNP Support @@ -16,7 +16,12 @@ ifeq ($(USE_UPNP),yes) LDLIBS = -lminiupnpc endif +ifeq ($(USE_WINXP_FLAGS), yes) + DEFINES += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501 +endif + LDLIBS += \ + $(MINGW_PREFIX)/lib/libboost_filesystem-mt.a \ $(MINGW_PREFIX)/lib/libboost_program_options-mt.a \ $(MINGW_PREFIX)/lib/libssl.a \ $(MINGW_PREFIX)/lib/libcrypto.a \ @@ -37,10 +42,6 @@ ifeq ($(USE_WIN32_APP), yes) DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) endif -ifeq ($(USE_WINXP_FLAGS), yes) - DEFINES += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501 -endif - ifeq ($(USE_AESNI),yes) NEEDED_CXXFLAGS += -maes LDFLAGS += -maes diff --git a/Win32/Win32NetState.cpp b/Win32/Win32NetState.cpp index 095afe45..4ef768c8 100644 --- a/Win32/Win32NetState.cpp +++ b/Win32/Win32NetState.cpp @@ -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 * diff --git a/Win32/Win32NetState.h b/Win32/Win32NetState.h index 5006daad..c1f47a24 100644 --- a/Win32/Win32NetState.h +++ b/Win32/Win32NetState.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 * diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index fdfd577e..a623a4eb 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -261,13 +261,13 @@ namespace fs { #else */ // TODO: wait until implemented const auto sctp = std::chrono::time_point_cast( t - decltype(t)::clock::now() + std::chrono::system_clock::now()); -/*#endif */ - return std::chrono::system_clock::to_time_t(sctp); -#else +/*#endif */ + return std::chrono::system_clock::to_time_t(sctp); +#else boost::system::error_code ec; auto t = boost::filesystem::last_write_time (path, ec); return ec ? 0 : t; -#endif +#endif } bool Remove(const std::string & path) { diff --git a/libi2pd/FS.h b/libi2pd/FS.h index 8bf8101e..7af8f494 100644 --- a/libi2pd/FS.h +++ b/libi2pd/FS.h @@ -16,7 +16,9 @@ #include #ifndef STD_FILESYSTEM -# if (!TARGET_OS_SIMULATOR && __has_include()) // supports std::filesystem +# if (_WIN32 && __GNUG__) // MinGW GCC somehow incorrectly converts paths +# define STD_FILESYSTEM 0 +# elif (!TARGET_OS_SIMULATOR && __has_include()) // supports std::filesystem # define STD_FILESYSTEM 1 # else # define STD_FILESYSTEM 0 From 1a6109109a2cec112d618ec45b078e39984ceb66 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 6 Oct 2024 20:57:35 -0400 Subject: [PATCH 167/527] don't sample too small list of eligible introducers --- libi2pd/SSU2.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 1a1965e1..83d23dd2 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1239,8 +1239,11 @@ namespace transport (!v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V6)))) eligible.push_back (s.second); } - - std::sample (eligible.begin(), eligible.end(), std::back_inserter(ret), maxNumIntroducers, m_Rng); + + if (eligible.size () <= (size_t)maxNumIntroducers) + return eligible; + else + std::sample (eligible.begin(), eligible.end(), std::back_inserter(ret), maxNumIntroducers, m_Rng); return ret; } From 78847306e9a96a2dfabce6058aaedb90ff8a48c5 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 8 Oct 2024 13:44:25 -0400 Subject: [PATCH 168/527] use EVP_PKEY for family signature verification --- libi2pd/Family.cpp | 75 ++++++++++++++++------------------------------ libi2pd/Family.h | 6 ++-- 2 files changed, 29 insertions(+), 52 deletions(-) diff --git a/libi2pd/Family.cpp b/libi2pd/Family.cpp index 8c6d3ba4..89e825f1 100644 --- a/libi2pd/Family.cpp +++ b/libi2pd/Family.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 * @@ -7,7 +7,6 @@ */ #include -#include #include #include "Crypto.h" #include "FS.h" @@ -25,6 +24,8 @@ namespace data Families::~Families () { + for (auto it : m_SigningKeys) + if (it.second.first) EVP_PKEY_free (it.second.first); } void Families::LoadCertificate (const std::string& filename) @@ -47,48 +48,16 @@ namespace data cn += 3; char * family = strstr (cn, ".family"); if (family) family[0] = 0; - } - auto pkey = X509_get_pubkey (cert); - int keyType = EVP_PKEY_base_id (pkey); - switch (keyType) - { - case EVP_PKEY_DSA: - // TODO: - break; - case EVP_PKEY_EC: - { - EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey); - if (ecKey) + auto pkey = X509_get_pubkey (cert); + if (pkey) + { + if (!m_SigningKeys.emplace (cn, std::make_pair(pkey, (int)m_SigningKeys.size () + 1)).second) { - auto group = EC_KEY_get0_group (ecKey); - if (group) - { - int curve = EC_GROUP_get_curve_name (group); - if (curve == NID_X9_62_prime256v1) - { - uint8_t signingKey[64]; - BIGNUM * x = BN_new(), * y = BN_new(); - EC_POINT_get_affine_coordinates_GFp (group, - EC_KEY_get0_public_key (ecKey), x, y, NULL); - i2p::crypto::bn2buf (x, signingKey, 32); - i2p::crypto::bn2buf (y, signingKey + 32, 32); - BN_free (x); BN_free (y); - verifier = std::make_shared(); - verifier->SetPublicKey (signingKey); - } - else - LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); - } - EC_KEY_free (ecKey); - } - break; - } - default: - LogPrint (eLogWarning, "Family: Certificate key type ", keyType, " is not supported"); + EVP_PKEY_free (pkey); + LogPrint (eLogError, "Family: Duplicated family name ", cn); + } + } } - EVP_PKEY_free (pkey); - if (verifier && cn) - m_SigningKeys.emplace (cn, std::make_pair(verifier, (int)m_SigningKeys.size () + 1)); } SSL_free (ssl); } @@ -130,14 +99,22 @@ namespace data LogPrint (eLogError, "Family: ", family, " is too long"); return false; } - - memcpy (buf, family.c_str (), len); - memcpy (buf + len, (const uint8_t *)ident, 32); - len += 32; - Base64ToByteStream (signature, signatureLen, signatureBuf, 64); auto it = m_SigningKeys.find (family); - if (it != m_SigningKeys.end ()) - return it->second.first->Verify (buf, len, signatureBuf); + if (it != m_SigningKeys.end () && it->second.first) + { + memcpy (buf, family.c_str (), len); + memcpy (buf + len, (const uint8_t *)ident, 32); + len += 32; + auto signatureBufLen = Base64ToByteStream (signature, signatureLen, signatureBuf, 64); + if (signatureBufLen) + { + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, it->second.first); + auto ret = EVP_DigestVerify (ctx, signatureBuf, signatureBufLen, buf, len); + EVP_MD_CTX_destroy (ctx); + return ret; + } + } // TODO: process key return true; } diff --git a/libi2pd/Family.h b/libi2pd/Family.h index b19ea142..a82e3042 100644 --- a/libi2pd/Family.h +++ b/libi2pd/Family.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 * @@ -12,7 +12,7 @@ #include #include #include -#include "Signature.h" +#include #include "Identity.h" namespace i2p @@ -37,7 +37,7 @@ namespace data private: - std::map, FamilyID> > m_SigningKeys; // family -> (verifier, id) + std::map > m_SigningKeys; // family -> (verification pkey, id) }; std::string CreateFamilySignature (const std::string& family, const IdentHash& ident); From 88a5f8b125f9404fb73c7b0d1a37007101d9e6b0 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 8 Oct 2024 18:44:46 -0400 Subject: [PATCH 169/527] use EVP_PKEY for signing --- libi2pd/Family.cpp | 49 +++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/libi2pd/Family.cpp b/libi2pd/Family.cpp index 89e825f1..26750e7d 100644 --- a/libi2pd/Family.cpp +++ b/libi2pd/Family.cpp @@ -136,35 +136,30 @@ namespace data if (ret) { SSL * ssl = SSL_new (ctx); - EVP_PKEY * pkey = SSL_get_privatekey (ssl); - EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey); - if (ecKey) + auto pkey = SSL_get_privatekey (ssl); + if (pkey) { - auto group = EC_KEY_get0_group (ecKey); - if (group) + uint8_t buf[100], signature[128]; + size_t len = family.length (); + memcpy (buf, family.c_str (), len); + memcpy (buf + len, (const uint8_t *)ident, 32); + len += 32; + size_t l = 128; + EVP_MD_CTX * mdctx = EVP_MD_CTX_create (); + EVP_DigestSignInit (mdctx, NULL, NULL, NULL, pkey); + if (EVP_DigestSign (mdctx, signature, &l, buf, len)) { - int curve = EC_GROUP_get_curve_name (group); - if (curve == NID_X9_62_prime256v1) - { - uint8_t signingPrivateKey[32], buf[50], signature[64]; - i2p::crypto::bn2buf (EC_KEY_get0_private_key (ecKey), signingPrivateKey, 32); - i2p::crypto::ECDSAP256Signer signer (signingPrivateKey); - size_t len = family.length (); - memcpy (buf, family.c_str (), len); - memcpy (buf + len, (const uint8_t *)ident, 32); - len += 32; - signer.Sign (buf, len, signature); - len = Base64EncodingBufferSize (64); - char * b64 = new char[len+1]; - len = ByteStreamToBase64 (signature, 64, b64, len); - b64[len] = 0; - sig = b64; - delete[] b64; - } - else - LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); - } - } + len = Base64EncodingBufferSize (l); + char * b64 = new char[len+1]; + len = ByteStreamToBase64 (signature, l, b64, len); + b64[len] = 0; + sig = b64; + delete[] b64; + } + else + LogPrint (eLogError, "Family: signing failed"); + EVP_MD_CTX_destroy (mdctx); + } SSL_free (ssl); } else From 2321a897f5ec89ab18f8b206c7191293ece0df3d Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 9 Oct 2024 08:48:24 -0400 Subject: [PATCH 170/527] rollback --- libi2pd/Family.cpp | 49 +++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/libi2pd/Family.cpp b/libi2pd/Family.cpp index 26750e7d..89e825f1 100644 --- a/libi2pd/Family.cpp +++ b/libi2pd/Family.cpp @@ -136,30 +136,35 @@ namespace data if (ret) { SSL * ssl = SSL_new (ctx); - auto pkey = SSL_get_privatekey (ssl); - if (pkey) + EVP_PKEY * pkey = SSL_get_privatekey (ssl); + EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey); + if (ecKey) { - uint8_t buf[100], signature[128]; - size_t len = family.length (); - memcpy (buf, family.c_str (), len); - memcpy (buf + len, (const uint8_t *)ident, 32); - len += 32; - size_t l = 128; - EVP_MD_CTX * mdctx = EVP_MD_CTX_create (); - EVP_DigestSignInit (mdctx, NULL, NULL, NULL, pkey); - if (EVP_DigestSign (mdctx, signature, &l, buf, len)) + auto group = EC_KEY_get0_group (ecKey); + if (group) { - len = Base64EncodingBufferSize (l); - char * b64 = new char[len+1]; - len = ByteStreamToBase64 (signature, l, b64, len); - b64[len] = 0; - sig = b64; - delete[] b64; - } - else - LogPrint (eLogError, "Family: signing failed"); - EVP_MD_CTX_destroy (mdctx); - } + int curve = EC_GROUP_get_curve_name (group); + if (curve == NID_X9_62_prime256v1) + { + uint8_t signingPrivateKey[32], buf[50], signature[64]; + i2p::crypto::bn2buf (EC_KEY_get0_private_key (ecKey), signingPrivateKey, 32); + i2p::crypto::ECDSAP256Signer signer (signingPrivateKey); + size_t len = family.length (); + memcpy (buf, family.c_str (), len); + memcpy (buf + len, (const uint8_t *)ident, 32); + len += 32; + signer.Sign (buf, len, signature); + len = Base64EncodingBufferSize (64); + char * b64 = new char[len+1]; + len = ByteStreamToBase64 (signature, 64, b64, len); + b64[len] = 0; + sig = b64; + delete[] b64; + } + else + LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); + } + } SSL_free (ssl); } else From 23bac4a4038b7053467a53b0d4e8bb8584228de9 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 9 Oct 2024 21:40:26 -0400 Subject: [PATCH 171/527] recreate certificate if invalid --- daemon/I2PControl.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index fc7f2257..74229220 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -45,15 +45,23 @@ namespace client i2pcp_crt = i2p::fs::DataDirPath(i2pcp_crt); if (i2pcp_key.at(0) != '/') i2pcp_key = i2p::fs::DataDirPath(i2pcp_key); - if (!i2p::fs::Exists (i2pcp_crt) || !i2p::fs::Exists (i2pcp_key)) { + if (!i2p::fs::Exists (i2pcp_crt) || !i2p::fs::Exists (i2pcp_key)) + { LogPrint (eLogInfo, "I2PControl: Creating new certificate for control connection"); CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str()); - } else { + } + else LogPrint(eLogDebug, "I2PControl: Using cert from ", i2pcp_crt); - } m_SSLContext.set_options (boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); - m_SSLContext.use_certificate_file (i2pcp_crt, boost::asio::ssl::context::pem); - m_SSLContext.use_private_key_file (i2pcp_key, boost::asio::ssl::context::pem); + boost::system::error_code ec; + m_SSLContext.use_certificate_file (i2pcp_crt, boost::asio::ssl::context::pem, ec); + if (!ec) + m_SSLContext.use_private_key_file (i2pcp_key, boost::asio::ssl::context::pem, ec); + if (ec) + { + LogPrint (eLogInfo, "I2PControl: Failed to load ceritifcate: ", ec.message (), ". Recreating"); + CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str()); + } // handlers m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler; From ac4c58bbe958d5ac6f14c93cdeffd51af28277ee Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 10 Oct 2024 15:46:22 -0400 Subject: [PATCH 172/527] reload cerificate again after re-creation attempt --- daemon/I2PControl.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 74229220..43c74199 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -61,6 +61,12 @@ namespace client { LogPrint (eLogInfo, "I2PControl: Failed to load ceritifcate: ", ec.message (), ". Recreating"); CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str()); + m_SSLContext.use_certificate_file (i2pcp_crt, boost::asio::ssl::context::pem, ec); + if (!ec) + m_SSLContext.use_private_key_file (i2pcp_key, boost::asio::ssl::context::pem, ec); + if (ec) + // give up + LogPrint (eLogError, "I2PControl: Can't load certificates"); } // handlers @@ -411,7 +417,7 @@ namespace client X509_NAME_add_entry_by_txt (name, "O", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_ORGANIZATION, -1, -1, 0); // organization X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name X509_set_issuer_name (x509, name); // set issuer to ourselves - X509_sign (x509, pkey, EVP_sha1 ()); // sign + X509_sign (x509, pkey, EVP_sha1 ()); // sign, last param must be NULL for EdDSA // save cert if ((f = fopen (crt_path, "wb")) != NULL) { From c86e0ec37192ae2237d33f97938910cc4d5e4934 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 10 Oct 2024 20:43:06 -0400 Subject: [PATCH 173/527] lock queue's mutex less often --- libi2pd/Queue.h | 17 +++++++++++++++-- libi2pd/Tunnel.cpp | 30 +++++++++++++++++------------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/libi2pd/Queue.h b/libi2pd/Queue.h index 441f8c3a..daca14c2 100644 --- a/libi2pd/Queue.h +++ b/libi2pd/Queue.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 * @@ -107,8 +107,21 @@ namespace util return GetNonThreadSafe (true); } - private: + void GetWholeQueue (std::queue& queue) + { + if (!queue.empty ()) + { + std::queue newQueue; + queue.swap (newQueue); + } + { + std::unique_lock l(m_QueueMutex); + m_Queue.swap (queue); + } + } + private: + Element GetNonThreadSafe (bool peek = false) { if (!m_Queue.empty ()) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 1b63b7a7..1aa8528e 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -483,14 +483,17 @@ namespace tunnel { try { - auto msg = m_Queue.GetNextWithTimeout (1000); // 1 sec - if (msg) + std::queue > msgs; + if (m_Queue.Wait (1,0)) // 1 sec { + m_Queue.GetWholeQueue (msgs); int numMsgs = 0; uint32_t prevTunnelID = 0, tunnelID = 0; std::shared_ptr prevTunnel; - do + while (!msgs.empty ()) { + auto msg = msgs.front (); msgs.pop (); + if (!msg) continue; std::shared_ptr tunnel; uint8_t typeID = msg->GetTypeID (); switch (typeID) @@ -530,17 +533,18 @@ namespace tunnel LogPrint (eLogWarning, "Tunnel: Unexpected message type ", (int) typeID); } - msg = (numMsgs <= MAX_TUNNEL_MSGS_BATCH_SIZE) ? m_Queue.Get () : nullptr; - if (msg) - { - prevTunnelID = tunnelID; - prevTunnel = tunnel; - numMsgs++; - } - else if (tunnel) - tunnel->FlushTunnelDataMsgs (); + prevTunnelID = tunnelID; + prevTunnel = tunnel; + numMsgs++; + + if (msgs.empty ()) + { + if (numMsgs < MAX_TUNNEL_MSGS_BATCH_SIZE && !m_Queue.IsEmpty ()) + m_Queue.GetWholeQueue (msgs); // try more + else if (tunnel) + tunnel->FlushTunnelDataMsgs (); // otherwise flush last + } } - while (msg); } if (i2p::transport::transports.IsOnline()) From ab02f722af2b4355754349efda3138d4426937af Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 11 Oct 2024 11:27:36 -0400 Subject: [PATCH 174/527] print non-resolved address to log --- libi2pd_client/I2PTunnel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index ad4e14b8..5ba83e1f 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.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 * @@ -784,7 +784,7 @@ namespace client } if (!found) { - LogPrint (eLogError, "I2PTunnel: Unable to resolve to compatible address"); + LogPrint (eLogError, "I2PTunnel: Unable to resolve ", m_Address, " to compatible address"); return; } @@ -794,7 +794,7 @@ namespace client Accept (); } else - LogPrint (eLogError, "I2PTunnel: Unable to resolve server tunnel address: ", ecode.message ()); + LogPrint (eLogError, "I2PTunnel: Unable to resolve server tunnel address ", m_Address, ": ", ecode.message ()); } void I2PServerTunnel::SetAccessList (const std::set& accessList) From 4a5406b80383ca3e8dfcc3a4c6d7d454dd0d40aa Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 11 Oct 2024 13:41:37 -0400 Subject: [PATCH 175/527] lock queue's mutex less often --- libi2pd/NetDb.cpp | 13 ++++++------- libi2pd/Tunnel.cpp | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 24269015..8abcb4d2 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -122,16 +122,18 @@ namespace data uint64_t lastProfilesCleanup = i2p::util::GetMonotonicMilliseconds (), lastObsoleteProfilesCleanup = lastProfilesCleanup; int16_t profilesCleanupVariance = 0, obsoleteProfilesCleanVariance = 0; + std::queue > msgs; while (m_IsRunning) { try { - auto msg = m_Queue.GetNextWithTimeout (1000); // 1 sec - if (msg) + if (m_Queue.Wait (1,0)) // 1 sec { - int numMsgs = 0; - while (msg) + m_Queue.GetWholeQueue (msgs); + while (!msgs.empty ()) { + auto msg = msgs.front (); msgs.pop (); + if (!msg) continue; LogPrint(eLogDebug, "NetDb: Got request with type ", (int) msg->GetTypeID ()); switch (msg->GetTypeID ()) { @@ -145,9 +147,6 @@ namespace data LogPrint (eLogError, "NetDb: Unexpected message type ", (int) msg->GetTypeID ()); //i2p::HandleI2NPMessage (msg); } - if (numMsgs > 100) break; - msg = m_Queue.Get (); - numMsgs++; } } if (!m_IsRunning) break; diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 1aa8528e..37d5a9b7 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -479,11 +479,11 @@ namespace tunnel std::this_thread::sleep_for (std::chrono::seconds(1)); // wait for other parts are ready uint64_t lastTs = 0, lastPoolsTs = 0, lastMemoryPoolTs = 0; + std::queue > msgs; while (m_IsRunning) { try { - std::queue > msgs; if (m_Queue.Wait (1,0)) // 1 sec { m_Queue.GetWholeQueue (msgs); From 8210911bc5fe3975e3fe364ab9619b4a95d9c2c8 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 12 Oct 2024 17:51:26 -0400 Subject: [PATCH 176/527] use std::list and splice fr msg queue --- libi2pd/I2NPProtocol.cpp | 6 ------ libi2pd/I2NPProtocol.h | 3 ++- libi2pd/NetDb.cpp | 4 ++-- libi2pd/Queue.h | 27 ++++++++++++--------------- libi2pd/Tunnel.cpp | 6 +++--- libi2pd/Tunnel.h | 2 +- 6 files changed, 20 insertions(+), 28 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 4cceda8f..3b2c204e 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -932,14 +932,8 @@ namespace i2p void I2NPMessagesHandler::Flush () { if (!m_TunnelMsgs.empty ()) - { i2p::tunnel::tunnels.PostTunnelData (m_TunnelMsgs); - m_TunnelMsgs.clear (); - } if (!m_TunnelGatewayMsgs.empty ()) - { i2p::tunnel::tunnels.PostTunnelData (m_TunnelGatewayMsgs); - m_TunnelGatewayMsgs.clear (); - } } } diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 4e26fc94..5971ce17 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "Crypto.h" #include "I2PEndian.h" @@ -328,7 +329,7 @@ namespace tunnel private: - std::vector > m_TunnelMsgs, m_TunnelGatewayMsgs; + std::list > m_TunnelMsgs, m_TunnelGatewayMsgs; }; } diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 8abcb4d2..20b2fd42 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -122,7 +122,7 @@ namespace data uint64_t lastProfilesCleanup = i2p::util::GetMonotonicMilliseconds (), lastObsoleteProfilesCleanup = lastProfilesCleanup; int16_t profilesCleanupVariance = 0, obsoleteProfilesCleanVariance = 0; - std::queue > msgs; + std::list > msgs; while (m_IsRunning) { try @@ -132,7 +132,7 @@ namespace data m_Queue.GetWholeQueue (msgs); while (!msgs.empty ()) { - auto msg = msgs.front (); msgs.pop (); + auto msg = msgs.front (); msgs.pop_front (); if (!msg) continue; LogPrint(eLogDebug, "NetDb: Got request with type ", (int) msg->GetTypeID ()); switch (msg->GetTypeID ()) diff --git a/libi2pd/Queue.h b/libi2pd/Queue.h index daca14c2..ec62bddf 100644 --- a/libi2pd/Queue.h +++ b/libi2pd/Queue.h @@ -9,8 +9,7 @@ #ifndef QUEUE_H__ #define QUEUE_H__ -#include -#include +#include #include #include #include @@ -29,22 +28,20 @@ namespace util void Put (Element e) { std::unique_lock l(m_QueueMutex); - m_Queue.push (std::move(e)); + m_Queue.push_back (std::move(e)); m_NonEmpty.notify_one (); } - templateclass Container, typename... R> - void Put (const Container& vec) + void Put (std::list& list) { - if (!vec.empty ()) + if (!list.empty ()) { std::unique_lock l(m_QueueMutex); - for (const auto& it: vec) - m_Queue.push (std::move(it)); + m_Queue.splice (m_Queue.end (), list); m_NonEmpty.notify_one (); - } - } - + } + } + Element GetNext () { std::unique_lock l(m_QueueMutex); @@ -107,11 +104,11 @@ namespace util return GetNonThreadSafe (true); } - void GetWholeQueue (std::queue& queue) + void GetWholeQueue (std::list& queue) { if (!queue.empty ()) { - std::queue newQueue; + std::list newQueue; queue.swap (newQueue); } { @@ -128,7 +125,7 @@ namespace util { auto el = m_Queue.front (); if (!peek) - m_Queue.pop (); + m_Queue.pop_front (); return el; } return nullptr; @@ -136,7 +133,7 @@ namespace util private: - std::queue m_Queue; + std::list m_Queue; std::mutex m_QueueMutex; std::condition_variable m_NonEmpty; }; diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 37d5a9b7..ca110ccc 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -479,7 +479,7 @@ namespace tunnel std::this_thread::sleep_for (std::chrono::seconds(1)); // wait for other parts are ready uint64_t lastTs = 0, lastPoolsTs = 0, lastMemoryPoolTs = 0; - std::queue > msgs; + std::list > msgs; while (m_IsRunning) { try @@ -492,7 +492,7 @@ namespace tunnel std::shared_ptr prevTunnel; while (!msgs.empty ()) { - auto msg = msgs.front (); msgs.pop (); + auto msg = msgs.front (); msgs.pop_front (); if (!msg) continue; std::shared_ptr tunnel; uint8_t typeID = msg->GetTypeID (); @@ -830,7 +830,7 @@ namespace tunnel if (msg) m_Queue.Put (msg); } - void Tunnels::PostTunnelData (const std::vector >& msgs) + void Tunnels::PostTunnelData (std::list >& msgs) { m_Queue.Put (msgs); } diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 6b014af2..00a05386 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -229,7 +229,7 @@ namespace tunnel std::shared_ptr CreateInboundTunnel (std::shared_ptr config, std::shared_ptr pool, std::shared_ptr outboundTunnel); std::shared_ptr CreateOutboundTunnel (std::shared_ptr config, std::shared_ptr pool); void PostTunnelData (std::shared_ptr msg); - void PostTunnelData (const std::vector >& msgs); + void PostTunnelData (std::list >& msgs); // and cleanup msgs void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr tunnel); void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr tunnel); std::shared_ptr CreateTunnelPool (int numInboundHops, From fbd07a5276ee12cf3ac28e123a8e57502ad422d6 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 13 Oct 2024 19:53:40 -0400 Subject: [PATCH 177/527] SSU2Session/SSU2OutOfSession split --- libi2pd/SSU2.h | 1 + libi2pd/SSU2OutOfSession.cpp | 228 +++++++++++++++++++++++++++++++++++ libi2pd/SSU2OutOfSession.h | 57 +++++++++ libi2pd/SSU2Session.cpp | 218 +-------------------------------- libi2pd/SSU2Session.h | 43 +------ 5 files changed, 293 insertions(+), 254 deletions(-) create mode 100644 libi2pd/SSU2OutOfSession.cpp create mode 100644 libi2pd/SSU2OutOfSession.h diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 2b97bd25..09f764c6 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -17,6 +17,7 @@ #include #include "util.h" #include "SSU2Session.h" +#include "SSU2OutOfSession.h" #include "Socks5.h" namespace i2p diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp new file mode 100644 index 00000000..cf9f3f36 --- /dev/null +++ b/libi2pd/SSU2OutOfSession.cpp @@ -0,0 +1,228 @@ +/* +* 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 +*/ + +#include "Log.h" +#include "SSU2.h" +#include "SSU2OutOfSession.h" + +namespace i2p +{ +namespace transport +{ + SSU2PeerTestSession::SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID): + SSU2Session (server, nullptr, nullptr, false), + m_MsgNumReceived (0), m_NumResends (0),m_IsConnectedRecently (false), m_IsStatusChanged (false), + m_PeerTestResendTimer (server.GetService ()) + { + if (!sourceConnID) sourceConnID = ~destConnID; + if (!destConnID) destConnID = ~sourceConnID; + SetSourceConnID (sourceConnID); + SetDestConnID (destConnID); + SetState (eSSU2SessionStatePeerTest); + SetTerminationTimeout (SSU2_PEER_TEST_EXPIRATION_TIMEOUT); + } + + bool SSU2PeerTestSession::ProcessPeerTest (uint8_t * buf, size_t len) + { + // we are Alice or Charlie, msgs 5,6,7 + Header header; + memcpy (header.buf, buf, 16); + header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 24)); + header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12)); + if (header.h.type != eSSU2PeerTest) + { + LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2PeerTest); + return false; + } + if (len < 48) + { + LogPrint (eLogWarning, "SSU2: PeerTest message too short ", len); + return false; + } + uint8_t nonce[12] = {0}; + uint64_t headerX[2]; // sourceConnID, token + i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); + SetDestConnID (headerX[0]); + // decrypt and handle payload + uint8_t * payload = buf + 32; + CreateNonce (be32toh (header.h.packetNum), nonce); + uint8_t h[32]; + memcpy (h, header.buf, 16); + memcpy (h + 16, &headerX, 16); + if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32, + i2p::context.GetSSU2IntroKey (), nonce, payload, len - 48, false)) + { + LogPrint (eLogWarning, "SSU2: PeerTest AEAD verification failed "); + return false; + } + HandlePayload (payload, len - 48); + SetIsDataReceived (false); + return true; + } + + void SSU2PeerTestSession::HandlePeerTest (const uint8_t * buf, size_t len) + { + // msgs 5-7 + if (len < 8) return; + uint8_t msg = buf[0]; + if (msg <= m_MsgNumReceived) + { + LogPrint (eLogDebug, "SSU2: PeerTest msg num ", msg, " received after ", m_MsgNumReceived, ". Ignored"); + return; + } + size_t offset = 3; // points to signed data after msg + code + flag + uint32_t nonce = bufbe32toh (buf + offset + 1); // 1 - ver + switch (msg) // msg + { + case 5: // Alice from Charlie 1 + { + if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ()) + { + m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ()); + if (GetAddress ()) + { + if (!m_IsConnectedRecently) + SetRouterStatus (eRouterStatusOK); + else if (m_IsStatusChanged && GetRouterStatus () == eRouterStatusFirewalled) + SetRouterStatus (eRouterStatusUnknown); + SendPeerTest (6, buf + offset, len - offset); + } + } + else + LogPrint (eLogWarning, "SSU2: Peer test 5 nonce mismatch ", nonce, " connID=", GetSourceConnID ()); + break; + } + case 6: // Charlie from Alice + { + m_PeerTestResendTimer.cancel (); // no more msg 5 resends + if (GetAddress ()) + SendPeerTest (7, buf + offset, len - offset); + else + LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6"); + GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ()); + GetServer ().RequestRemoveSession (GetConnID ()); + break; + } + case 7: // Alice from Charlie 2 + { + m_PeerTestResendTimer.cancel (); // no more msg 6 resends + auto addr = GetAddress (); + if (addr && addr->IsV6 ()) + i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2 + GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ()); + GetServer ().RequestRemoveSession (GetConnID ()); + break; + } + default: + LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", msg); + return; + } + m_MsgNumReceived = msg; + } + + void SSU2PeerTestSession::SendPeerTest (uint8_t msg) + { + auto addr = GetAddress (); + if (!addr) return; + Header header; + uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE]; + // fill packet + header.h.connID = GetDestConnID (); // dest id + RAND_bytes (header.buf + 8, 4); // random packet num + header.h.type = eSSU2PeerTest; + header.h.flags[0] = 2; // ver + header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID + header.h.flags[2] = 0; // flag + memcpy (h, header.buf, 16); + htobuf64 (h + 16, GetSourceConnID ()); // source id + // payload + payload[0] = eSSU2BlkDateTime; + htobe16buf (payload + 1, 4); + htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); + size_t payloadSize = 7; + if (msg == 6 || msg == 7) + payloadSize += CreateAddressBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, GetRemoteEndpoint ()); + payloadSize += CreatePeerTestBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, + msg, eSSU2PeerTestCodeAccept, nullptr, m_SignedData.data (), m_SignedData.size ()); + payloadSize += CreatePaddingBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize); + // encrypt + uint8_t n[12]; + CreateNonce (be32toh (header.h.packetNum), n); + i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, addr->i, n, payload, payloadSize + 16, true); + payloadSize += 16; + header.ll[0] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 24)); + header.ll[1] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 12)); + memset (n, 0, 12); + i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16); + // send + GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ()); + } + + void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen) + { +#if __cplusplus >= 202002L // C++20 + m_SignedData.assign (signedData, signedData + signedDataLen); +#else + m_SignedData.resize (signedDataLen); + memcpy (m_SignedData.data (), signedData, signedDataLen); +#endif + SendPeerTest (msg); + // schedule resend for msgs 5 or 6 + if (msg == 5 || msg == 6) + ScheduleResend (); + } + + void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, + std::shared_ptr addr) + { + if (!addr) return; + SetAddress (addr); + SendPeerTest (msg, signedData, signedDataLen); + } + + void SSU2PeerTestSession::Connect () + { + LogPrint (eLogError, "SSU2: Can't connect peer test session"); + } + + bool SSU2PeerTestSession::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) + { + LogPrint (eLogError, "SSU2: Can't handle incoming message in peer test session"); + return false; + } + + void SSU2PeerTestSession::ScheduleResend () + { + if (m_NumResends < SSU2_PEER_TEST_MAX_NUM_RESENDS) + { + m_PeerTestResendTimer.expires_from_now (boost::posix_time::milliseconds( + SSU2_PEER_TEST_RESEND_INTERVAL + GetServer ().GetRng ()() % SSU2_PEER_TEST_RESEND_INTERVAL_VARIANCE)); + std::weak_ptr s(std::static_pointer_cast(shared_from_this ())); + m_PeerTestResendTimer.async_wait ([s](const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + auto s1 = s.lock (); + if (s1) + { + int msg = 0; + if (s1->m_MsgNumReceived < 6) + msg = (s1->m_MsgNumReceived == 5) ? 6 : 5; + if (msg) // 5 or 6 + { + s1->SendPeerTest (msg); + s1->ScheduleResend (); + } + } + } + }); + m_NumResends++; + } + } +} +} diff --git a/libi2pd/SSU2OutOfSession.h b/libi2pd/SSU2OutOfSession.h new file mode 100644 index 00000000..29a35d52 --- /dev/null +++ b/libi2pd/SSU2OutOfSession.h @@ -0,0 +1,57 @@ +/* +* 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 SSU2_OUT_OF_SESSION_H__ +#define SSU2_OUT_OF_SESSION_H__ + +#include +#include "SSU2Session.h" + +namespace i2p +{ +namespace transport +{ + const int SSU2_PEER_TEST_RESEND_INTERVAL = 3000; // in milliseconds + const int SSU2_PEER_TEST_RESEND_INTERVAL_VARIANCE = 2000; // in milliseconds + const int SSU2_PEER_TEST_MAX_NUM_RESENDS = 3; + + class SSU2PeerTestSession: public SSU2Session // for PeerTest msgs 5,6,7 + { + public: + + SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID); + + uint8_t GetMsgNumReceived () const { return m_MsgNumReceived; } + bool IsConnectedRecently () const { return m_IsConnectedRecently; } + void SetStatusChanged () { m_IsStatusChanged = true; } + + void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, + std::shared_ptr addr); + bool ProcessPeerTest (uint8_t * buf, size_t len) override; + void Connect () override; // outgoing + bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) override; // incoming + + private: + + void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen); // PeerTest message + void SendPeerTest (uint8_t msg); // send or resend m_SignedData + void HandlePeerTest (const uint8_t * buf, size_t len) override; + + void ScheduleResend (); + + private: + + uint8_t m_MsgNumReceived, m_NumResends; + bool m_IsConnectedRecently, m_IsStatusChanged; + std::vector m_SignedData; // for resends + boost::asio::deadline_timer m_PeerTestResendTimer; + }; +} +} + +#endif diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 6213c614..37d078ac 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -13,17 +13,12 @@ #include "Gzip.h" #include "NetDb.hpp" #include "SSU2.h" +#include "SSU2Session.h" namespace i2p { namespace transport { - static inline void CreateNonce (uint64_t seqn, uint8_t * nonce) - { - memset (nonce, 0, 4); - htole64buf (nonce + 4, seqn); - } - void SSU2IncompleteMessage::AttachNextFragment (const uint8_t * fragment, size_t fragmentSize) { if (msg->len + fragmentSize > msg->maxLen) @@ -3086,216 +3081,5 @@ namespace transport else if (!sent && !m_SentPackets.empty ()) // if only acks received, nothing sent and we still have something to resend Resend (i2p::util::GetMillisecondsSinceEpoch ()); // than right time to resend } - - SSU2PeerTestSession::SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID): - SSU2Session (server, nullptr, nullptr, false), - m_MsgNumReceived (0), m_NumResends (0),m_IsConnectedRecently (false), m_IsStatusChanged (false), - m_PeerTestResendTimer (server.GetService ()) - { - if (!sourceConnID) sourceConnID = ~destConnID; - if (!destConnID) destConnID = ~sourceConnID; - SetSourceConnID (sourceConnID); - SetDestConnID (destConnID); - SetState (eSSU2SessionStatePeerTest); - SetTerminationTimeout (SSU2_PEER_TEST_EXPIRATION_TIMEOUT); - } - - bool SSU2PeerTestSession::ProcessPeerTest (uint8_t * buf, size_t len) - { - // we are Alice or Charlie, msgs 5,6,7 - Header header; - memcpy (header.buf, buf, 16); - header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 24)); - header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12)); - if (header.h.type != eSSU2PeerTest) - { - LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2PeerTest); - return false; - } - if (len < 48) - { - LogPrint (eLogWarning, "SSU2: PeerTest message too short ", len); - return false; - } - uint8_t nonce[12] = {0}; - uint64_t headerX[2]; // sourceConnID, token - i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); - SetDestConnID (headerX[0]); - // decrypt and handle payload - uint8_t * payload = buf + 32; - CreateNonce (be32toh (header.h.packetNum), nonce); - uint8_t h[32]; - memcpy (h, header.buf, 16); - memcpy (h + 16, &headerX, 16); - if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32, - i2p::context.GetSSU2IntroKey (), nonce, payload, len - 48, false)) - { - LogPrint (eLogWarning, "SSU2: PeerTest AEAD verification failed "); - return false; - } - HandlePayload (payload, len - 48); - SetIsDataReceived (false); - return true; - } - - void SSU2PeerTestSession::HandlePeerTest (const uint8_t * buf, size_t len) - { - // msgs 5-7 - if (len < 8) return; - uint8_t msg = buf[0]; - if (msg <= m_MsgNumReceived) - { - LogPrint (eLogDebug, "SSU2: PeerTest msg num ", msg, " received after ", m_MsgNumReceived, ". Ignored"); - return; - } - size_t offset = 3; // points to signed data after msg + code + flag - uint32_t nonce = bufbe32toh (buf + offset + 1); // 1 - ver - switch (msg) // msg - { - case 5: // Alice from Charlie 1 - { - if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ()) - { - m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ()); - if (GetAddress ()) - { - if (!m_IsConnectedRecently) - SetRouterStatus (eRouterStatusOK); - else if (m_IsStatusChanged && GetRouterStatus () == eRouterStatusFirewalled) - SetRouterStatus (eRouterStatusUnknown); - SendPeerTest (6, buf + offset, len - offset); - } - } - else - LogPrint (eLogWarning, "SSU2: Peer test 5 nonce mismatch ", nonce, " connID=", GetSourceConnID ()); - break; - } - case 6: // Charlie from Alice - { - m_PeerTestResendTimer.cancel (); // no more msg 5 resends - if (GetAddress ()) - SendPeerTest (7, buf + offset, len - offset); - else - LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6"); - GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ()); - GetServer ().RequestRemoveSession (GetConnID ()); - break; - } - case 7: // Alice from Charlie 2 - { - m_PeerTestResendTimer.cancel (); // no more msg 6 resends - auto addr = GetAddress (); - if (addr && addr->IsV6 ()) - i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2 - GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ()); - GetServer ().RequestRemoveSession (GetConnID ()); - break; - } - default: - LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", msg); - return; - } - m_MsgNumReceived = msg; - } - - void SSU2PeerTestSession::SendPeerTest (uint8_t msg) - { - auto addr = GetAddress (); - if (!addr) return; - Header header; - uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE]; - // fill packet - header.h.connID = GetDestConnID (); // dest id - RAND_bytes (header.buf + 8, 4); // random packet num - header.h.type = eSSU2PeerTest; - header.h.flags[0] = 2; // ver - header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID - header.h.flags[2] = 0; // flag - memcpy (h, header.buf, 16); - htobuf64 (h + 16, GetSourceConnID ()); // source id - // payload - payload[0] = eSSU2BlkDateTime; - htobe16buf (payload + 1, 4); - htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); - size_t payloadSize = 7; - if (msg == 6 || msg == 7) - payloadSize += CreateAddressBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, GetRemoteEndpoint ()); - payloadSize += CreatePeerTestBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, - msg, eSSU2PeerTestCodeAccept, nullptr, m_SignedData.data (), m_SignedData.size ()); - payloadSize += CreatePaddingBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize); - // encrypt - uint8_t n[12]; - CreateNonce (be32toh (header.h.packetNum), n); - i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, addr->i, n, payload, payloadSize + 16, true); - payloadSize += 16; - header.ll[0] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 24)); - header.ll[1] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 12)); - memset (n, 0, 12); - i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16); - // send - GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ()); - } - - void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen) - { -#if __cplusplus >= 202002L // C++20 - m_SignedData.assign (signedData, signedData + signedDataLen); -#else - m_SignedData.resize (signedDataLen); - memcpy (m_SignedData.data (), signedData, signedDataLen); -#endif - SendPeerTest (msg); - // schedule resend for msgs 5 or 6 - if (msg == 5 || msg == 6) - ScheduleResend (); - } - - void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, - std::shared_ptr addr) - { - if (!addr) return; - SetAddress (addr); - SendPeerTest (msg, signedData, signedDataLen); - } - - void SSU2PeerTestSession::Connect () - { - LogPrint (eLogError, "SSU2: Can't connect peer test session"); - } - - bool SSU2PeerTestSession::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) - { - LogPrint (eLogError, "SSU2: Can't handle incoming message in peer test session"); - return false; - } - - void SSU2PeerTestSession::ScheduleResend () - { - if (m_NumResends < SSU2_PEER_TEST_MAX_NUM_RESENDS) - { - m_PeerTestResendTimer.expires_from_now (boost::posix_time::milliseconds( - SSU2_PEER_TEST_RESEND_INTERVAL + GetServer ().GetRng ()() % SSU2_PEER_TEST_RESEND_INTERVAL_VARIANCE)); - std::weak_ptr s(std::static_pointer_cast(shared_from_this ())); - m_PeerTestResendTimer.async_wait ([s](const boost::system::error_code& ecode) - { - if (ecode != boost::asio::error::operation_aborted) - { - auto s1 = s.lock (); - if (s1) - { - int msg = 0; - if (s1->m_MsgNumReceived < 6) - msg = (s1->m_MsgNumReceived == 5) ? 6 : 5; - if (msg) // 5 or 6 - { - s1->SendPeerTest (msg); - s1->ScheduleResend (); - } - } - } - }); - m_NumResends++; - } - } } } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 49bd3be6..f0b6d7e6 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -390,43 +390,6 @@ namespace transport std::unordered_map m_ReceivedI2NPMsgIDs; // msgID -> timestamp in seconds uint64_t m_LastResendTime, m_LastResendAttemptTime; // in milliseconds }; - - - const int SSU2_PEER_TEST_RESEND_INTERVAL = 3000; // in milliseconds - const int SSU2_PEER_TEST_RESEND_INTERVAL_VARIANCE = 2000; // in milliseconds - const int SSU2_PEER_TEST_MAX_NUM_RESENDS = 3; - - class SSU2PeerTestSession: public SSU2Session // for PeerTest msgs 5,6,7 - { - public: - - SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID); - - uint8_t GetMsgNumReceived () const { return m_MsgNumReceived; } - bool IsConnectedRecently () const { return m_IsConnectedRecently; } - void SetStatusChanged () { m_IsStatusChanged = true; } - - void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, - std::shared_ptr addr); - bool ProcessPeerTest (uint8_t * buf, size_t len) override; - void Connect () override; // outgoing - bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) override; // incoming - - private: - - void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen); // PeerTest message - void SendPeerTest (uint8_t msg); // send or resend m_SignedData - void HandlePeerTest (const uint8_t * buf, size_t len) override; - - void ScheduleResend (); - - private: - - uint8_t m_MsgNumReceived, m_NumResends; - bool m_IsConnectedRecently, m_IsStatusChanged; - std::vector m_SignedData; // for resends - boost::asio::deadline_timer m_PeerTestResendTimer; - }; inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) { @@ -434,6 +397,12 @@ namespace transport i2p::crypto::ChaCha20 ((uint8_t *)&data, 8, kh, nonce, (uint8_t *)&data); return data; } + + inline void CreateNonce (uint64_t seqn, uint8_t * nonce) + { + memset (nonce, 0, 4); + htole64buf (nonce + 4, seqn); + } } } From 48f7131a7dc6d2f6b0eac98fba4d4d45eba52bd0 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Oct 2024 18:55:41 -0400 Subject: [PATCH 178/527] received packets queue --- libi2pd/SSU2.cpp | 61 +++++++++++++++++++++++++++++++++++------------- libi2pd/SSU2.h | 9 ++++--- 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 83d23dd2..96658db5 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -157,6 +157,10 @@ namespace transport m_IntroducersV6.clear (); m_ConnectedRecently.clear (); m_RequestedPeerTests.clear (); + + for (auto it: m_ReceivedPacketsQueue) + m_PacketsArrayPool.ReleaseMt (it); + m_ReceivedPacketsQueue.clear (); } void SSU2Server::SetLocalAddress (const boost::asio::ip::address& localAddress) @@ -398,10 +402,25 @@ namespace transport break; } } - GetService ().post (std::bind (&SSU2Server::HandleReceivedPackets, this, packets)); + InsertToReceivedPacketsQueue (packets); } else - GetService ().post (std::bind (&SSU2Server::HandleReceivedPacket, this, packet)); + { + bool added = false; + { + // try to add single packet to existing packets array in queue + std::lock_guard l(m_ReceivedPacketsQueueMutex); + if (!m_ReceivedPacketsQueue.empty ()) + added = m_ReceivedPacketsQueue.back ()->AddPacket (packet); + } + if (!added) + { + // create new packets array for single packet + auto packets = m_PacketsArrayPool.AcquireMt (); + packets->AddPacket (packet); + InsertToReceivedPacketsQueue (packets); + } + } Receive (socket); } else @@ -428,20 +447,6 @@ namespace transport } } - void SSU2Server::HandleReceivedPacket (Packet * packet) - { - if (packet) - { - if (m_IsThroughProxy) - ProcessNextPacketFromProxy (packet->buf, packet->len); - else - ProcessNextPacket (packet->buf, packet->len, packet->from); - m_PacketsPool.ReleaseMt (packet); - if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) - m_LastSession->FlushData (); - } - } - void SSU2Server::HandleReceivedPackets (Packets * packets) { if (!packets) return; @@ -463,6 +468,30 @@ namespace transport m_LastSession->FlushData (); } + void SSU2Server::InsertToReceivedPacketsQueue (Packets * packets) + { + if (!packets) return; + bool empty = false; + { + std::lock_guard l(m_ReceivedPacketsQueueMutex); + empty = m_ReceivedPacketsQueue.empty (); + m_ReceivedPacketsQueue.push_back (packets); + } + if (empty) + { + GetService ().post([this]() + { + std::list receivedPackets; + { + std::lock_guard l(m_ReceivedPacketsQueueMutex); + m_ReceivedPacketsQueue.swap (receivedPackets); + } + for (auto it: receivedPackets) + HandleReceivedPackets (it); + }); + } + } + void SSU2Server::AddSession (std::shared_ptr session) { if (session) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 09f764c6..494c11c6 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,7 @@ namespace transport return true; } return false; - } + } }; class ReceiveService: public i2p::util::RunnableService @@ -145,10 +146,10 @@ namespace transport void Receive (boost::asio::ip::udp::socket& socket); void HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred, Packet * packet, boost::asio::ip::udp::socket& socket); - void HandleReceivedPacket (Packet * packet); void HandleReceivedPackets (Packets * packets); void ProcessNextPacket (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); - + void InsertToReceivedPacketsQueue (Packets * packets); + void ScheduleTermination (); void HandleTerminationTimer (const boost::system::error_code& ecode); @@ -206,6 +207,8 @@ namespace transport std::mt19937 m_Rng; std::map m_ConnectedRecently; // endpoint -> last activity time in seconds std::unordered_map, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp) + std::list m_ReceivedPacketsQueue; + mutable std::mutex m_ReceivedPacketsQueueMutex; // proxy bool m_IsThroughProxy; From 4e581af3ba7de4ee144c1e7f253eb23f20af092d Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Oct 2024 21:21:07 -0400 Subject: [PATCH 179/527] plain list of received packets in queue --- libi2pd/SSU2.cpp | 72 ++++++++++++++---------------------------------- libi2pd/SSU2.h | 23 +++------------- 2 files changed, 24 insertions(+), 71 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 96658db5..f971e250 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -158,8 +158,7 @@ namespace transport m_ConnectedRecently.clear (); m_RequestedPeerTests.clear (); - for (auto it: m_ReceivedPacketsQueue) - m_PacketsArrayPool.ReleaseMt (it); + m_PacketsPool.ReleaseMt (m_ReceivedPacketsQueue); m_ReceivedPacketsQueue.clear (); } @@ -368,28 +367,23 @@ namespace transport return; } packet->len = bytes_transferred; + InsertToReceivedPacketsQueue (packet); + size_t numPackets = 1; boost::system::error_code ec; size_t moreBytes = socket.available (ec); if (!ec && moreBytes) { - auto packets = m_PacketsArrayPool.AcquireMt (); - packets->AddPacket (packet); - while (moreBytes && packets->numPackets < SSU2_MAX_NUM_PACKETS_PER_BATCH) - { + do + { packet = m_PacketsPool.AcquireMt (); packet->len = socket.receive_from (boost::asio::buffer (packet->buf, SSU2_MAX_PACKET_SIZE), packet->from, 0, ec); if (!ec) { i2p::transport::transports.UpdateReceivedBytes (packet->len); + numPackets++; if (packet->len >= SSU2_MIN_RECEIVED_PACKET_SIZE) - { - if (!packets->AddPacket (packet)) - { - LogPrint (eLogError, "SSU2: Received packets array is full"); - m_PacketsPool.ReleaseMt (packet); - } - } + InsertToReceivedPacketsQueue (packet); else // drop too short packets m_PacketsPool.ReleaseMt (packet); moreBytes = socket.available(ec); @@ -402,25 +396,8 @@ namespace transport break; } } - InsertToReceivedPacketsQueue (packets); + while (moreBytes && numPackets < SSU2_MAX_NUM_PACKETS_PER_BATCH); } - else - { - bool added = false; - { - // try to add single packet to existing packets array in queue - std::lock_guard l(m_ReceivedPacketsQueueMutex); - if (!m_ReceivedPacketsQueue.empty ()) - added = m_ReceivedPacketsQueue.back ()->AddPacket (packet); - } - if (!added) - { - // create new packets array for single packet - auto packets = m_PacketsArrayPool.AcquireMt (); - packets->AddPacket (packet); - InsertToReceivedPacketsQueue (packets); - } - } Receive (socket); } else @@ -447,47 +424,39 @@ namespace transport } } - void SSU2Server::HandleReceivedPackets (Packets * packets) + void SSU2Server::HandleReceivedPackets (std::list&& packets) { - if (!packets) return; + if (packets.empty ()) return; if (m_IsThroughProxy) - for (size_t i = 0; i < packets->numPackets; i++) - { - auto& packet = (*packets)[i]; - ProcessNextPacketFromProxy (packet->buf, packet->len); - } + for (auto it: packets) + ProcessNextPacketFromProxy (it->buf, it->len); else - for (size_t i = 0; i < packets->numPackets; i++) - { - auto& packet = (*packets)[i]; - ProcessNextPacket (packet->buf, packet->len, packet->from); - } - m_PacketsPool.ReleaseMt (packets->data (), packets->numPackets); - m_PacketsArrayPool.ReleaseMt (packets); + for (auto it: packets) + ProcessNextPacket (it->buf, it->len, it->from); + m_PacketsPool.ReleaseMt (packets); if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) m_LastSession->FlushData (); } - void SSU2Server::InsertToReceivedPacketsQueue (Packets * packets) + void SSU2Server::InsertToReceivedPacketsQueue (Packet * packet) { - if (!packets) return; + if (!packet) return; bool empty = false; { std::lock_guard l(m_ReceivedPacketsQueueMutex); empty = m_ReceivedPacketsQueue.empty (); - m_ReceivedPacketsQueue.push_back (packets); + m_ReceivedPacketsQueue.push_back (packet); } if (empty) { GetService ().post([this]() { - std::list receivedPackets; + std::list receivedPackets; { std::lock_guard l(m_ReceivedPacketsQueueMutex); m_ReceivedPacketsQueue.swap (receivedPackets); } - for (auto it: receivedPackets) - HandleReceivedPackets (it); + HandleReceivedPackets (std::move (receivedPackets)); }); } } @@ -1167,7 +1136,6 @@ namespace transport } m_PacketsPool.CleanUpMt (); - m_PacketsArrayPool.CleanUpMt (); m_SentPacketsPool.CleanUp (); m_IncompleteMessagesPool.CleanUp (); m_FragmentsPool.CleanUp (); diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 494c11c6..7a02730b 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -43,7 +43,7 @@ namespace transport const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds const int SSU2_HOLE_PUNCH_EXPIRATION = 150; // in seconds - const size_t SSU2_MAX_NUM_PACKETS_PER_BATCH = 32; + const size_t SSU2_MAX_NUM_PACKETS_PER_BATCH = 64; class SSU2Server: private i2p::util::RunnableServiceWithWork { @@ -53,20 +53,6 @@ namespace transport size_t len; boost::asio::ip::udp::endpoint from; }; - - struct Packets: public std::array - { - size_t numPackets = 0; - bool AddPacket (Packet *p) - { - if (p && numPackets < size ()) - { - data()[numPackets] = p; numPackets++; - return true; - } - return false; - } - }; class ReceiveService: public i2p::util::RunnableService { @@ -146,9 +132,9 @@ namespace transport void Receive (boost::asio::ip::udp::socket& socket); void HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred, Packet * packet, boost::asio::ip::udp::socket& socket); - void HandleReceivedPackets (Packets * packets); + void HandleReceivedPackets (std::list&& packets); void ProcessNextPacket (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); - void InsertToReceivedPacketsQueue (Packets * packets); + void InsertToReceivedPacketsQueue (Packet * packet); void ScheduleTermination (); void HandleTerminationTimer (const boost::system::error_code& ecode); @@ -193,7 +179,6 @@ namespace transport std::unordered_map, uint64_t > > m_PeerTests; // nonce->(Alice, timestamp). We are Bob std::list > m_Introducers, m_IntroducersV6; // introducers we are connected to i2p::util::MemoryPoolMt m_PacketsPool; - i2p::util::MemoryPoolMt m_PacketsArrayPool; i2p::util::MemoryPool m_SentPacketsPool; i2p::util::MemoryPool m_IncompleteMessagesPool; i2p::util::MemoryPool m_FragmentsPool; @@ -207,7 +192,7 @@ namespace transport std::mt19937 m_Rng; std::map m_ConnectedRecently; // endpoint -> last activity time in seconds std::unordered_map, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp) - std::list m_ReceivedPacketsQueue; + std::list m_ReceivedPacketsQueue; mutable std::mutex m_ReceivedPacketsQueueMutex; // proxy From 7104d334fddbebc7d85150553c207ef0269809fa Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Oct 2024 22:29:55 -0400 Subject: [PATCH 180/527] Do not increase the window size if the speed limit is reached when it is limited --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index c30c5d39..6a91e33f 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1225,7 +1225,7 @@ namespace stream m_NumPacketsToSend = ((ts*1000 - m_LastSendTime*1000) + m_PacingTimeRem) / m_PacingTime; m_PacingTimeRem = ((ts*1000 - m_LastSendTime*1000) + m_PacingTimeRem) - (m_NumPacketsToSend * m_PacingTime); m_IsSendTime = true; - if (m_WindowIncCounter && m_WindowSize < MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty ()) + if (m_WindowIncCounter && m_WindowSize < MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) { for (int i = 0; i < m_NumPacketsToSend; i++) { From ec1f41b13cef0cef17936bbd6210b9c885d88b91 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 15 Oct 2024 15:05:18 -0400 Subject: [PATCH 181/527] insert multiple packets to the queue using splice --- libi2pd/SSU2.cpp | 48 +++++++++++++++++++++++++++++++----------------- libi2pd/SSU2.h | 2 ++ 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index f971e250..574aea55 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -367,23 +367,22 @@ namespace transport return; } packet->len = bytes_transferred; - InsertToReceivedPacketsQueue (packet); - - size_t numPackets = 1; + boost::system::error_code ec; size_t moreBytes = socket.available (ec); if (!ec && moreBytes) { - do + std::list packets; + packets.push_back (packet); + while (moreBytes && packets.size () < SSU2_MAX_NUM_PACKETS_PER_BATCH) { packet = m_PacketsPool.AcquireMt (); packet->len = socket.receive_from (boost::asio::buffer (packet->buf, SSU2_MAX_PACKET_SIZE), packet->from, 0, ec); if (!ec) { i2p::transport::transports.UpdateReceivedBytes (packet->len); - numPackets++; if (packet->len >= SSU2_MIN_RECEIVED_PACKET_SIZE) - InsertToReceivedPacketsQueue (packet); + packets.push_back (packet); else // drop too short packets m_PacketsPool.ReleaseMt (packet); moreBytes = socket.available(ec); @@ -396,8 +395,10 @@ namespace transport break; } } - while (moreBytes && numPackets < SSU2_MAX_NUM_PACKETS_PER_BATCH); + InsertToReceivedPacketsQueue (packets); } + else + InsertToReceivedPacketsQueue (packet); Receive (socket); } else @@ -448,17 +449,30 @@ namespace transport m_ReceivedPacketsQueue.push_back (packet); } if (empty) + GetService ().post([this]() { HandleReceivedPacketsQueue (); }); + } + + void SSU2Server::InsertToReceivedPacketsQueue (std::list& packets) + { + if (packets.empty ()) return; + bool empty = false; { - GetService ().post([this]() - { - std::list receivedPackets; - { - std::lock_guard l(m_ReceivedPacketsQueueMutex); - m_ReceivedPacketsQueue.swap (receivedPackets); - } - HandleReceivedPackets (std::move (receivedPackets)); - }); - } + std::lock_guard l(m_ReceivedPacketsQueueMutex); + empty = m_ReceivedPacketsQueue.empty (); + m_ReceivedPacketsQueue.splice (m_ReceivedPacketsQueue.end (), packets); + } + if (empty) + GetService ().post([this]() { HandleReceivedPacketsQueue (); }); + } + + void SSU2Server::HandleReceivedPacketsQueue () + { + std::list receivedPackets; + { + std::lock_guard l(m_ReceivedPacketsQueueMutex); + m_ReceivedPacketsQueue.swap (receivedPackets); + } + HandleReceivedPackets (std::move (receivedPackets)); } void SSU2Server::AddSession (std::shared_ptr session) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 7a02730b..426c6a10 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -135,6 +135,8 @@ namespace transport void HandleReceivedPackets (std::list&& packets); void ProcessNextPacket (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void InsertToReceivedPacketsQueue (Packet * packet); + void InsertToReceivedPacketsQueue (std::list& packets); + void HandleReceivedPacketsQueue (); void ScheduleTermination (); void HandleTerminationTimer (const boost::system::error_code& ecode); From 97fdedfbe393ef2ce2195960d72bd0b5fe339413 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Oct 2024 08:28:25 -0400 Subject: [PATCH 182/527] implement SSU2HolPunchSession --- libi2pd/SSU2.cpp | 11 +++++-- libi2pd/SSU2OutOfSession.cpp | 58 ++++++++++++++++++++++++++++++++++++ libi2pd/SSU2OutOfSession.h | 15 ++++++++++ libi2pd/SSU2Session.cpp | 48 +++-------------------------- libi2pd/SSU2Session.h | 5 ++-- 5 files changed, 88 insertions(+), 49 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 574aea55..e96a7233 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -479,9 +479,11 @@ namespace transport { if (session) { - m_Sessions.emplace (session->GetConnID (), session); - if (session->GetState () != eSSU2SessionStatePeerTest) - AddSessionByRouterHash (session); + if (m_Sessions.emplace (session->GetConnID (), session).second) + { + if (session->GetState () != eSSU2SessionStatePeerTest) + AddSessionByRouterHash (session); + } } } @@ -715,6 +717,9 @@ namespace transport m_LastSession->SetRemoteEndpoint (senderEndpoint); m_LastSession->ProcessPeerTest (buf, len); break; + case eSSU2SessionStateHolePunch: + m_LastSession->ProcessFirstIncomingMessage (connID, buf, len); // SessionRequest + break; case eSSU2SessionStateClosing: m_LastSession->ProcessData (buf, len, senderEndpoint); // we might receive termintaion block if (m_LastSession && m_LastSession->GetState () == eSSU2SessionStateClosing) diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index cf9f3f36..574ad75b 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -224,5 +224,63 @@ namespace transport m_NumResends++; } } + + SSU2HolePunchSession::SSU2HolePunchSession (SSU2Server& server, uint32_t nonce, + const boost::asio::ip::udp::endpoint& remoteEndpoint, + std::shared_ptr localAddr): + SSU2Session (server), // we create full incoming session + m_Nonce (nonce) + { + // we are Charlie + m_Token = GetServer ().GetIncomingToken (remoteEndpoint); + uint64_t destConnID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id + uint32_t sourceConnID = ~destConnID; + SetSourceConnID (sourceConnID); + SetDestConnID (destConnID); + SetState (eSSU2SessionStateHolePunch); + SetRemoteEndpoint (remoteEndpoint); + SetAddress (localAddr); + SetTerminationTimeout (SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT); + } + + void SSU2HolePunchSession::SendHolePunch () + { + auto addr = GetAddress (); + if (!addr) return; + auto& ep = GetRemoteEndpoint (); + LogPrint (eLogDebug, "SSU2: Sending HolePunch to ", ep); + Header header; + uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE]; + // fill packet + header.h.connID = GetDestConnID (); // dest id + RAND_bytes (header.buf + 8, 4); // random packet num + header.h.type = eSSU2HolePunch; + header.h.flags[0] = 2; // ver + header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID + header.h.flags[2] = 0; // flag + memcpy (h, header.buf, 16); + htobuf64 (h + 16, GetSourceConnID ()); // source id + RAND_bytes (h + 24, 8); // header token, to be ignored by Alice + // payload + payload[0] = eSSU2BlkDateTime; + htobe16buf (payload + 1, 4); + htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); + size_t payloadSize = 7; + payloadSize += CreateAddressBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, ep); + payloadSize += CreateRelayResponseBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, + eSSU2RelayResponseCodeAccept, m_Nonce, m_Token, ep.address ().is_v4 ()); + payloadSize += CreatePaddingBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize); + // encrypt + uint8_t n[12]; + CreateNonce (be32toh (header.h.packetNum), n); + i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, addr->i, n, payload, payloadSize + 16, true); + payloadSize += 16; + header.ll[0] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 24)); + header.ll[1] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 12)); + memset (n, 0, 12); + i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16); + // send + GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep); + } } } diff --git a/libi2pd/SSU2OutOfSession.h b/libi2pd/SSU2OutOfSession.h index 29a35d52..d0d944d1 100644 --- a/libi2pd/SSU2OutOfSession.h +++ b/libi2pd/SSU2OutOfSession.h @@ -51,6 +51,21 @@ namespace transport std::vector m_SignedData; // for resends boost::asio::deadline_timer m_PeerTestResendTimer; }; + + class SSU2HolePunchSession: public SSU2Session // Charlie + { + public: + + SSU2HolePunchSession (SSU2Server& server, uint32_t nonce, const boost::asio::ip::udp::endpoint& remoteEndpoint, + std::shared_ptr localAddr); + + void SendHolePunch (); + + private: + + uint32_t m_Nonce; + uint64_t m_Token; // for RelayResponse block + }; } } diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 37d078ac..958f7536 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1352,46 +1352,6 @@ namespace transport return true; } - void SSU2Session::SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, - const uint8_t * introKey, uint64_t token) - { - // we are Charlie - LogPrint (eLogDebug, "SSU2: Sending HolePunch to ", ep); - Header header; - uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE]; - // fill packet - header.h.connID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id - RAND_bytes (header.buf + 8, 4); // random packet num - header.h.type = eSSU2HolePunch; - header.h.flags[0] = 2; // ver - header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID - header.h.flags[2] = 0; // flag - memcpy (h, header.buf, 16); - uint64_t c = ~header.h.connID; - memcpy (h + 16, &c, 8); // source id - RAND_bytes (h + 24, 8); // token - // payload - payload[0] = eSSU2BlkDateTime; - htobe16buf (payload + 1, 4); - htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); - size_t payloadSize = 7; - payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, ep); - payloadSize += CreateRelayResponseBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, - eSSU2RelayResponseCodeAccept, nonce, token, ep.address ().is_v4 ()); - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - // encrypt - uint8_t n[12]; - CreateNonce (be32toh (header.h.packetNum), n); - i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, introKey, n, payload, payloadSize + 16, true); - payloadSize += 16; - header.ll[0] ^= CreateHeaderMask (introKey, payload + (payloadSize - 24)); - header.ll[1] ^= CreateHeaderMask (introKey, payload + (payloadSize - 12)); - memset (n, 0, 12); - i2p::crypto::ChaCha20 (h + 16, 16, introKey, n, h + 16); - // send - m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep); - } - bool SSU2Session::ProcessHolePunch (uint8_t * buf, size_t len) { // we are Alice @@ -1984,7 +1944,6 @@ namespace transport void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len, int attempts) { // we are Charlie - auto mts = i2p::util::GetMillisecondsSinceEpoch (); SSU2RelayResponseCode code = eSSU2RelayResponseCodeAccept; uint64_t token = 0; bool isV4 = false; @@ -2011,10 +1970,11 @@ namespace transport { if (m_Server.IsSupported (ep.address ())) { - token = m_Server.GetIncomingToken (ep); isV4 = ep.address ().is_v4 (); - SendHolePunch (bufbe32toh (buf + 33), ep, addr->i, token); - m_Server.AddConnectedRecently (ep, mts/1000); + auto holePunchSession = std::make_shared( + m_Server, bufbe32toh (buf + 33), ep, addr); + m_Server.AddSession (holePunchSession); + holePunchSession->SendHolePunch (); } else { diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index f0b6d7e6..b3b81b4d 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -112,6 +112,7 @@ namespace transport eSSU2SessionStateTerminated, eSSU2SessionStateFailed, eSSU2SessionStateIntroduced, + eSSU2SessionStateHolePunch, eSSU2SessionStatePeerTest, eSSU2SessionStateTokenRequestReceived }; @@ -295,6 +296,8 @@ namespace transport size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); + + size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4); private: @@ -320,7 +323,6 @@ namespace transport uint32_t SendData (const uint8_t * buf, size_t len, uint8_t flags = 0); // returns packet num void SendQuickAck (); void SendTermination (); - void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey, uint64_t token); void SendPathResponse (const uint8_t * data, size_t len); void SendPathChallenge (); @@ -352,7 +354,6 @@ namespace transport size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg); size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg, uint8_t& fragmentNum, uint32_t msgID); size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen); - size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice size_t CreateTerminationBlock (uint8_t * buf, size_t len); From d69e957213f4ce3d7fd977fba42f73f6a60403cc Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Oct 2024 09:04:35 -0400 Subject: [PATCH 183/527] rollback --- libi2pd/SSU2Session.cpp | 47 +++++++++++++++++++++++++++++++++++++---- libi2pd/SSU2Session.h | 2 ++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 958f7536..f68231db 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1352,6 +1352,46 @@ namespace transport return true; } + void SSU2Session::SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, + const uint8_t * introKey, uint64_t token) + { + // we are Charlie + LogPrint (eLogDebug, "SSU2: Sending HolePunch to ", ep); + Header header; + uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE]; + // fill packet + header.h.connID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id + RAND_bytes (header.buf + 8, 4); // random packet num + header.h.type = eSSU2HolePunch; + header.h.flags[0] = 2; // ver + header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID + header.h.flags[2] = 0; // flag + memcpy (h, header.buf, 16); + uint64_t c = ~header.h.connID; + memcpy (h + 16, &c, 8); // source id + RAND_bytes (h + 24, 8); // token + // payload + payload[0] = eSSU2BlkDateTime; + htobe16buf (payload + 1, 4); + htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); + size_t payloadSize = 7; + payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, ep); + payloadSize += CreateRelayResponseBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, + eSSU2RelayResponseCodeAccept, nonce, token, ep.address ().is_v4 ()); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); + // encrypt + uint8_t n[12]; + CreateNonce (be32toh (header.h.packetNum), n); + i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, introKey, n, payload, payloadSize + 16, true); + payloadSize += 16; + header.ll[0] ^= CreateHeaderMask (introKey, payload + (payloadSize - 24)); + header.ll[1] ^= CreateHeaderMask (introKey, payload + (payloadSize - 12)); + memset (n, 0, 12); + i2p::crypto::ChaCha20 (h + 16, 16, introKey, n, h + 16); + // send + m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep); + } + bool SSU2Session::ProcessHolePunch (uint8_t * buf, size_t len) { // we are Alice @@ -1970,11 +2010,10 @@ namespace transport { if (m_Server.IsSupported (ep.address ())) { + token = m_Server.GetIncomingToken (ep); isV4 = ep.address ().is_v4 (); - auto holePunchSession = std::make_shared( - m_Server, bufbe32toh (buf + 33), ep, addr); - m_Server.AddSession (holePunchSession); - holePunchSession->SendHolePunch (); + SendHolePunch (bufbe32toh (buf + 33), ep, addr->i, token); + m_Server.AddConnectedRecently (ep, i2p::util::GetSecondsSinceEpoch ()); } else { diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index b3b81b4d..6a5ae5e2 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -274,6 +274,8 @@ namespace transport bool ProcessSessionConfirmed (uint8_t * buf, size_t len); bool ProcessRetry (uint8_t * buf, size_t len); bool ProcessHolePunch (uint8_t * buf, size_t len); + void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, + const uint8_t * introKey, uint64_t token); virtual bool ProcessPeerTest (uint8_t * buf, size_t len); void ProcessData (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from); From 4f73f60e5177a3b6add0a06934227bea47556bb0 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Oct 2024 12:07:13 -0400 Subject: [PATCH 184/527] don't create relay response block twice --- libi2pd/SSU2OutOfSession.cpp | 24 +++++++++--- libi2pd/SSU2OutOfSession.h | 8 +++- libi2pd/SSU2Session.cpp | 74 ++++++++++-------------------------- libi2pd/SSU2Session.h | 6 +-- 4 files changed, 47 insertions(+), 65 deletions(-) diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index 574ad75b..46809217 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -227,19 +227,18 @@ namespace transport SSU2HolePunchSession::SSU2HolePunchSession (SSU2Server& server, uint32_t nonce, const boost::asio::ip::udp::endpoint& remoteEndpoint, - std::shared_ptr localAddr): + std::shared_ptr addr): SSU2Session (server), // we create full incoming session m_Nonce (nonce) { // we are Charlie - m_Token = GetServer ().GetIncomingToken (remoteEndpoint); uint64_t destConnID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id uint32_t sourceConnID = ~destConnID; SetSourceConnID (sourceConnID); SetDestConnID (destConnID); SetState (eSSU2SessionStateHolePunch); SetRemoteEndpoint (remoteEndpoint); - SetAddress (localAddr); + SetAddress (addr); SetTerminationTimeout (SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT); } @@ -267,8 +266,12 @@ namespace transport htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); size_t payloadSize = 7; payloadSize += CreateAddressBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, ep); - payloadSize += CreateRelayResponseBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, - eSSU2RelayResponseCodeAccept, m_Nonce, m_Token, ep.address ().is_v4 ()); + // relay response block + if (payloadSize + m_RelayResponseBlock.size () < GetMaxPayloadSize ()) + { + memcpy (payload + payloadSize, m_RelayResponseBlock.data (), m_RelayResponseBlock.size ()); + payloadSize += m_RelayResponseBlock.size (); + } payloadSize += CreatePaddingBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize); // encrypt uint8_t n[12]; @@ -282,5 +285,16 @@ namespace transport // send GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep); } + + void SSU2HolePunchSession::SendHolePunch (const uint8_t * relayResponseBlock, size_t relayResponseBlockLen) + { +#if __cplusplus >= 202002L // C++20 + m_RelayResponseBlock.assign (relayResponseBlock, relayResponseBlock + relayResponseBlockLen); +#else + m_RelayResponseBlock.resize (relayResponseBlockLen); + memcpy (m_RelayResponseBlock.data (), relayResponseBlock, relayResponseBlockLen); +#endif + SendHolePunch (); + } } } diff --git a/libi2pd/SSU2OutOfSession.h b/libi2pd/SSU2OutOfSession.h index d0d944d1..1069ab40 100644 --- a/libi2pd/SSU2OutOfSession.h +++ b/libi2pd/SSU2OutOfSession.h @@ -57,14 +57,18 @@ namespace transport public: SSU2HolePunchSession (SSU2Server& server, uint32_t nonce, const boost::asio::ip::udp::endpoint& remoteEndpoint, - std::shared_ptr localAddr); + std::shared_ptr addr); + void SendHolePunch (const uint8_t * relayResponseBlock, size_t relayResponseBlockLen); + + private: + void SendHolePunch (); private: uint32_t m_Nonce; - uint64_t m_Token; // for RelayResponse block + std::vector m_RelayResponseBlock; }; } } diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index f68231db..47f6a9b2 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1351,46 +1351,6 @@ namespace transport SendSessionRequest (token); return true; } - - void SSU2Session::SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, - const uint8_t * introKey, uint64_t token) - { - // we are Charlie - LogPrint (eLogDebug, "SSU2: Sending HolePunch to ", ep); - Header header; - uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE]; - // fill packet - header.h.connID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id - RAND_bytes (header.buf + 8, 4); // random packet num - header.h.type = eSSU2HolePunch; - header.h.flags[0] = 2; // ver - header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID - header.h.flags[2] = 0; // flag - memcpy (h, header.buf, 16); - uint64_t c = ~header.h.connID; - memcpy (h + 16, &c, 8); // source id - RAND_bytes (h + 24, 8); // token - // payload - payload[0] = eSSU2BlkDateTime; - htobe16buf (payload + 1, 4); - htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); - size_t payloadSize = 7; - payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, ep); - payloadSize += CreateRelayResponseBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, - eSSU2RelayResponseCodeAccept, nonce, token, ep.address ().is_v4 ()); - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - // encrypt - uint8_t n[12]; - CreateNonce (be32toh (header.h.packetNum), n); - i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, introKey, n, payload, payloadSize + 16, true); - payloadSize += 16; - header.ll[0] ^= CreateHeaderMask (introKey, payload + (payloadSize - 24)); - header.ll[1] ^= CreateHeaderMask (introKey, payload + (payloadSize - 12)); - memset (n, 0, 12); - i2p::crypto::ChaCha20 (h + 16, 16, introKey, n, h + 16); - // send - m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep); - } bool SSU2Session::ProcessHolePunch (uint8_t * buf, size_t len) { @@ -1985,8 +1945,8 @@ namespace transport { // we are Charlie SSU2RelayResponseCode code = eSSU2RelayResponseCodeAccept; - uint64_t token = 0; - bool isV4 = false; + boost::asio::ip::udp::endpoint ep; + std::shared_ptr addr; auto r = i2p::data::netdb.FindRouter (buf + 1); // Alice if (r) { @@ -1999,31 +1959,29 @@ namespace transport s.Insert (buf + 47, asz); // Alice Port, Alice IP if (s.Verify (r->GetIdentity (), buf + 47 + asz)) { - // send HolePunch - boost::asio::ip::udp::endpoint ep; + // obtain and check endpoint and address for HolePunch if (ExtractEndpoint (buf + 47, asz, ep)) { - std::shared_ptr addr; if (!ep.address ().is_unspecified () && ep.port ()) - addr = ep.address ().is_v6 () ? r->GetSSU2V6Address () : r->GetSSU2V4Address (); - if (addr) { if (m_Server.IsSupported (ep.address ())) { - token = m_Server.GetIncomingToken (ep); - isV4 = ep.address ().is_v4 (); - SendHolePunch (bufbe32toh (buf + 33), ep, addr->i, token); - m_Server.AddConnectedRecently (ep, i2p::util::GetSecondsSinceEpoch ()); + addr = ep.address ().is_v6 () ? r->GetSSU2V6Address () : r->GetSSU2V4Address (); + if (!addr) + { + LogPrint (eLogWarning, "SSU2: RelayIntro address for endpoint not found"); + code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; + } } else { LogPrint (eLogWarning, "SSU2: RelayIntro unsupported address"); code = eSSU2RelayResponseCodeCharlieUnsupportedAddress; - } + } } else { - LogPrint (eLogWarning, "SSU2: RelayIntro unknown address"); + LogPrint (eLogWarning, "SSU2: RelayIntro invalid endpoint"); code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; } } @@ -2059,8 +2017,16 @@ namespace transport } // send relay response to Bob auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); + uint32_t nonce = bufbe32toh (buf + 33); packet->payloadSize = CreateRelayResponseBlock (packet->payload, m_MaxPayloadSize, - code, bufbe32toh (buf + 33), token, isV4); + code, nonce, m_Server.GetIncomingToken (ep), ep.address ().is_v4 ()); + if (code == eSSU2RelayResponseCodeAccept && addr) + { + // send HolePunch + auto holePunchSession = std::make_shared(m_Server, nonce, ep, addr); + m_Server.AddSession (holePunchSession); + holePunchSession->SendHolePunch (packet->payload, packet->payloadSize); // relay response block + } packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); /*uint32_t packetNum = */SendData (packet->payload, packet->payloadSize); // sometimes Bob doesn't ack this RelayResponse diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 6a5ae5e2..ae0f18f4 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -274,8 +274,6 @@ namespace transport bool ProcessSessionConfirmed (uint8_t * buf, size_t len); bool ProcessRetry (uint8_t * buf, size_t len); bool ProcessHolePunch (uint8_t * buf, size_t len); - void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, - const uint8_t * introKey, uint64_t token); virtual bool ProcessPeerTest (uint8_t * buf, size_t len); void ProcessData (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from); @@ -298,8 +296,6 @@ namespace transport size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); - - size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4); private: @@ -356,6 +352,8 @@ namespace transport size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg); size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg, uint8_t& fragmentNum, uint32_t msgID); size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen); + size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4); + size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice size_t CreateTerminationBlock (uint8_t * buf, size_t len); From 50d9252ba96c5456026036ec2d2f9c3f111ec9a7 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Oct 2024 13:10:21 -0400 Subject: [PATCH 185/527] resend HolePunch 3 times or until SessionRequest received --- libi2pd/SSU2OutOfSession.cpp | 32 +++++++++++++++++++++++++++++++- libi2pd/SSU2OutOfSession.h | 9 +++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index 46809217..a2e0941e 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -229,7 +229,7 @@ namespace transport const boost::asio::ip::udp::endpoint& remoteEndpoint, std::shared_ptr addr): SSU2Session (server), // we create full incoming session - m_Nonce (nonce) + m_Nonce (nonce), m_NumResends (0), m_HolePunchResendTimer (server.GetService ()) { // we are Charlie uint64_t destConnID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id @@ -295,6 +295,36 @@ namespace transport memcpy (m_RelayResponseBlock.data (), relayResponseBlock, relayResponseBlockLen); #endif SendHolePunch (); + ScheduleResend (); + } + + void SSU2HolePunchSession::ScheduleResend () + { + if (m_NumResends < SSU2_HOLE_PUNCH_MAX_NUM_RESENDS) + { + m_HolePunchResendTimer.expires_from_now (boost::posix_time::milliseconds( + SSU2_HOLE_PUNCH_RESEND_INTERVAL + GetServer ().GetRng ()() % SSU2_HOLE_PUNCH_RESEND_INTERVAL_VARIANCE)); + std::weak_ptr s(std::static_pointer_cast(shared_from_this ())); + m_HolePunchResendTimer.async_wait ([s](const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + auto s1 = s.lock (); + if (s1 && s1->GetState () == eSSU2SessionStateHolePunch) + { + s1->SendHolePunch (); + s1->ScheduleResend (); + } + } + }); + m_NumResends++; + } + } + + bool SSU2HolePunchSession::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) + { + m_HolePunchResendTimer.cancel (); + return SSU2Session::ProcessFirstIncomingMessage (connID, buf, len); } } } diff --git a/libi2pd/SSU2OutOfSession.h b/libi2pd/SSU2OutOfSession.h index 1069ab40..176a30f9 100644 --- a/libi2pd/SSU2OutOfSession.h +++ b/libi2pd/SSU2OutOfSession.h @@ -52,6 +52,10 @@ namespace transport boost::asio::deadline_timer m_PeerTestResendTimer; }; + const int SSU2_HOLE_PUNCH_RESEND_INTERVAL = 1000; // in milliseconds + const int SSU2_HOLE_PUNCH_RESEND_INTERVAL_VARIANCE = 500; // in milliseconds + const int SSU2_HOLE_PUNCH_MAX_NUM_RESENDS = 3; + class SSU2HolePunchSession: public SSU2Session // Charlie { public: @@ -60,15 +64,20 @@ namespace transport std::shared_ptr addr); void SendHolePunch (const uint8_t * relayResponseBlock, size_t relayResponseBlockLen); + + bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) override; // SessionRequest private: void SendHolePunch (); + void ScheduleResend (); private: uint32_t m_Nonce; + int m_NumResends; std::vector m_RelayResponseBlock; + boost::asio::deadline_timer m_HolePunchResendTimer; }; } } From 8981e406f50e49561b5d209685880800ae6cfc3f Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Oct 2024 13:51:48 -0400 Subject: [PATCH 186/527] don't delete RouterInfo's buffer right a way --- libi2pd/NetDb.cpp | 9 +++++++-- libi2pd/RouterInfo.cpp | 6 ++++-- libi2pd/RouterInfo.h | 6 ++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 20b2fd42..f436a436 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -646,6 +646,11 @@ namespace data for (auto& it: m_RouterInfos) { if (!it.second || it.second == own) continue; // skip own + if (it.second->IsBufferScheduledToDelete ()) // from previous SaveUpdated, we assume m_PersistingRouters complete + { + std::lock_guard l(m_RouterInfosMutex); // possible collision between DeleteBuffer and Update + it.second->DeleteBuffer (); + } std::string ident = it.second->GetIdentHashBase64(); if (it.second->IsUpdated ()) { @@ -655,8 +660,8 @@ namespace data std::shared_ptr buffer; { std::lock_guard l(m_RouterInfosMutex); // possible collision between DeleteBuffer and Update - buffer = it.second->GetSharedBuffer (); - it.second->DeleteBuffer (); + buffer = it.second->CopyBuffer (); + it.second->ScheduleBufferToDelete (); } if (buffer && !it.second->IsUnreachable ()) // don't save bad router saveToDisk.push_back(std::make_pair(ident, buffer)); diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 2da40ae8..168c5665 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -45,8 +45,9 @@ namespace data RouterInfo::RouterInfo (const std::string& fullPath): m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false), m_IsFloodfill (false), - m_SupportedTransports (0),m_ReachableTransports (0), m_PublishedTransports (0), - m_Caps (0), m_Version (0), m_Congestion (eLowCongestion) + m_IsBufferScheduledToDelete (false), m_SupportedTransports (0), + m_ReachableTransports (0), m_PublishedTransports (0), m_Caps (0), m_Version (0), + m_Congestion (eLowCongestion) { m_Addresses = AddressesPtr(new Addresses ()); // create empty list m_Buffer = RouterInfo::NewBuffer (); // always RouterInfo's @@ -1140,6 +1141,7 @@ namespace data if (len > m_Buffer->size ()) len = m_Buffer->size (); memcpy (m_Buffer->data (), buf, len); m_Buffer->SetBufferLen (len); + m_IsBufferScheduledToDelete = false; } std::shared_ptr RouterInfo::CopyBuffer () const diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 72521797..719d5795 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -290,9 +290,11 @@ namespace data const uint8_t * GetBuffer () const { return m_Buffer ? m_Buffer->data () : nullptr; }; const uint8_t * LoadBuffer (const std::string& fullPath); // load if necessary size_t GetBufferLen () const { return m_Buffer ? m_Buffer->GetBufferLen () : 0; }; - void DeleteBuffer () { m_Buffer = nullptr; }; + void DeleteBuffer () { m_Buffer = nullptr; m_IsBufferScheduledToDelete = false; }; std::shared_ptr GetSharedBuffer () const { return m_Buffer; }; std::shared_ptr CopyBuffer () const; + void ScheduleBufferToDelete () { m_IsBufferScheduledToDelete = false; }; + bool IsBufferScheduledToDelete () const { return m_IsBufferScheduledToDelete; }; bool IsUpdated () const { return m_IsUpdated; }; void SetUpdated (bool updated) { m_IsUpdated = updated; }; @@ -354,7 +356,7 @@ namespace data #else AddressesPtr m_Addresses; #endif - bool m_IsUpdated, m_IsUnreachable, m_IsFloodfill; + bool m_IsUpdated, m_IsUnreachable, m_IsFloodfill, m_IsBufferScheduledToDelete; CompatibleTransports m_SupportedTransports, m_ReachableTransports, m_PublishedTransports; uint8_t m_Caps; char m_BandwidthCap; From e26682f4cbba40230a12ab17f9f7133bbf45da68 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Oct 2024 15:05:29 -0400 Subject: [PATCH 187/527] don't try to save invalid router --- libi2pd/NetDb.cpp | 5 ++--- libi2pd/RouterInfo.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index f436a436..d32f113d 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -654,7 +654,7 @@ namespace data std::string ident = it.second->GetIdentHashBase64(); if (it.second->IsUpdated ()) { - if (it.second->GetBuffer ()) + if (it.second->GetBuffer () && !it.second->IsUnreachable ()) { // we have something to save std::shared_ptr buffer; @@ -663,9 +663,8 @@ namespace data buffer = it.second->CopyBuffer (); it.second->ScheduleBufferToDelete (); } - if (buffer && !it.second->IsUnreachable ()) // don't save bad router + if (buffer) saveToDisk.push_back(std::make_pair(ident, buffer)); - it.second->SetUnreachable (false); } it.second->SetUpdated (false); updatedCount++; diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 719d5795..beeba5bf 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -293,7 +293,7 @@ namespace data void DeleteBuffer () { m_Buffer = nullptr; m_IsBufferScheduledToDelete = false; }; std::shared_ptr GetSharedBuffer () const { return m_Buffer; }; std::shared_ptr CopyBuffer () const; - void ScheduleBufferToDelete () { m_IsBufferScheduledToDelete = false; }; + void ScheduleBufferToDelete () { m_IsBufferScheduledToDelete = true; }; bool IsBufferScheduledToDelete () const { return m_IsBufferScheduledToDelete; }; bool IsUpdated () const { return m_IsUpdated; }; From 0ccf0a633943db416f93af4cd654aca5d2b08eb5 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Oct 2024 17:57:52 -0400 Subject: [PATCH 188/527] use pointer to RouterInfo in SaveUpdated --- libi2pd/NetDb.cpp | 67 +++++++++++++++++++++--------------------- libi2pd/RouterInfo.cpp | 2 +- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index d32f113d..7266f44f 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -643,69 +643,68 @@ namespace data std::list removeFromDisk; auto own = i2p::context.GetSharedRouterInfo (); - for (auto& it: m_RouterInfos) + for (auto [ident, r]: m_RouterInfos) { - if (!it.second || it.second == own) continue; // skip own - if (it.second->IsBufferScheduledToDelete ()) // from previous SaveUpdated, we assume m_PersistingRouters complete + if (!r || r == own) continue; // skip own + if (r->IsBufferScheduledToDelete ()) // from previous SaveUpdated, we assume m_PersistingRouters complete { std::lock_guard l(m_RouterInfosMutex); // possible collision between DeleteBuffer and Update - it.second->DeleteBuffer (); + r->DeleteBuffer (); } - std::string ident = it.second->GetIdentHashBase64(); - if (it.second->IsUpdated ()) + if (r->IsUpdated ()) { - if (it.second->GetBuffer () && !it.second->IsUnreachable ()) + if (r->GetBuffer () && !r->IsUnreachable ()) { // we have something to save std::shared_ptr buffer; { std::lock_guard l(m_RouterInfosMutex); // possible collision between DeleteBuffer and Update - buffer = it.second->CopyBuffer (); - it.second->ScheduleBufferToDelete (); + buffer = r->CopyBuffer (); + r->ScheduleBufferToDelete (); } if (buffer) - saveToDisk.push_back(std::make_pair(ident, buffer)); + saveToDisk.push_back(std::make_pair(ident.ToBase64 (), buffer)); } - it.second->SetUpdated (false); + r->SetUpdated (false); updatedCount++; continue; } - if (it.second->GetProfile ()->IsUnreachable ()) - it.second->SetUnreachable (true); + if (r->GetProfile ()->IsUnreachable ()) + r->SetUnreachable (true); // make router reachable back if too few routers or floodfills - if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate || - (it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS))) - it.second->SetUnreachable (false); - if (!it.second->IsUnreachable ()) + if (r->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate || + (r->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS))) + r->SetUnreachable (false); + if (!r->IsUnreachable ()) { // find & mark expired routers - if (!it.second->GetCompatibleTransports (true)) // non reachable by any transport - it.second->SetUnreachable (true); - else if (ts + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < it.second->GetTimestamp ()) + if (!r->GetCompatibleTransports (true)) // non reachable by any transport + r->SetUnreachable (true); + else if (ts + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < r->GetTimestamp ()) { - LogPrint (eLogWarning, "NetDb: RouterInfo is from future for ", (it.second->GetTimestamp () - ts)/1000LL, " seconds"); - it.second->SetUnreachable (true); + LogPrint (eLogWarning, "NetDb: RouterInfo is from future for ", (r->GetTimestamp () - ts)/1000LL, " seconds"); + r->SetUnreachable (true); } else if (checkForExpiration) { - if (ts > it.second->GetTimestamp () + expirationTimeout) - it.second->SetUnreachable (true); - else if ((ts > it.second->GetTimestamp () + expirationTimeout/2) && // more than half of expiration - total > NETDB_NUM_ROUTERS_THRESHOLD && !it.second->IsHighBandwidth() && // low bandwidth - !it.second->IsFloodfill() && (!i2p::context.IsFloodfill () || // non floodfill - (CreateRoutingKey (it.second->GetIdentHash ()) ^ i2p::context.GetIdentHash ()).metric[0] >= 0x02)) // different first 7 bits - it.second->SetUnreachable (true); + if (ts > r->GetTimestamp () + expirationTimeout) + r->SetUnreachable (true); + else if ((ts > r->GetTimestamp () + expirationTimeout/2) && // more than half of expiration + total > NETDB_NUM_ROUTERS_THRESHOLD && !r->IsHighBandwidth() && // low bandwidth + !r->IsFloodfill() && (!i2p::context.IsFloodfill () || // non floodfill + (CreateRoutingKey (ident) ^ i2p::context.GetIdentHash ()).metric[0] >= 0x02)) // different first 7 bits + r->SetUnreachable (true); } } // make router reachable back if connected now - if (it.second->IsUnreachable () && i2p::transport::transports.IsConnected (it.second->GetIdentHash ())) - it.second->SetUnreachable (false); + if (r->IsUnreachable () && i2p::transport::transports.IsConnected (ident)) + r->SetUnreachable (false); - if (it.second->IsUnreachable ()) + if (r->IsUnreachable ()) { - if (it.second->IsFloodfill ()) deletedFloodfillsCount++; + if (r->IsFloodfill ()) deletedFloodfillsCount++; // delete RI file - removeFromDisk.push_back (ident); + removeFromDisk.push_back (ident.ToBase64()); deletedCount++; if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false; } diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 168c5665..2321a1e0 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -56,7 +56,7 @@ namespace data RouterInfo::RouterInfo (std::shared_ptr&& buf, size_t len): m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false), m_IsFloodfill (false), - m_SupportedTransports (0), m_ReachableTransports (0), m_PublishedTransports (0), + m_IsBufferScheduledToDelete (false), m_SupportedTransports (0), m_ReachableTransports (0), m_PublishedTransports (0), m_Caps (0), m_Version (0), m_Congestion (eLowCongestion) { if (len <= MAX_RI_BUFFER_SIZE) From 0213f058d14f4d550aa857f619b44a4a56ef5f5f Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Oct 2024 21:19:30 -0400 Subject: [PATCH 189/527] Send peer test msg 6 with delay if msg 4 was received before msg 5 --- libi2pd/SSU2OutOfSession.cpp | 32 ++++++++++++++------------------ libi2pd/SSU2OutOfSession.h | 7 +++---- libi2pd/SSU2Session.cpp | 4 +++- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index a2e0941e..c337938e 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -83,6 +83,7 @@ namespace transport { if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ()) { + m_PeerTestResendTimer.cancel (); // calcel delayed msg 6 if any m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ()); if (GetAddress ()) { @@ -111,9 +112,6 @@ namespace transport case 7: // Alice from Charlie 2 { m_PeerTestResendTimer.cancel (); // no more msg 6 resends - auto addr = GetAddress (); - if (addr && addr->IsV6 ()) - i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2 GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ()); GetServer ().RequestRemoveSession (GetConnID ()); break; @@ -163,7 +161,7 @@ namespace transport GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ()); } - void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen) + void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, bool delayed) { #if __cplusplus >= 202002L // C++20 m_SignedData.assign (signedData, signedData + signedDataLen); @@ -171,18 +169,19 @@ namespace transport m_SignedData.resize (signedDataLen); memcpy (m_SignedData.data (), signedData, signedDataLen); #endif - SendPeerTest (msg); + if (!delayed) + SendPeerTest (msg); // schedule resend for msgs 5 or 6 if (msg == 5 || msg == 6) - ScheduleResend (); + ScheduleResend (msg); } void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, - std::shared_ptr addr) + std::shared_ptr addr, bool delayed) { if (!addr) return; SetAddress (addr); - SendPeerTest (msg, signedData, signedDataLen); + SendPeerTest (msg, signedData, signedDataLen, delayed); } void SSU2PeerTestSession::Connect () @@ -196,32 +195,29 @@ namespace transport return false; } - void SSU2PeerTestSession::ScheduleResend () + void SSU2PeerTestSession::ScheduleResend (uint8_t msg) { if (m_NumResends < SSU2_PEER_TEST_MAX_NUM_RESENDS) { m_PeerTestResendTimer.expires_from_now (boost::posix_time::milliseconds( SSU2_PEER_TEST_RESEND_INTERVAL + GetServer ().GetRng ()() % SSU2_PEER_TEST_RESEND_INTERVAL_VARIANCE)); std::weak_ptr s(std::static_pointer_cast(shared_from_this ())); - m_PeerTestResendTimer.async_wait ([s](const boost::system::error_code& ecode) + m_PeerTestResendTimer.async_wait ([s, msg](const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) { auto s1 = s.lock (); if (s1) { - int msg = 0; - if (s1->m_MsgNumReceived < 6) - msg = (s1->m_MsgNumReceived == 5) ? 6 : 5; - if (msg) // 5 or 6 + if (msg > s1->m_MsgNumReceived) { s1->SendPeerTest (msg); - s1->ScheduleResend (); + s1->m_NumResends++; + s1->ScheduleResend (msg); } } } }); - m_NumResends++; } } @@ -229,7 +225,7 @@ namespace transport const boost::asio::ip::udp::endpoint& remoteEndpoint, std::shared_ptr addr): SSU2Session (server), // we create full incoming session - m_Nonce (nonce), m_NumResends (0), m_HolePunchResendTimer (server.GetService ()) + m_NumResends (0), m_HolePunchResendTimer (server.GetService ()) { // we are Charlie uint64_t destConnID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id @@ -313,11 +309,11 @@ namespace transport if (s1 && s1->GetState () == eSSU2SessionStateHolePunch) { s1->SendHolePunch (); + s1->m_NumResends++; s1->ScheduleResend (); } } }); - m_NumResends++; } } diff --git a/libi2pd/SSU2OutOfSession.h b/libi2pd/SSU2OutOfSession.h index 176a30f9..6f2a9fbd 100644 --- a/libi2pd/SSU2OutOfSession.h +++ b/libi2pd/SSU2OutOfSession.h @@ -31,18 +31,18 @@ namespace transport void SetStatusChanged () { m_IsStatusChanged = true; } void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, - std::shared_ptr addr); + std::shared_ptr addr, bool delayed = false); bool ProcessPeerTest (uint8_t * buf, size_t len) override; void Connect () override; // outgoing bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) override; // incoming private: - void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen); // PeerTest message + void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, bool delayed = false); // PeerTest message void SendPeerTest (uint8_t msg); // send or resend m_SignedData void HandlePeerTest (const uint8_t * buf, size_t len) override; - void ScheduleResend (); + void ScheduleResend (uint8_t msg); private: @@ -74,7 +74,6 @@ namespace transport private: - uint32_t m_Nonce; int m_NumResends; std::vector m_RelayResponseBlock; boost::asio::deadline_timer m_HolePunchResendTimer; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 47f6a9b2..454c38d5 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2312,7 +2312,7 @@ namespace transport { if (!session->IsConnectedRecently ()) SetRouterStatus (eRouterStatusOK); - // send msg 6 + // send msg 6 immeditely session->SendPeerTest (6, buf + offset, len - offset, addr); } else @@ -2323,6 +2323,8 @@ namespace transport session->m_Address = addr; if (GetTestingState ()) { + // schedule msg 6 with delay + session->SendPeerTest (6, buf + offset, len - offset, addr, true); SetTestingState (false); if (GetRouterStatus () != eRouterStatusFirewalled && addr->IsPeerTesting ()) { From fe71776b6f6a8f4bb9c94902b495d37a621d17c9 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 17 Oct 2024 15:44:26 -0400 Subject: [PATCH 190/527] update LeaseSet if inbound tunnel was restored --- libi2pd/Tunnel.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index ca110ccc..6e5ebdad 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -250,7 +250,18 @@ namespace tunnel void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr&& msg) { - if (GetState () != eTunnelStateExpiring) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive + if (!IsEstablished () && GetState () != eTunnelStateExpiring) + { + // incoming messages means a tunnel is alive + SetState (eTunnelStateEstablished); + auto pool = GetTunnelPool (); + if (pool) + { + // update LeaseSet + auto dest = pool->GetLocalDestination (); + if (dest) dest->SetLeaseSetUpdated (); + } + } EncryptTunnelMsg (msg, msg); msg->from = GetSharedFromThis (); m_Endpoint.HandleDecryptedTunnelDataMsg (msg); From bc9d25ec3b53b9c2baa2371ce5747de8a35e7e88 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 17 Oct 2024 16:20:27 -0400 Subject: [PATCH 191/527] ability post LeaseSet update to destination's thread --- libi2pd/Destination.cpp | 7 +++++-- libi2pd/Destination.h | 2 +- libi2pd/Garlic.cpp | 2 +- libi2pd/Garlic.h | 2 +- libi2pd/Tunnel.cpp | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 28b23950..01ff2d2a 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -588,9 +588,12 @@ namespace client i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msgID); } - void LeaseSetDestination::SetLeaseSetUpdated () + void LeaseSetDestination::SetLeaseSetUpdated (bool post) { - UpdateLeaseSet (); + if (post) + m_Service.post([s = shared_from_this ()]() { s->UpdateLeaseSet (); }); + else + UpdateLeaseSet (); } void LeaseSetDestination::Publish () diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 4a51a257..293cd75d 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -150,7 +150,7 @@ namespace client void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag); void ProcessGarlicMessage (std::shared_ptr msg); void ProcessDeliveryStatusMessage (std::shared_ptr msg); - void SetLeaseSetUpdated (); + void SetLeaseSetUpdated (bool post) override; bool IsPublic () const { return m_IsPublic; }; void SetPublic (bool pub) { m_IsPublic = pub; }; diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 1705b03a..04884acd 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -897,7 +897,7 @@ namespace garlic } } - void GarlicDestination::SetLeaseSetUpdated () + void GarlicDestination::SetLeaseSetUpdated (bool post) { { std::unique_lock l(m_SessionsMutex); diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index a4475dc7..80fc15da 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -253,7 +253,7 @@ namespace garlic virtual void ProcessGarlicMessage (std::shared_ptr msg); virtual void ProcessDeliveryStatusMessage (std::shared_ptr msg); - virtual void SetLeaseSetUpdated (); + virtual void SetLeaseSetUpdated (bool post = false); virtual std::shared_ptr GetLeaseSet () = 0; // TODO virtual std::shared_ptr GetTunnelPool () const = 0; diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 6e5ebdad..c41bb775 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -259,7 +259,7 @@ namespace tunnel { // update LeaseSet auto dest = pool->GetLocalDestination (); - if (dest) dest->SetLeaseSetUpdated (); + if (dest) dest->SetLeaseSetUpdated (true); } } EncryptTunnelMsg (msg, msg); From 890fe77b1019b7dab0619a8138bbc844e34bccfa Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 17 Oct 2024 18:15:33 -0400 Subject: [PATCH 192/527] update leaseset in destination's thread --- libi2pd/TunnelPool.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 5af42373..3d50738c 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -141,7 +141,7 @@ namespace tunnel m_InboundTunnels.insert (createdTunnel); } if (m_LocalDestination) - m_LocalDestination->SetLeaseSetUpdated (); + m_LocalDestination->SetLeaseSetUpdated (true); } void TunnelPool::TunnelExpired (std::shared_ptr expiredTunnel) @@ -330,7 +330,7 @@ namespace tunnel } if (num < m_NumInboundTunnels && m_NumInboundHops <= 0 && m_LocalDestination) // zero hops IB - m_LocalDestination->SetLeaseSetUpdated (); // update LeaseSet immediately + m_LocalDestination->SetLeaseSetUpdated (true); // update LeaseSet immediately } void TunnelPool::TestTunnels () @@ -377,10 +377,10 @@ namespace tunnel it.second.second->SetState (eTunnelStateTestFailed); } if (failed && m_LocalDestination) - m_LocalDestination->SetLeaseSetUpdated (); + m_LocalDestination->SetLeaseSetUpdated (true); } if (m_LocalDestination) - m_LocalDestination->SetLeaseSetUpdated (); + m_LocalDestination->SetLeaseSetUpdated (true); } else if (it.second.second->GetState () != eTunnelStateExpiring) it.second.second->SetState (eTunnelStateTestFailed); From 1419745a5d848ac283225230d1a76209253a4d61 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 17 Oct 2024 21:09:37 -0400 Subject: [PATCH 193/527] recognize symmetric NAT from peer test msg 7 --- libi2pd/SSU2OutOfSession.cpp | 29 +++++++++++++++++++++++++++++ libi2pd/SSU2OutOfSession.h | 2 ++ libi2pd/SSU2Session.h | 5 +++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index c337938e..262f93a9 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -65,6 +65,12 @@ namespace transport return true; } + void SSU2PeerTestSession::HandleAddress (const uint8_t * buf, size_t len) + { + if (!ExtractEndpoint (buf, len, m_OurEndpoint)) + LogPrint (eLogWarning, "SSU2: Can't hanlde address block from peer test message"); + } + void SSU2PeerTestSession::HandlePeerTest (const uint8_t * buf, size_t len) { // msgs 5-7 @@ -112,6 +118,29 @@ namespace transport case 7: // Alice from Charlie 2 { m_PeerTestResendTimer.cancel (); // no more msg 6 resends + if (m_MsgNumReceived < 5 && m_OurEndpoint.port ()) // msg 5 was not received + { + if (m_OurEndpoint.address ().is_v4 ()) // ipv4 + { + if (i2p::context.GetStatus () == eRouterStatusFirewalled) + { + if (m_OurEndpoint.port () != GetServer ().GetPort (true)) + i2p::context.SetError (eRouterErrorSymmetricNAT); + else if (i2p::context.GetError () == eRouterErrorSymmetricNAT) + i2p::context.SetError (eRouterErrorNone); + } + } + else + { + if (i2p::context.GetStatusV6 () == eRouterStatusFirewalled) + { + if (m_OurEndpoint.port () != GetServer ().GetPort (false)) + i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT); + else if (i2p::context.GetErrorV6 () == eRouterErrorSymmetricNAT) + i2p::context.SetErrorV6 (eRouterErrorNone); + } + } + } GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ()); GetServer ().RequestRemoveSession (GetConnID ()); break; diff --git a/libi2pd/SSU2OutOfSession.h b/libi2pd/SSU2OutOfSession.h index 6f2a9fbd..e8c55c3c 100644 --- a/libi2pd/SSU2OutOfSession.h +++ b/libi2pd/SSU2OutOfSession.h @@ -41,6 +41,7 @@ namespace transport void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, bool delayed = false); // PeerTest message void SendPeerTest (uint8_t msg); // send or resend m_SignedData void HandlePeerTest (const uint8_t * buf, size_t len) override; + void HandleAddress (const uint8_t * buf, size_t len) override; void ScheduleResend (uint8_t msg); @@ -50,6 +51,7 @@ namespace transport bool m_IsConnectedRecently, m_IsStatusChanged; std::vector m_SignedData; // for resends boost::asio::deadline_timer m_PeerTestResendTimer; + boost::asio::ip::udp::endpoint m_OurEndpoint; // as seen by peer }; const int SSU2_HOLE_PUNCH_RESEND_INTERVAL = 1000; // in milliseconds diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index ae0f18f4..e27671f8 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -296,6 +296,8 @@ namespace transport size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); + + bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep); private: @@ -328,8 +330,7 @@ namespace transport void HandleRouterInfo (const uint8_t * buf, size_t len); void HandleAck (const uint8_t * buf, size_t len); void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts); - void HandleAddress (const uint8_t * buf, size_t len); - bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep); + 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 (); From f98a310235d7e96dd39a9423593e2fd3cbb546ed Mon Sep 17 00:00:00 2001 From: SystemFailure Date: Fri, 18 Oct 2024 13:17:47 +0000 Subject: [PATCH 194/527] Revert LibreSSL workaround when LibreSSL version >= 4.0.0 --- libi2pd/Crypto.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 2f9677c1..8ce290f1 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -997,7 +997,7 @@ namespace crypto } else { -#if defined(LIBRESSL_VERSION_NUMBER) +#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x4000000fL std::vector m(msgLen + 16); if (msg == buf) { From 8a234f70e6e109340d64c161097c5d651dca6d53 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 18 Oct 2024 15:59:37 -0400 Subject: [PATCH 195/527] send a packet to new remote lease in advance if current is about to expire --- libi2pd/Streaming.cpp | 81 +++++++++++++++++++++++++++++++------------ libi2pd/Streaming.h | 6 +++- 2 files changed, 64 insertions(+), 23 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 6a91e33f..c81a12eb 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -73,14 +73,14 @@ namespace stream m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), - m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_LocalDestination (local), + m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_RemoteLeaseChangeTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { @@ -101,13 +101,13 @@ namespace stream m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), - m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_LocalDestination (local), + m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_LocalDestination (local), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_RemoteLeaseChangeTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { @@ -256,6 +256,7 @@ namespace stream if (receivedSeqn <= m_PreviousReceivedSequenceNumber || receivedSeqn == m_LastReceivedSequenceNumber) { m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel); + CancelRemoteLeaseChange (); UpdateCurrentRemoteLease (); } m_PreviousReceivedSequenceNumber = receivedSeqn; @@ -1104,6 +1105,7 @@ namespace stream { if (!m_RemoteLeaseSet) { + CancelRemoteLeaseChange (); UpdateCurrentRemoteLease (); if (!m_RemoteLeaseSet) { @@ -1127,9 +1129,28 @@ namespace stream } auto ts = i2p::util::GetMillisecondsSinceEpoch (); - if (!m_CurrentRemoteLease || !m_CurrentRemoteLease->endDate || // excluded from LeaseSet - ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD) + if (!m_CurrentRemoteLease || !m_CurrentRemoteLease->endDate) // excluded from LeaseSet + { + CancelRemoteLeaseChange (); UpdateCurrentRemoteLease (true); + } + if (m_RemoteLeaseChangeTime && m_IsRemoteLeaseChangeInProgress && ts > m_RemoteLeaseChangeTime + INITIAL_RTT) + { + CancelRemoteLeaseChange (); + m_CurrentRemoteLease = m_NextRemoteLease; + HalveWindowSize (); + } + auto currentRemoteLease = m_CurrentRemoteLease; + if (!m_IsRemoteLeaseChangeInProgress && m_RemoteLeaseSet && m_CurrentRemoteLease && ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD) + { + auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (false); + if (leases.size () > 1) + { + m_IsRemoteLeaseChangeInProgress = true; + UpdateCurrentRemoteLease (true); + m_NextRemoteLease = m_CurrentRemoteLease; + } + } if (m_CurrentRemoteLease && ts < m_CurrentRemoteLease->endDate + i2p::data::LEASE_ENDDATE_THRESHOLD) { bool freshTunnel = false; @@ -1166,6 +1187,11 @@ namespace stream msg }); m_NumSentBytes += it->GetLength (); + if (m_IsRemoteLeaseChangeInProgress && !m_RemoteLeaseChangeTime) + { + m_RemoteLeaseChangeTime = ts; + m_CurrentRemoteLease = currentRemoteLease; // change it back before new lease is confirmed + } } m_CurrentOutboundTunnel->SendTunnelDataMsgs (msgs); } @@ -1366,6 +1392,7 @@ namespace stream } else { + CancelRemoteLeaseChange (); UpdateCurrentRemoteLease (); // pick another lease LogPrint (eLogWarning, "Streaming: Resend #", m_NumResendAttempts, ", another remote lease has been selected for stream with rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID); @@ -1506,22 +1533,9 @@ namespace stream LogPrint (eLogWarning, "Streaming: Remote LeaseSet not found"); m_CurrentRemoteLease = nullptr; } - if (isLeaseChanged) + if (isLeaseChanged && !m_IsRemoteLeaseChangeInProgress) { - // drop window to initial upon RemoteLease change - m_RTO = INITIAL_RTO; - if (m_WindowSize > INITIAL_WINDOW_SIZE) - { - m_WindowDropTargetSize = std::max (m_WindowSize/2, (float)INITIAL_WINDOW_SIZE); - m_IsWinDropped = true; - } - else - m_WindowSize = INITIAL_WINDOW_SIZE; - m_LastWindowDropSize = 0; - m_WindowIncCounter = 0; - m_IsFirstRttSample = true; - m_IsFirstACK = true; - UpdatePacingTime (); + HalveWindowSize (); } } @@ -1559,7 +1573,30 @@ namespace stream m_IsWinDropped = true; // don't drop window twice UpdatePacingTime (); } - + + void Stream::HalveWindowSize () + { + m_RTO = INITIAL_RTO; + if (m_WindowSize > INITIAL_WINDOW_SIZE) + { + m_WindowDropTargetSize = std::max (m_WindowSize/2, (float)INITIAL_WINDOW_SIZE); + m_IsWinDropped = true; + } + else + m_WindowSize = INITIAL_WINDOW_SIZE; + m_LastWindowDropSize = 0; + m_WindowIncCounter = 0; + m_IsFirstRttSample = true; + m_IsFirstACK = true; + UpdatePacingTime (); + } + + void Stream::CancelRemoteLeaseChange () + { + m_RemoteLeaseChangeTime = 0; + m_IsRemoteLeaseChangeInProgress = false; + } + StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort, bool gzip): m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), m_PendingIncomingTimer (m_Owner->GetService ()), diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 9ac84990..8183bdad 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -248,6 +248,8 @@ namespace stream void UpdatePacingTime (); void ProcessWindowDrop (); + void HalveWindowSize (); + void CancelRemoteLeaseChange (); private: @@ -268,12 +270,14 @@ namespace stream bool m_IsWinDropped; bool m_IsTimeOutResend; bool m_IsImmediateAckRequested; + bool m_IsRemoteLeaseChangeInProgress; StreamingDestination& m_LocalDestination; std::shared_ptr m_RemoteIdentity; std::shared_ptr m_TransientVerifier; // in case of offline key std::shared_ptr m_RemoteLeaseSet; std::shared_ptr m_RoutingSession; std::shared_ptr m_CurrentRemoteLease; + std::shared_ptr m_NextRemoteLease; std::shared_ptr m_CurrentOutboundTunnel; std::queue m_ReceiveQueue; std::set m_SavedPackets; @@ -289,7 +293,7 @@ namespace stream int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; double m_Jitter; uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, // microseconds - m_LastSendTime; // miliseconds + m_LastSendTime, m_RemoteLeaseChangeTime; // miliseconds uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed int m_NumResendAttempts, m_NumPacketsToSend; size_t m_MTU; From 10335b90c58bc4137b8eface9c517e3d2a053606 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 18 Oct 2024 19:57:35 -0400 Subject: [PATCH 196/527] fixed warnings --- libi2pd/Destination.h | 16 ++++++++-------- libi2pd/RouterContext.h | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 293cd75d..c6a8cab7 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -142,14 +142,14 @@ namespace client void CancelDestinationRequestWithEncryptedLeaseSet (std::shared_ptr dest, bool notify = true); // implements GarlicDestination - std::shared_ptr GetLeaseSet (); - std::shared_ptr GetTunnelPool () const { return m_Pool; } + std::shared_ptr GetLeaseSet () override; + std::shared_ptr GetTunnelPool () const override { return m_Pool; } // override GarlicDestination - bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); - void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag); - void ProcessGarlicMessage (std::shared_ptr msg); - void ProcessDeliveryStatusMessage (std::shared_ptr msg); + bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag) override; + void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag) override; + void ProcessGarlicMessage (std::shared_ptr msg) override; + void ProcessDeliveryStatusMessage (std::shared_ptr msg) override; void SetLeaseSetUpdated (bool post) override; bool IsPublic () const { return m_IsPublic; }; @@ -158,8 +158,8 @@ namespace client protected: // implements GarlicDestination - void HandleI2NPMessage (const uint8_t * buf, size_t len); - bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID); + 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; void SetLeaseSet (std::shared_ptr newLeaseSet); int GetLeaseSetType () const { return m_LeaseSetType; }; diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index c620f8b1..269c2125 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -186,24 +186,23 @@ namespace garlic void UpdateTimestamp (uint64_t ts); // in seconds, called from NetDb before publishing // implements LocalDestination - std::shared_ptr GetIdentity () const { return m_Keys.GetPublic (); }; - bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const; - void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; - void SetLeaseSetUpdated () {}; + std::shared_ptr GetIdentity () const override{ return m_Keys.GetPublic (); }; + bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const override; + void SetLeaseSetUpdated (bool post) override {}; // implements GarlicDestination - std::shared_ptr GetLeaseSet () { return nullptr; }; - std::shared_ptr GetTunnelPool () const; + std::shared_ptr GetLeaseSet () override { return nullptr; }; + std::shared_ptr GetTunnelPool () const override; // override GarlicDestination - void ProcessGarlicMessage (std::shared_ptr msg); - void ProcessDeliveryStatusMessage (std::shared_ptr msg); + void ProcessGarlicMessage (std::shared_ptr msg) override; + void ProcessDeliveryStatusMessage (std::shared_ptr msg) override; protected: // implements GarlicDestination - void HandleI2NPMessage (const uint8_t * buf, size_t len); - bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID); + 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; private: @@ -216,6 +215,7 @@ namespace garlic void UpdateSSU2Keys (); bool Load (); void SaveKeys (); + void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; uint16_t SelectRandomPort () const; void PublishNTCP2Address (std::shared_ptr address, int port, bool publish) const; From f087654f258eb691488d3bd39c45c250bc8da84d Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 18 Oct 2024 20:02:41 -0400 Subject: [PATCH 197/527] fixed warnings --- libi2pd/RouterContext.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 269c2125..f828a182 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -146,7 +146,6 @@ 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 @@ -197,6 +196,7 @@ namespace garlic // override GarlicDestination void ProcessGarlicMessage (std::shared_ptr msg) override; void ProcessDeliveryStatusMessage (std::shared_ptr msg) override; + void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag) override; protected: From e6cbc842bfb1de2f0bc23f9e897b369e226cb9a7 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 19 Oct 2024 08:45:25 -0400 Subject: [PATCH 198/527] request new leaseset if all leases are about to expire --- libi2pd/Streaming.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index c81a12eb..f22e724d 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1144,12 +1144,14 @@ namespace stream if (!m_IsRemoteLeaseChangeInProgress && m_RemoteLeaseSet && m_CurrentRemoteLease && ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD) { auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (false); - if (leases.size () > 1) + if (leases.size ()) { m_IsRemoteLeaseChangeInProgress = true; UpdateCurrentRemoteLease (true); m_NextRemoteLease = m_CurrentRemoteLease; } + else + UpdateCurrentRemoteLease (true); } if (m_CurrentRemoteLease && ts < m_CurrentRemoteLease->endDate + i2p::data::LEASE_ENDDATE_THRESHOLD) { From 0cb677a2c0771a6d61df43cacfd8ad407b1e63b7 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 19 Oct 2024 09:18:31 -0400 Subject: [PATCH 199/527] don't send peer test msg 6 if remote endpoint is unknown --- libi2pd/SSU2Session.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 454c38d5..17d2c1da 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2303,11 +2303,11 @@ namespace transport { session->SetRemoteIdentity (r->GetIdentity ()); auto addr = r->GetSSU2Address (m_Address->IsV4 ()); - if (addr) + if (addr && addr->IsPeerTesting ()) { if (session->GetMsgNumReceived () >= 5) { - // msg 5 already received + // msg 5 already received and we know remote endpoint if (session->GetMsgNumReceived () == 5) { if (!session->IsConnectedRecently ()) @@ -2324,7 +2324,11 @@ namespace transport if (GetTestingState ()) { // schedule msg 6 with delay - session->SendPeerTest (6, buf + offset, len - offset, addr, true); + if (!addr->host.is_unspecified () && addr->port) + { + session->SetRemoteEndpoint (boost::asio::ip::udp::endpoint (addr->host, addr->port)); + session->SendPeerTest (6, buf + offset, len - offset, addr, true); + } SetTestingState (false); if (GetRouterStatus () != eRouterStatusFirewalled && addr->IsPeerTesting ()) { @@ -2342,7 +2346,7 @@ namespace transport } else { - LogPrint (eLogWarning, "SSU2: Peer test 4 address not found"); + LogPrint (eLogWarning, "SSU2: Peer test 4 address not found or not supported"); session->Done (); } } From a24e0eb2dc6b71af2c6e09c50b8a4870937e9d09 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 20 Oct 2024 16:12:35 -0400 Subject: [PATCH 200/527] don't delete unreachable routers if no transports --- libi2pd/NetDb.cpp | 5 +++-- libi2pd/NetDb.hpp | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 7266f44f..341d617e 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -638,7 +638,8 @@ namespace data if (checkForExpiration && uptime > i2p::transport::SSU2_TO_INTRODUCER_SESSION_DURATION) // 1 hour expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL : NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total; - + bool isOffline = checkForExpiration && i2p::transport::transports.GetNumPeers () < NETDB_MIN_TRANSPORTS; // enough routers and uptime, but no tranports + std::list > > saveToDisk; std::list removeFromDisk; @@ -672,7 +673,7 @@ namespace data if (r->GetProfile ()->IsUnreachable ()) r->SetUnreachable (true); // make router reachable back if too few routers or floodfills - if (r->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate || + if (r->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate || isOffline || (r->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS))) r->SetUnreachable (false); if (!r->IsUnreachable ()) diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index b84387de..9d8b875a 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -39,6 +39,7 @@ namespace data { const int NETDB_MIN_ROUTERS = 90; const int NETDB_MIN_FLOODFILLS = 5; + const int NETDB_MIN_TRANSPORTS = 10 ; // otherwise assume offline const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1200; const int NETDB_NUM_ROUTERS_THRESHOLD = 4*NETDB_NUM_FLOODFILLS_THRESHOLD; const int NETDB_TUNNEL_CREATION_RATE_THRESHOLD = 10; // in % From ea14b00d634f1ac547dbaf0bc40b4366c7741a3d Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 21 Oct 2024 20:58:09 -0400 Subject: [PATCH 201/527] save router's endpoint to profile and try to use it next time without requesting introducers --- libi2pd/Profiling.h | 8 ++++++ libi2pd/SSU2.cpp | 59 ++++++++++++++++++++++++++--------------- libi2pd/SSU2.h | 1 + libi2pd/SSU2Session.cpp | 9 +++++++ 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/libi2pd/Profiling.h b/libi2pd/Profiling.h index 1846f08e..be674d95 100644 --- a/libi2pd/Profiling.h +++ b/libi2pd/Profiling.h @@ -11,6 +11,7 @@ #include #include +#include #include "Identity.h" namespace i2p @@ -67,6 +68,11 @@ namespace data bool IsUseful() const; bool IsDuplicated () const { return m_IsDuplicated; }; + + const boost::asio::ip::udp::endpoint& GetLastEndpoint () const { return m_LastEndpoint; } + void SetLastEndpoint (const boost::asio::ip::udp::endpoint& ep) { m_LastEndpoint = ep; } + bool HasLastEndpoint (bool v4) const { return !m_LastEndpoint.address ().is_unspecified () && m_LastEndpoint.port () && + ((v4 && m_LastEndpoint.address ().is_v4 ()) || (!v4 && m_LastEndpoint.address ().is_v6 ())); } private: @@ -90,6 +96,8 @@ namespace data uint32_t m_NumTimesRejected; bool m_HasConnected; // successful trusted(incoming or NTCP2) connection bool m_IsDuplicated; + // connectivity + boost::asio::ip::udp::endpoint m_LastEndpoint; // SSU2 for non-published addresses }; std::shared_ptr GetRouterProfile (const IdentHash& identHash); diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index e96a7233..871b5b05 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -833,6 +833,29 @@ namespace transport } } + bool SSU2Server::CheckPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep, bool peerTest) + { + auto s = FindPendingOutgoingSession (ep); + if (s) + { + if (peerTest) + { + // if peer test requested add it to the list for pending session + auto onEstablished = s->GetOnEstablished (); + if (onEstablished) + s->SetOnEstablished ([s, onEstablished]() + { + onEstablished (); + s->SendPeerTest (); + }); + else + s->SetOnEstablished ([s]() { s->SendPeerTest (); }); + } + return true; + } + return false; + } + bool SSU2Server::CreateSession (std::shared_ptr router, std::shared_ptr address, bool peerTest) { @@ -852,34 +875,28 @@ namespace transport if (isValidEndpoint) { if (i2p::transport::transports.IsInReservedRange(address->host)) return false; - auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (address->host, address->port)); - if (s) - { - if (peerTest) - { - // if peer test requested add it to the list for pending session - auto onEstablished = s->GetOnEstablished (); - if (onEstablished) - s->SetOnEstablished ([s, onEstablished]() - { - onEstablished (); - s->SendPeerTest (); - }); - else - s->SetOnEstablished ([s]() { s->SendPeerTest (); }); - } - return false; - } + if (CheckPendingOutgoingSession (boost::asio::ip::udp::endpoint (address->host, address->port), peerTest)) return false; } auto session = std::make_shared (*this, router, address); + if (!isValidEndpoint && router->GetProfile ()->HasLastEndpoint (address->IsV4 ())) + { + // router doesn't publish endpoint, but we connected before and hole punch might be alive + const auto& ep = router->GetProfile ()->GetLastEndpoint (); + if (IsConnectedRecently (ep)) + { + if (CheckPendingOutgoingSession (ep, peerTest)) return false; + session->SetRemoteEndpoint (ep); + isValidEndpoint = true; + } + } if (peerTest) session->SetOnEstablished ([session]() {session->SendPeerTest (); }); - if (address->UsesIntroducer ()) - GetService ().post (std::bind (&SSU2Server::ConnectThroughIntroducer, this, session)); - else if (isValidEndpoint) // we can't connect without endpoint + if (isValidEndpoint) // we know endpoint GetService ().post ([session]() { session->Connect (); }); + else if (address->UsesIntroducer ()) // we don't know endpoint yet + GetService ().post (std::bind (&SSU2Server::ConnectThroughIntroducer, this, session)); else return false; } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 426c6a10..31783d58 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -147,6 +147,7 @@ namespace transport void ScheduleResend (bool more); void HandleResendTimer (const boost::system::error_code& ecode); + bool CheckPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep, bool peerTest); void ConnectThroughIntroducer (std::shared_ptr session); std::vector > FindIntroducers (int maxNumIntroducers, bool v4, const std::unordered_set& excluded); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 17d2c1da..20f21ce5 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -226,6 +226,13 @@ namespace transport if (m_Server.AddPendingOutgoingSession (shared_from_this ())) { m_Server.RemoveSession (GetConnID ()); + // update endpoint in profile because we know it now + auto identity = GetRemoteIdentity (); + if (identity) + { + auto profile = i2p::data::GetRouterProfile (identity->GetIdentHash ()); + if (profile) profile->SetLastEndpoint (m_RemoteEndpoint); + } // connect LogPrint (eLogDebug, "SSU2: Connecting after introduction to ", GetIdentHashBase64()); Connect (); @@ -1169,6 +1176,8 @@ namespace transport " and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ())); return false; } + if (!m_Address->published) + ri->GetProfile ()->SetLastEndpoint (m_RemoteEndpoint); SetRemoteIdentity (ri->GetRouterIdentity ()); AdjustMaxPayloadSize (); m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now From ddf30784eca8375cc0c6a8445400e3e566101a0e Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 21 Oct 2024 21:22:16 -0400 Subject: [PATCH 202/527] connected recently mutex --- libi2pd/SSU2.cpp | 2 ++ libi2pd/SSU2.h | 1 + 2 files changed, 3 insertions(+) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 871b5b05..296b3817 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -219,6 +219,7 @@ namespace transport bool SSU2Server::IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep) { if (!ep.port () || ep.address ().is_unspecified ()) return false; + std::lock_guard l(m_ConnectedRecentlyMutex); auto it = m_ConnectedRecently.find (ep); if (it != m_ConnectedRecently.end ()) { @@ -234,6 +235,7 @@ namespace transport { if (!ep.port () || ep.address ().is_unspecified () || i2p::util::GetSecondsSinceEpoch () > ts + SSU2_HOLE_PUNCH_EXPIRATION) return; + std::lock_guard l(m_ConnectedRecentlyMutex); auto [it, added] = m_ConnectedRecently.try_emplace (ep, ts); if (!added && ts > it->second) it->second = ts; // renew timestamp of existing endpoint diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 31783d58..aac1d02f 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -194,6 +194,7 @@ namespace transport std::shared_ptr m_PendingTimeOffsetFrom; std::mt19937 m_Rng; std::map m_ConnectedRecently; // endpoint -> last activity time in seconds + mutable std::mutex m_ConnectedRecentlyMutex; std::unordered_map, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp) std::list m_ReceivedPacketsQueue; mutable std::mutex m_ReceivedPacketsQueueMutex; From 26901e2945f898c4c3c5161f382374f6840a6dd7 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 23 Oct 2024 20:39:00 -0400 Subject: [PATCH 203/527] try recently connected SSU2 address if no other transports found --- libi2pd/SSU2.cpp | 2 +- libi2pd/Transports.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 296b3817..305cf1a4 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -884,7 +884,7 @@ namespace transport if (!isValidEndpoint && router->GetProfile ()->HasLastEndpoint (address->IsV4 ())) { // router doesn't publish endpoint, but we connected before and hole punch might be alive - const auto& ep = router->GetProfile ()->GetLastEndpoint (); + auto ep = router->GetProfile ()->GetLastEndpoint (); if (IsConnectedRecently (ep)) { if (CheckPendingOutgoingSession (ep, peerTest)) return false; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 549efb63..fc5c42e8 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -672,6 +672,31 @@ namespace transport if (transport & compatibleTransports) peer->priority.push_back (transport); } + if (peer->priority.empty ()) + { + // try recently connected SSU2 if any + auto supportedTransports = context.GetRouterInfo ().GetCompatibleTransports (false) & + peer->router->GetCompatibleTransports (false); + if (supportedTransports & (i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6)) + { + auto ep = peer->router->GetProfile ()->GetLastEndpoint (); + if (!ep.address ().is_unspecified () && ep.port ()) + { + if (ep.address ().is_v4 ()) + { + if ((supportedTransports & i2p::data::RouterInfo::eSSU2V4) && + m_SSU2Server->IsConnectedRecently (ep)) + peer->priority.push_back (i2p::data::RouterInfo::eSSU2V4); + } + else if (ep.address ().is_v6 ()) + { + if ((supportedTransports & i2p::data::RouterInfo::eSSU2V6) && + m_SSU2Server->IsConnectedRecently (ep)) + peer->priority.push_back (i2p::data::RouterInfo::eSSU2V6); + } + } + } + } } void Transports::RequestComplete (std::shared_ptr r, const i2p::data::IdentHash& ident) From 500afe745f364fad292c275c0a022e838c04ec62 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 24 Oct 2024 18:49:11 -0400 Subject: [PATCH 204/527] use min hole punch interval for connection attempts --- libi2pd/SSU2.cpp | 12 ++++++------ libi2pd/SSU2.h | 5 +++-- libi2pd/Transports.cpp | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 305cf1a4..01a3bb6c 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -216,16 +216,16 @@ namespace transport return ep.port (); } - bool SSU2Server::IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep) + bool SSU2Server::IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max) { if (!ep.port () || ep.address ().is_unspecified ()) return false; std::lock_guard l(m_ConnectedRecentlyMutex); auto it = m_ConnectedRecently.find (ep); if (it != m_ConnectedRecently.end ()) { - if (i2p::util::GetSecondsSinceEpoch () <= it->second + SSU2_HOLE_PUNCH_EXPIRATION) + if (i2p::util::GetSecondsSinceEpoch () <= it->second + (max ? SSU2_MAX_HOLE_PUNCH_EXPIRATION : SSU2_MIN_HOLE_PUNCH_EXPIRATION)) return true; - else + else if (max) m_ConnectedRecently.erase (it); } return false; @@ -234,7 +234,7 @@ namespace transport void SSU2Server::AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts) { if (!ep.port () || ep.address ().is_unspecified () || - i2p::util::GetSecondsSinceEpoch () > ts + SSU2_HOLE_PUNCH_EXPIRATION) return; + i2p::util::GetSecondsSinceEpoch () > ts + SSU2_MAX_HOLE_PUNCH_EXPIRATION) return; std::lock_guard l(m_ConnectedRecentlyMutex); auto [it, added] = m_ConnectedRecently.try_emplace (ep, ts); if (!added && ts > it->second) @@ -885,7 +885,7 @@ namespace transport { // router doesn't publish endpoint, but we connected before and hole punch might be alive auto ep = router->GetProfile ()->GetLastEndpoint (); - if (IsConnectedRecently (ep)) + if (IsConnectedRecently (ep, false)) { if (CheckPendingOutgoingSession (ep, peerTest)) return false; session->SetRemoteEndpoint (ep); @@ -1148,7 +1148,7 @@ namespace transport for (auto it = m_ConnectedRecently.begin (); it != m_ConnectedRecently.end (); ) { - if (ts > it->second + SSU2_HOLE_PUNCH_EXPIRATION) + if (ts > it->second + SSU2_MAX_HOLE_PUNCH_EXPIRATION) it = m_ConnectedRecently.erase (it); else it++; diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index aac1d02f..0433033d 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -42,7 +42,8 @@ namespace transport const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds - const int SSU2_HOLE_PUNCH_EXPIRATION = 150; // in seconds + const int SSU2_MIN_HOLE_PUNCH_EXPIRATION = 45; // in seconds + const int SSU2_MAX_HOLE_PUNCH_EXPIRATION = 181; // in seconds const size_t SSU2_MAX_NUM_PACKETS_PER_BATCH = 64; class SSU2Server: private i2p::util::RunnableServiceWithWork @@ -77,7 +78,7 @@ namespace transport bool UsesProxy () const { return m_IsThroughProxy; }; bool IsSupported (const boost::asio::ip::address& addr) const; uint16_t GetPort (bool v4) const; - bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep); + bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max = true); void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts); std::mt19937& GetRng () { return m_Rng; } bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; } diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index fc5c42e8..34bc6142 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -685,7 +685,7 @@ namespace transport if (ep.address ().is_v4 ()) { if ((supportedTransports & i2p::data::RouterInfo::eSSU2V4) && - m_SSU2Server->IsConnectedRecently (ep)) + m_SSU2Server->IsConnectedRecently (ep, false)) peer->priority.push_back (i2p::data::RouterInfo::eSSU2V4); } else if (ep.address ().is_v6 ()) From d3630fb2b2fa09a7ae33fe794815d4c85db72091 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 25 Oct 2024 13:25:33 -0400 Subject: [PATCH 205/527] assign name to main thread --- daemon/UnixDaemon.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/daemon/UnixDaemon.cpp b/daemon/UnixDaemon.cpp index d1eb1c39..9414962d 100644 --- a/daemon/UnixDaemon.cpp +++ b/daemon/UnixDaemon.cpp @@ -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 * @@ -25,6 +25,7 @@ #include "RouterContext.h" #include "ClientContext.h" #include "Transports.h" +#include "util.h" void handle_signal(int sig) { @@ -220,6 +221,7 @@ namespace i2p void DaemonLinux::run () { + i2p::util::SetThreadName ("Daemon"); while (running) { std::this_thread::sleep_for (std::chrono::seconds(1)); From 87ae9c4b742c2112c95343d132a87b8e775c96f8 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 25 Oct 2024 18:40:51 -0400 Subject: [PATCH 206/527] call main thread as i2pd-daemon --- daemon/UnixDaemon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/UnixDaemon.cpp b/daemon/UnixDaemon.cpp index 9414962d..66661e0f 100644 --- a/daemon/UnixDaemon.cpp +++ b/daemon/UnixDaemon.cpp @@ -221,7 +221,7 @@ namespace i2p void DaemonLinux::run () { - i2p::util::SetThreadName ("Daemon"); + i2p::util::SetThreadName ("i2pd-daemon"); while (running) { std::this_thread::sleep_for (std::chrono::seconds(1)); From f611136ea795868e43a357e60a239c75c6ec8210 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 26 Oct 2024 15:30:48 -0400 Subject: [PATCH 207/527] resend relay reponnse if remote router >= 0.9.64 --- libi2pd/SSU2Session.cpp | 30 ++++++++++++++++++------------ libi2pd/SSU2Session.h | 3 +++ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 20f21ce5..8a1a44df 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -83,7 +83,7 @@ namespace transport std::shared_ptr addr, bool noise): TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT), m_Server (server), m_Address (addr), m_RemoteTransports (0), m_RemotePeerTestTransports (0), - m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), + m_RemoteVersion (0), m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), m_SendPacketNum (0), m_ReceivePacketNum (0), m_LastDatetimeSentPacketNum (0), m_IsDataReceived (false), m_RTT (SSU2_UNKNOWN_RTT), m_MsgLocalExpirationTimeout (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX), @@ -103,6 +103,7 @@ namespace transport InitNoiseXKState1 (*m_NoiseState, m_Address->s); m_RemoteEndpoint = boost::asio::ip::udp::endpoint (m_Address->host, m_Address->port); m_RemoteTransports = in_RemoteRouter->GetCompatibleTransports (false); + m_RemoteVersion = in_RemoteRouter->GetVersion (); if (in_RemoteRouter->IsSSU2PeerTesting (true)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V4; if (in_RemoteRouter->IsSSU2PeerTesting (false)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V6; RAND_bytes ((uint8_t *)&m_DestConnID, 8); @@ -1185,7 +1186,8 @@ namespace transport m_RemotePeerTestTransports = 0; if (ri->IsSSU2PeerTesting (true)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V4; if (ri->IsSSU2PeerTesting (false)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V6; - + m_RemoteVersion = ri->GetVersion (); + // handle other blocks HandlePayload (decryptedPayload.data () + riSize + 3, decryptedPayload.size () - riSize - 3); Established (); @@ -2037,11 +2039,13 @@ namespace transport holePunchSession->SendHolePunch (packet->payload, packet->payloadSize); // relay response block } packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); - /*uint32_t packetNum = */SendData (packet->payload, packet->payloadSize); - // sometimes Bob doesn't ack this RelayResponse - // TODO: uncomment line below once the problem is resolved - //packet->sendTime = mts; - //m_SentPackets.emplace (packetNum, packet); + uint32_t packetNum = SendData (packet->payload, packet->payloadSize); + if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION) + { + // sometimes Bob doesn't ack this RelayResponse in older versions + packet->sendTime = i2p::util::GetMillisecondsSinceEpoch (); + m_SentPackets.emplace (packetNum, packet); + } } void SSU2Session::HandleRelayResponse (const uint8_t * buf, size_t len) @@ -2076,11 +2080,13 @@ namespace transport memcpy (payload + 3, buf, len); // forward to Alice as is packet->payloadSize = len + 3; packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); - /*uint32_t packetNum = */it->second.first->SendData (packet->payload, packet->payloadSize); - // sometimes Alice doesn't ack this RelayResponse - // TODO: uncomment line below once the problem is resolved - //packet->sendTime = i2p::util::GetMillisecondsSinceEpoch (); - //it->second.first->m_SentPackets.emplace (packetNum, packet); + uint32_t packetNum = it->second.first->SendData (packet->payload, packet->payloadSize); + if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION) + { + // sometimes Alice doesn't ack this RelayResponse in older versions + packet->sendTime = i2p::util::GetMillisecondsSinceEpoch (); + it->second.first->m_SentPackets.emplace (packetNum, packet); + } } else { diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index e27671f8..d54731dc 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -15,6 +15,7 @@ #include #include #include +#include "version.h" #include "Crypto.h" #include "RouterInfo.h" #include "RouterContext.h" @@ -55,6 +56,7 @@ namespace transport const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64; const int SSU2_SEND_DATETIME_NUM_PACKETS = 256; + const int SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION = MAKE_VERSION_NUMBER(0, 9, 64); // 0.9.64 // flags const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01; @@ -368,6 +370,7 @@ namespace transport std::shared_ptr m_Address; boost::asio::ip::udp::endpoint m_RemoteEndpoint; i2p::data::RouterInfo::CompatibleTransports m_RemoteTransports, m_RemotePeerTestTransports; + int m_RemoteVersion; uint64_t m_DestConnID, m_SourceConnID; SSU2SessionState m_State; uint8_t m_KeyDataSend[64], m_KeyDataReceive[64]; From 743126b2ad11f774363fd41e280cbeb2806aa675 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 26 Oct 2024 19:05:08 -0400 Subject: [PATCH 208/527] better hole punch expiration intervals --- libi2pd/SSU2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 0433033d..6f51f955 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -42,8 +42,8 @@ namespace transport const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds - const int SSU2_MIN_HOLE_PUNCH_EXPIRATION = 45; // in seconds - const int SSU2_MAX_HOLE_PUNCH_EXPIRATION = 181; // in seconds + const int SSU2_MIN_HOLE_PUNCH_EXPIRATION = 30; // in seconds + const int SSU2_MAX_HOLE_PUNCH_EXPIRATION = 160; // in seconds const size_t SSU2_MAX_NUM_PACKETS_PER_BATCH = 64; class SSU2Server: private i2p::util::RunnableServiceWithWork From 7461b640e32fdd8cabe42557051f59fae166c3b5 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 26 Oct 2024 19:26:25 -0400 Subject: [PATCH 209/527] reduce CPU usage --- libi2pd/Streaming.cpp | 16 +++++++++++++--- libi2pd/Streaming.h | 3 ++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index f22e724d..f9257974 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1237,7 +1237,8 @@ namespace stream if (m_Status != eStreamStatusTerminated) { m_SendTimer.cancel (); - m_SendTimer.expires_from_now (boost::posix_time::microseconds(SEND_INTERVAL)); + m_SendTimer.expires_from_now (boost::posix_time::microseconds( + SEND_INTERVAL + m_LocalDestination.GetRandom () % SEND_INTERVAL_VARIANCE)); m_SendTimer.async_wait (std::bind (&Stream::HandleSendTimer, shared_from_this (), std::placeholders::_1)); } @@ -1250,8 +1251,17 @@ namespace stream auto ts = i2p::util::GetMillisecondsSinceEpoch (); if (m_LastSendTime && ts*1000 > m_LastSendTime*1000 + m_PacingTime) { - m_NumPacketsToSend = ((ts*1000 - m_LastSendTime*1000) + m_PacingTimeRem) / m_PacingTime; - m_PacingTimeRem = ((ts*1000 - m_LastSendTime*1000) + m_PacingTimeRem) - (m_NumPacketsToSend * m_PacingTime); + if (m_PacingTime) + { + auto numPackets = std::lldiv (m_PacingTimeRem + ts*1000 - m_LastSendTime*1000, m_PacingTime); + m_NumPacketsToSend = numPackets.quot; + m_PacingTimeRem = numPackets.rem; + } + else + { + LogPrint (eLogError, "Streaming: pacing time is zero"); + m_NumPacketsToSend = 1; m_PacingTimeRem = 0; + } m_IsSendTime = true; if (m_WindowIncCounter && m_WindowSize < MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) { diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 8183bdad..a686d71b 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -69,7 +69,8 @@ namespace stream const int PENDING_INCOMING_TIMEOUT = 10; // in seconds const int MAX_RECEIVE_TIMEOUT = 20; // in seconds const uint16_t DELAY_CHOKING = 60000; // in milliseconds - const uint64_t SEND_INTERVAL = 1000; // in microseconds + const uint64_t SEND_INTERVAL = 10000; // in microseconds + const uint64_t SEND_INTERVAL_VARIANCE = 2000; // in microseconds const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL = 7500; // in milliseconds const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL_VARIANCE = 3200; // in milliseconds const bool LOSS_BASED_CONTROL_ENABLED = 1; // 0/1 From 608056dcd2dcf999a4541ca66bdb78caade4b9b1 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 27 Oct 2024 11:55:10 -0400 Subject: [PATCH 210/527] don't handle RelayRequest and RelayIntro with same nonce twice --- libi2pd/SSU2.cpp | 4 +++- libi2pd/SSU2.h | 2 +- libi2pd/SSU2Session.cpp | 50 ++++++++++++++++++++++++----------------- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 01a3bb6c..c8f2909b 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -477,7 +477,7 @@ namespace transport HandleReceivedPackets (std::move (receivedPackets)); } - void SSU2Server::AddSession (std::shared_ptr session) + bool SSU2Server::AddSession (std::shared_ptr session) { if (session) { @@ -485,8 +485,10 @@ namespace transport { if (session->GetState () != eSSU2SessionStatePeerTest) AddSessionByRouterHash (session); + return true; } } + return false; } void SSU2Server::RemoveSession (uint64_t connID) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 6f51f955..319a4780 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -85,7 +85,7 @@ namespace transport bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; void AdjustTimeOffset (int64_t offset, std::shared_ptr from); - void AddSession (std::shared_ptr session); + bool AddSession (std::shared_ptr session); void RemoveSession (uint64_t connID); void RequestRemoveSession (uint64_t connID); void AddSessionByRouterHash (std::shared_ptr session); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 8a1a44df..15cabac9 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1931,25 +1931,28 @@ namespace transport return; } auto mts = i2p::util::GetMillisecondsSinceEpoch (); - session->m_RelaySessions.emplace (bufbe32toh (buf + 1), // nonce - std::make_pair (shared_from_this (), mts/1000) ); + uint32_t nonce = bufbe32toh (buf + 1); + if (session->m_RelaySessions.emplace (nonce, std::make_pair (shared_from_this (), mts/1000)).second) + { + // send relay intro to Charlie + auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); // Alice's RI + if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; + if (!r) LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found"); - // send relay intro to Charlie - auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); // Alice's RI - if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; - if (!r) LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found"); - - auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); - packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; - if (!packet->payloadSize && r) - session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); - packet->payloadSize += CreateRelayIntroBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, buf + 1, len -1); - if (packet->payloadSize < m_MaxPayloadSize) - packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); - uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize); - packet->sendTime = mts; - // Charlie always responds with RelayResponse - session->m_SentPackets.emplace (packetNum, packet); + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); + packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; + if (!packet->payloadSize && r) + session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); + packet->payloadSize += CreateRelayIntroBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, buf + 1, len -1); + if (packet->payloadSize < m_MaxPayloadSize) + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize); + packet->sendTime = mts; + // Charlie always responds with RelayResponse + session->m_SentPackets.emplace (packetNum, packet); + } + else + LogPrint (eLogInfo, "SSU2: Relay request nonce ", nonce, " already exists. Ignore"); } void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len, int attempts) @@ -2035,8 +2038,13 @@ namespace transport { // send HolePunch auto holePunchSession = std::make_shared(m_Server, nonce, ep, addr); - m_Server.AddSession (holePunchSession); - holePunchSession->SendHolePunch (packet->payload, packet->payloadSize); // relay response block + if (m_Server.AddSession (holePunchSession)) + holePunchSession->SendHolePunch (packet->payload, packet->payloadSize); // relay response block + else + { + LogPrint (eLogInfo, "SSU2: Relay intro nonce ", nonce, " already exists. Ignore"); + return; + } } packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); uint32_t packetNum = SendData (packet->payload, packet->payloadSize); @@ -3043,7 +3051,7 @@ namespace transport { if (ts > it->second.second + SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT) { - LogPrint (eLogWarning, "SSU2: Relay nonce ", it->first, " was not responded in ", SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT, " seconds, deleted"); + LogPrint (eLogInfo, "SSU2: Relay nonce ", it->first, " was not responded in ", SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT, " seconds, deleted"); it = m_RelaySessions.erase (it); } else From 79e8ccbb5b2f4306208f8fe776dd09566963fbea Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 27 Oct 2024 12:24:22 -0400 Subject: [PATCH 211/527] don't handle PeerTest 1 with same nonce twice --- libi2pd/SSU2Session.cpp | 42 ++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 15cabac9..3489a6ba 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2162,29 +2162,33 @@ namespace transport GetRemoteIdentity ()->GetIdentHash ()); if (session) // session with Charlie { - m_Server.AddPeerTest (nonce, shared_from_this (), ts/1000); - auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); - // Alice's RouterInfo - auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); - if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; - packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; - if (!packet->payloadSize && r) - session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); - if (packet->payloadSize + len + 48 > m_MaxPayloadSize) - { - // doesn't fit one message, send RouterInfo in separate message + if (m_Server.AddPeerTest (nonce, shared_from_this (), ts/1000)) + { + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); + // Alice's RouterInfo + auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); + if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; + packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; + if (!packet->payloadSize && r) + session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); + if (packet->payloadSize + len + 48 > m_MaxPayloadSize) + { + // doesn't fit one message, send RouterInfo in separate message + uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); + packet->sendTime = ts; + session->m_SentPackets.emplace (packetNum, packet); + packet = m_Server.GetSentPacketsPool ().AcquireShared (); // new packet + } + // PeerTest to Charlie + packet->payloadSize += CreatePeerTestBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, 2, + eSSU2PeerTestCodeAccept, GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); packet->sendTime = ts; session->m_SentPackets.emplace (packetNum, packet); - packet = m_Server.GetSentPacketsPool ().AcquireShared (); // new packet } - // PeerTest to Charlie - packet->payloadSize += CreatePeerTestBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, 2, - eSSU2PeerTestCodeAccept, GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); - packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); - uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); - packet->sendTime = ts; - session->m_SentPackets.emplace (packetNum, packet); + else + LogPrint (eLogInfo, "SSU2: Peer test 1 nonce ", nonce, " already exists. Ignored"); } else { From ec4fe9a1e680e677b94fab21c7febd8151478ab4 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 27 Oct 2024 18:17:28 -0400 Subject: [PATCH 212/527] set congesion cap G if symmetric NAT and ipv4 in only transport --- libi2pd/RouterContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 1efb25db..f5f8b4fb 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -1489,7 +1489,7 @@ namespace i2p void RouterContext::UpdateCongestion () { auto c = i2p::data::RouterInfo::eLowCongestion; - if (!AcceptsTunnels () || !m_ShareRatio) + if (!AcceptsTunnels () || !m_ShareRatio || (m_Error == eRouterErrorSymmetricNAT && !SupportsV6 () && !SupportsMesh ())) c = i2p::data::RouterInfo::eRejectAll; else { From 4c66608caf0971902df0a528ea5738802d2fe828 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 27 Oct 2024 21:58:19 -0400 Subject: [PATCH 213/527] random tunnel reject when medium congestion --- libi2pd/I2NPProtocol.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 3b2c204e..198f798b 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -396,8 +396,26 @@ namespace i2p return false; } uint8_t retCode = 0; + // decide if we should accept tunnel + bool accept = i2p::context.AcceptsTunnels (); + if (accept) + { + auto congestionLevel = i2p::context.GetCongestionLevel (false); + if (congestionLevel >= CONGESTION_LEVEL_MEDIUM) + { + if (congestionLevel < CONGESTION_LEVEL_FULL) + { + // random reject depending on congestion level + int level = i2p::tunnel::tunnels.GetRng ()() % (CONGESTION_LEVEL_FULL - CONGESTION_LEVEL_MEDIUM) + CONGESTION_LEVEL_MEDIUM; + if (congestionLevel > level) + accept = false; + } + else + accept = false; + } + } // replace record to reply - if (i2p::context.AcceptsTunnels () && i2p::context.GetCongestionLevel (false) < CONGESTION_LEVEL_FULL) + if (accept) { auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), From 43939cedf4aa0ba2db17b96ba424f132daf9f079 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 27 Oct 2024 22:19:06 -0400 Subject: [PATCH 214/527] random tunnel reject when medium congestion --- libi2pd/Tunnel.cpp | 3 ++- libi2pd/Tunnel.h | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index c41bb775..1e2a75d9 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -350,7 +350,8 @@ namespace tunnel Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr), m_MaxNumTransitTunnels (DEFAULT_MAX_NUM_TRANSIT_TUNNELS), m_TotalNumSuccesiveTunnelCreations (0), m_TotalNumFailedTunnelCreations (0), // for normal average - m_TunnelCreationSuccessRate (TCSR_START_VALUE), m_TunnelCreationAttemptsNum(0) + m_TunnelCreationSuccessRate (TCSR_START_VALUE), m_TunnelCreationAttemptsNum(0), + m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL) { } diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 00a05386..02bfb374 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "util.h" #include "Queue.h" #include "Crypto.h" @@ -244,6 +245,8 @@ namespace tunnel uint32_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; }; int GetCongestionLevel() const { return m_MaxNumTransitTunnels ? CONGESTION_LEVEL_FULL * m_TransitTunnels.size() / m_MaxNumTransitTunnels : CONGESTION_LEVEL_FULL; } + std::mt19937& GetRng () { return m_Rng; }; + private: template @@ -307,6 +310,7 @@ namespace tunnel int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations; double m_TunnelCreationSuccessRate; int m_TunnelCreationAttemptsNum; + std::mt19937 m_Rng; public: From 8f9874570a01698fe739b759feed4e0a8d67148b Mon Sep 17 00:00:00 2001 From: mittwerk Date: Mon, 28 Oct 2024 09:11:09 +0200 Subject: [PATCH 215/527] hardening iterator --- libi2pd_client/UDPTunnel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/UDPTunnel.cpp b/libi2pd_client/UDPTunnel.cpp index cd17bbf0..9f7fe864 100644 --- a/libi2pd_client/UDPTunnel.cpp +++ b/libi2pd_client/UDPTunnel.cpp @@ -203,7 +203,7 @@ namespace client std::vector > sessions; std::lock_guard lock (m_SessionsMutex); - for (auto it: m_Sessions) + for (const auto &it: m_Sessions) { auto s = it.second; if (!s->m_Destination) continue; From 0e8d624d861bd08c705e8390f98609e3876d0acf Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 28 Oct 2024 08:38:04 -0400 Subject: [PATCH 216/527] move UpdatePacingTime out of loop --- libi2pd/Streaming.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index f9257974..966c172d 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1276,10 +1276,12 @@ namespace stream else m_WindowSize += (m_WindowSize - (1 - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize; if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; - m_WindowIncCounter --; - UpdatePacingTime (); + m_WindowIncCounter--; } + else + break; } + UpdatePacingTime (); } if (m_IsNAcked) ResendPacket (); From ec67f48d855c196669938a2da71064da8a501d4b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 28 Oct 2024 08:46:01 -0400 Subject: [PATCH 217/527] fixed possible memory leak --- libi2pd/NTCP2.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 728ac01d..a05469f1 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1822,7 +1822,7 @@ namespace transport LogPrint(eLogError, "NTCP2: HTTP proxy write error ", ec.message()); }); - boost::asio::streambuf * readbuff = new boost::asio::streambuf; + auto readbuff = std::make_shared(); boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n", [readbuff, timer, conn] (const boost::system::error_code & ec, std::size_t transferred) { @@ -1842,7 +1842,6 @@ namespace transport { timer->cancel(); conn->ClientLogin(); - delete readbuff; return; } else @@ -1852,7 +1851,6 @@ namespace transport LogPrint(eLogError, "NTCP2: HTTP proxy gave malformed response"); timer->cancel(); conn->Terminate(); - delete readbuff; } }); break; From 23e66671c2fcd1fc11abd11f07ec18f93a346aab Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 28 Oct 2024 20:36:50 -0400 Subject: [PATCH 218/527] intermediate queue for transport sessions. use std::list instead std::vector for multiple I2NP messages --- libi2pd/NTCP2.cpp | 40 ++++++++++++++++++++++++++++---------- libi2pd/NTCP2.h | 9 ++++++--- libi2pd/NetDb.cpp | 2 +- libi2pd/SSU2Session.cpp | 25 +++++++++++++++++++----- libi2pd/SSU2Session.h | 6 ++++-- libi2pd/TransportSession.h | 8 ++++++-- libi2pd/Transports.cpp | 36 ++++++++++++++++++++++++---------- libi2pd/Transports.h | 7 ++++--- libi2pd/TunnelGateway.cpp | 2 +- 9 files changed, 98 insertions(+), 37 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index a05469f1..747dc0b0 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -375,6 +375,8 @@ namespace transport m_Socket.close (); transports.PeerDisconnected (shared_from_this ()); m_Server.RemoveNTCP2Session (shared_from_this ()); + if (!m_IntermediateQueue.empty ()) + m_SendQueue.splice (m_SendQueue.end (), m_IntermediateQueue); for (auto& it: m_SendQueue) it->Drop (); m_SendQueue.clear (); @@ -1207,7 +1209,7 @@ namespace transport void NTCP2Session::MoveSendQueue (std::shared_ptr other) { if (!other || m_SendQueue.empty ()) return; - std::vector > msgs; + std::list > msgs; auto ts = i2p::util::GetMillisecondsSinceEpoch (); for (auto it: m_SendQueue) if (!it->IsExpired (ts)) @@ -1216,7 +1218,7 @@ namespace transport it->Drop (); m_SendQueue.clear (); if (!msgs.empty ()) - other->PostI2NPMessages (msgs); + other->SendI2NPMessages (msgs); } size_t NTCP2Session::CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len) @@ -1297,20 +1299,38 @@ namespace transport m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); // let termination message go } - void NTCP2Session::SendI2NPMessages (const std::vector >& msgs) + void NTCP2Session::SendI2NPMessages (std::list >& msgs) { - m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this (), msgs)); + if (m_IsTerminated || msgs.empty ()) return; + bool empty = false; + { + std::lock_guard l(m_IntermediateQueueMutex); + empty = m_IntermediateQueue.empty (); + m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs); + } + if (empty) + m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this ())); } - void NTCP2Session::PostI2NPMessages (std::vector > msgs) + void NTCP2Session::PostI2NPMessages () { if (m_IsTerminated) return; + std::list > msgs; + { + std::lock_guard l(m_IntermediateQueueMutex); + m_IntermediateQueue.swap (msgs); + } bool isSemiFull = m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE/2; - for (auto it: msgs) - if (isSemiFull && it->onDrop) - it->Drop (); // drop earlier because we can handle it - else - m_SendQueue.push_back (std::move (it)); + if (isSemiFull) + { + for (auto it: msgs) + if (it->onDrop) + it->Drop (); // drop earlier because we can handle it + else + m_SendQueue.push_back (std::move (it)); + } + else + m_SendQueue.splice (m_SendQueue.end (), msgs); if (!m_IsSending && m_IsEstablished) SendQueue (); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index f7912b54..27acb529 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -153,7 +153,7 @@ namespace transport void ServerLogin (); // Bob void SendLocalRouterInfo (bool update) override; // after handshake or by update - void SendI2NPMessages (const std::vector >& msgs) override; + void SendI2NPMessages (std::list >& msgs) override; void MoveSendQueue (std::shared_ptr other); private: @@ -196,7 +196,7 @@ namespace transport void SendRouterInfo (); void SendTermination (NTCP2TerminationReason reason); void SendTerminationAndTerminate (NTCP2TerminationReason reason); - void PostI2NPMessages (std::vector > msgs); + void PostI2NPMessages (); private: @@ -229,7 +229,10 @@ namespace transport bool m_IsSending, m_IsReceiving; std::list > m_SendQueue; uint64_t m_NextRouterInfoResendTime; // seconds since epoch - + + std::list > m_IntermediateQueue; // from transports + mutable std::mutex m_IntermediateQueueMutex; + uint16_t m_PaddingSizes[16]; int m_NextPaddingSize; }; diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 341d617e..c96bcf95 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -480,7 +480,7 @@ namespace data void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills) { LogPrint(eLogInfo, "NetDB: Reseeding from floodfill ", ri.GetIdentHashBase64()); - std::vector > requests; + std::list > requests; i2p::data::IdentHash ourIdent = i2p::context.GetIdentHash(); i2p::data::IdentHash ih = ri.GetIdentHash(); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 3489a6ba..9ceb491e 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -293,6 +293,8 @@ namespace transport m_SentHandshakePacket.reset (nullptr); m_SessionConfirmedFragment.reset (nullptr); m_PathChallenge.reset (nullptr); + if (!m_IntermediateQueue.empty ()) + m_SendQueue.splice (m_SendQueue.end (), m_IntermediateQueue); for (auto& it: m_SendQueue) it->Drop (); m_SendQueue.clear (); @@ -372,14 +374,27 @@ namespace transport } - void SSU2Session::SendI2NPMessages (const std::vector >& msgs) + void SSU2Session::SendI2NPMessages (std::list >& msgs) { - m_Server.GetService ().post (std::bind (&SSU2Session::PostI2NPMessages, shared_from_this (), msgs)); + if (m_State == eSSU2SessionStateTerminated || msgs.empty ()) return; + bool empty = false; + { + std::lock_guard l(m_IntermediateQueueMutex); + empty = m_IntermediateQueue.empty (); + m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs); + } + if (empty) + m_Server.GetService ().post (std::bind (&SSU2Session::PostI2NPMessages, shared_from_this ())); } - void SSU2Session::PostI2NPMessages (std::vector > msgs) + void SSU2Session::PostI2NPMessages () { if (m_State == eSSU2SessionStateTerminated) return; + std::list > msgs; + { + std::lock_guard l(m_IntermediateQueueMutex); + m_IntermediateQueue.swap (msgs); + } uint64_t mts = i2p::util::GetMonotonicMicroseconds (); bool isSemiFull = false; if (m_SendQueue.size ()) @@ -415,7 +430,7 @@ namespace transport void SSU2Session::MoveSendQueue (std::shared_ptr other) { if (!other || m_SendQueue.empty ()) return; - std::vector > msgs; + std::list > msgs; auto ts = i2p::util::GetMillisecondsSinceEpoch (); for (auto it: m_SendQueue) if (!it->IsExpired (ts)) @@ -424,7 +439,7 @@ namespace transport it->Drop (); m_SendQueue.clear (); if (!msgs.empty ()) - other->PostI2NPMessages (msgs); + other->SendI2NPMessages (msgs); } bool SSU2Session::SendQueue () diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index d54731dc..4b3139a7 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -261,7 +261,7 @@ namespace transport void FlushData (); void Done () override; void SendLocalRouterInfo (bool update) override; - void SendI2NPMessages (const std::vector >& msgs) override; + void SendI2NPMessages (std::list >& msgs) override; void MoveSendQueue (std::shared_ptr other); uint32_t GetRelayTag () const override { return m_RelayTag; }; size_t Resend (uint64_t ts); // return number of resent packets @@ -307,7 +307,7 @@ namespace transport void Established (); void ScheduleConnectTimer (); void HandleConnectTimer (const boost::system::error_code& ecode); - void PostI2NPMessages (std::vector > msgs); + void PostI2NPMessages (); bool SendQueue (); // returns true if ack block was sent bool SendFragmentedMessage (std::shared_ptr msg); void ResendHandshakePacket (); @@ -381,6 +381,8 @@ namespace transport std::unordered_map, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice std::list > m_SendQueue; i2p::I2NPMessagesHandler m_Handler; + std::list > m_IntermediateQueue; // from transports + mutable std::mutex m_IntermediateQueueMutex; bool m_IsDataReceived; double m_RTT; int m_MsgLocalExpirationTimeout; diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index c6bf0de3..6c878d11 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -144,8 +144,12 @@ namespace transport void SetLastActivityTimestamp (uint64_t ts) { m_LastActivityTimestamp = ts; }; virtual uint32_t GetRelayTag () const { return 0; }; - virtual void SendLocalRouterInfo (bool update = false) { SendI2NPMessages ({ CreateDatabaseStoreMsg () }); }; - virtual void SendI2NPMessages (const std::vector >& msgs) = 0; + virtual void SendLocalRouterInfo (bool update = false) + { + std::list > msgs{ CreateDatabaseStoreMsg () }; + SendI2NPMessages (msgs); + }; + virtual void SendI2NPMessages (std::list >& msgs) = 0; virtual bool IsEstablished () const = 0; private: diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 34bc6142..3954e2cf 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -450,15 +450,23 @@ namespace transport void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg) { if (m_IsOnline) - SendMessages (ident, std::vector > {msg }); + SendMessages (ident, { msg }); } - void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector >& msgs) + void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::list >& msgs) { m_Service->post (std::bind (&Transports::PostMessages, this, ident, msgs)); } - void Transports::PostMessages (i2p::data::IdentHash ident, std::vector > msgs) + void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list >&& msgs) + { + m_Service->post ([this, ident, msgs = std::move(msgs)] () + { + PostMessages (ident, msgs); + }); + } + + void Transports::PostMessages (i2p::data::IdentHash ident, std::list > msgs) { if (ident == i2p::context.GetRouterInfo ().GetIdentHash ()) { @@ -517,11 +525,16 @@ namespace transport return; } } - for (auto& it1: msgs) - if (sz > MAX_NUM_DELAYED_MESSAGES/2 && it1->onDrop) - it1->Drop (); // drop earlier because we can handle it - else - peer->delayedMessages.push_back (it1); + if (sz > MAX_NUM_DELAYED_MESSAGES/2) + { + for (auto& it1: msgs) + if (it1->onDrop) + it1->Drop (); // drop earlier because we can handle it + else + peer->delayedMessages.push_back (it1); + } + else + peer->delayedMessages.splice (peer->delayedMessages.end (), msgs); } else { @@ -865,7 +878,7 @@ namespace transport if (it->second->delayedMessages.size () > 0) { // check if first message is our DatabaseStore (publishing) - auto firstMsg = peer->delayedMessages[0]; + auto firstMsg = peer->delayedMessages.front (); if (firstMsg && firstMsg->GetTypeID () == eI2NPDatabaseStore && i2p::data::IdentHash(firstMsg->GetPayload () + DATABASE_STORE_KEY_OFFSET) == i2p::context.GetIdentHash ()) sendDatabaseStore = false; // we have it in the list already @@ -887,7 +900,10 @@ namespace transport return; } if (!session->IsOutgoing ()) // incoming - session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore + { + std::list > msgs{ CreateDatabaseStoreMsg () }; + session->SendI2NPMessages (msgs); // send DatabaseStore + } auto r = i2p::data::netdb.FindRouter (ident); // router should be in netdb after SessionConfirmed if (r) r->GetProfile ()->Connected (); auto ts = i2p::util::GetSecondsSinceEpoch (); diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 70273094..e18ec29d 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -71,7 +71,7 @@ namespace transport std::shared_ptr router; std::list > sessions; uint64_t creationTime, nextRouterInfoUpdateTime, lastSelectionTime; - std::vector > delayedMessages; + std::list > delayedMessages; std::vector priority; bool isHighBandwidth, isEligible; @@ -141,7 +141,8 @@ namespace transport void ReuseX25519KeysPair (std::shared_ptr pair); void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg); - void SendMessages (const i2p::data::IdentHash& ident, const std::vector >& msgs); + void SendMessages (const i2p::data::IdentHash& ident, const std::list >& msgs); + void SendMessages (const i2p::data::IdentHash& ident, std::list >&& msgs); void PeerConnected (std::shared_ptr session); void PeerDisconnected (std::shared_ptr session); @@ -185,7 +186,7 @@ namespace transport void Run (); void RequestComplete (std::shared_ptr r, const i2p::data::IdentHash& ident); void HandleRequestComplete (std::shared_ptr r, i2p::data::IdentHash ident); - void PostMessages (i2p::data::IdentHash ident, std::vector > msgs); + void PostMessages (i2p::data::IdentHash ident, std::list > msgs); bool ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr peer); void SetPriority (std::shared_ptr peer) const; void HandlePeerCleanupTimer (const boost::system::error_code& ecode); diff --git a/libi2pd/TunnelGateway.cpp b/libi2pd/TunnelGateway.cpp index 85ff224e..77110c39 100644 --- a/libi2pd/TunnelGateway.cpp +++ b/libi2pd/TunnelGateway.cpp @@ -221,7 +221,7 @@ namespace tunnel void TunnelGateway::SendBuffer () { m_Buffer.CompleteCurrentTunnelDataMessage (); - std::vector > newTunnelMsgs; + std::list > newTunnelMsgs; const auto& tunnelDataMsgs = m_Buffer.GetTunnelDataMsgs (); for (auto& tunnelMsg : tunnelDataMsgs) { From 4c90a88b85c736dad7e70ef1e2503a9360358042 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 28 Oct 2024 21:10:30 -0400 Subject: [PATCH 219/527] eliminate extra copy of I2NP messages list --- libi2pd/TransitTunnel.cpp | 5 ++--- libi2pd/Transports.cpp | 9 +++++---- libi2pd/Transports.h | 2 +- libi2pd/TunnelGateway.cpp | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index 6c2c52a7..72d7b8c2 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.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 * @@ -59,8 +59,7 @@ namespace tunnel auto num = m_TunnelDataMsgs.size (); if (num > 1) LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num); - i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs); - m_TunnelDataMsgs.clear (); + i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs); // send and clear } } diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 3954e2cf..d18d3429 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -453,9 +453,11 @@ namespace transport SendMessages (ident, { msg }); } - void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::list >& msgs) + void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list >& msgs) { - m_Service->post (std::bind (&Transports::PostMessages, this, ident, msgs)); + std::list > msgs1; + msgs.swap (msgs1); + SendMessages (ident, std::move (msgs1)); } void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list >&& msgs) @@ -888,8 +890,7 @@ namespace transport else session->SetTerminationTimeout (10); // most likely it's publishing, no follow-up messages expected, set timeout to 10 seconds peer->sessions.push_back (session); - session->SendI2NPMessages (peer->delayedMessages); - peer->delayedMessages.clear (); + session->SendI2NPMessages (peer->delayedMessages); // send and clear } else // incoming connection or peer test { diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index e18ec29d..bfabc6b3 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -141,7 +141,7 @@ namespace transport void ReuseX25519KeysPair (std::shared_ptr pair); void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg); - void SendMessages (const i2p::data::IdentHash& ident, const std::list >& msgs); + void SendMessages (const i2p::data::IdentHash& ident, std::list >& msgs); void SendMessages (const i2p::data::IdentHash& ident, std::list >&& msgs); void PeerConnected (std::shared_ptr session); diff --git a/libi2pd/TunnelGateway.cpp b/libi2pd/TunnelGateway.cpp index 77110c39..78a63fc4 100644 --- a/libi2pd/TunnelGateway.cpp +++ b/libi2pd/TunnelGateway.cpp @@ -234,7 +234,7 @@ namespace tunnel m_NumSentBytes += TUNNEL_DATA_MSG_SIZE; } m_Buffer.ClearTunnelDataMsgs (); - i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), newTunnelMsgs); + i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), std::move (newTunnelMsgs)); } } } From 361f3649667593dd95d2ad6dd79b38959ceaf1b2 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 28 Oct 2024 21:15:16 -0400 Subject: [PATCH 220/527] intermediate queue for transport sessions. use std::list instead std::vector for multiple I2NP messages --- libi2pd/TransitTunnel.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index f83007a9..b3381fb7 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.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 * @@ -10,7 +10,7 @@ #define TRANSIT_TUNNEL_H__ #include -#include +#include #include #include #include "Crypto.h" @@ -61,7 +61,7 @@ namespace tunnel private: size_t m_NumTransmittedBytes; - std::vector > m_TunnelDataMsgs; + std::list > m_TunnelDataMsgs; }; class TransitTunnelGateway: public TransitTunnel From f04048717dc1633c2d21ef2d223f79138b2b03bd Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 28 Oct 2024 21:34:33 -0400 Subject: [PATCH 221/527] cleanup messages to send if session was terminated --- libi2pd/NTCP2.cpp | 6 +++++- libi2pd/SSU2Session.cpp | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 747dc0b0..33c33596 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1301,7 +1301,11 @@ namespace transport void NTCP2Session::SendI2NPMessages (std::list >& msgs) { - if (m_IsTerminated || msgs.empty ()) return; + if (m_IsTerminated || msgs.empty ()) + { + msgs.clear (); + return; + } bool empty = false; { std::lock_guard l(m_IntermediateQueueMutex); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 9ceb491e..5d5d5249 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -376,7 +376,11 @@ namespace transport void SSU2Session::SendI2NPMessages (std::list >& msgs) { - if (m_State == eSSU2SessionStateTerminated || msgs.empty ()) return; + if (m_State == eSSU2SessionStateTerminated || msgs.empty ()) + { + msgs.clear (); + return; + } bool empty = false; { std::lock_guard l(m_IntermediateQueueMutex); From 9bc595a9a2849743e85b3707e6f30163ede676d1 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 29 Oct 2024 08:41:59 -0400 Subject: [PATCH 222/527] eliminate extra copy --- libi2pd/Transports.cpp | 4 ++-- libi2pd/Transports.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index d18d3429..178188f2 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -462,13 +462,13 @@ namespace transport void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list >&& msgs) { - m_Service->post ([this, ident, msgs = std::move(msgs)] () + m_Service->post ([this, ident, msgs = std::move(msgs)] () mutable { PostMessages (ident, msgs); }); } - void Transports::PostMessages (i2p::data::IdentHash ident, std::list > msgs) + void Transports::PostMessages (const i2p::data::IdentHash& ident, std::list >& msgs) { if (ident == i2p::context.GetRouterInfo ().GetIdentHash ()) { diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index bfabc6b3..095cc81a 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -186,7 +186,7 @@ namespace transport void Run (); void RequestComplete (std::shared_ptr r, const i2p::data::IdentHash& ident); void HandleRequestComplete (std::shared_ptr r, i2p::data::IdentHash ident); - void PostMessages (i2p::data::IdentHash ident, std::list > msgs); + void PostMessages (const i2p::data::IdentHash& ident, std::list >& msgs); bool ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr peer); void SetPriority (std::shared_ptr peer) const; void HandlePeerCleanupTimer (const boost::system::error_code& ecode); From 3f10f6651d7b966a23c68621d63389ea35e55839 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 29 Oct 2024 12:46:14 -0400 Subject: [PATCH 223/527] use splice if queue is not semi-full --- libi2pd/SSU2Session.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 5d5d5249..aba8195e 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -412,16 +412,24 @@ namespace transport " is semi-full (size = ", m_SendQueue.size (), ", lag = ", queueLag / 1000, ", rtt = ", (int)m_RTT, ")"); } } - for (auto it: msgs) - { - if (isSemiFull && it->onDrop) - it->Drop (); // drop earlier because we can handle it - else + if (isSemiFull) + { + for (auto it: msgs) { - it->SetEnqueueTime (mts); - m_SendQueue.push_back (std::move (it)); + if (it->onDrop) + it->Drop (); // drop earlier because we can handle it + else + { + it->SetEnqueueTime (mts); + m_SendQueue.push_back (std::move (it)); + } } - } + } + else + { + for (auto& it: msgs) it->SetEnqueueTime (mts); + m_SendQueue.splice (m_SendQueue.end (), msgs); + } if (IsEstablished ()) { SendQueue (); From 8a8277edda0392a3fd99278409b811fc44f9e739 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 29 Oct 2024 13:59:21 -0400 Subject: [PATCH 224/527] check for empty URL string --- libi2pd/HTTP.cpp | 1 + libi2pd_client/AddressBook.cpp | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index 990781bc..258d3ada 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.cpp @@ -103,6 +103,7 @@ namespace http bool URL::parse(std::string_view url) { + if (url.empty ()) return false; std::size_t pos_p = 0; /* < current parse position */ std::size_t pos_c = 0; /* < work position */ if(url.at(0) != '/' || pos_p > 0) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index 14599cf7..802b7996 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -582,16 +582,15 @@ namespace client } else { - LogPrint (eLogInfo, "Addressbook: Loading subscriptions from config file"); + LogPrint (eLogInfo, "Addressbook: Loading subscriptions from config"); // using config file items std::string subscriptionURLs; i2p::config::GetOption("addressbook.subscriptions", subscriptionURLs); std::vector subsList; boost::split(subsList, subscriptionURLs, boost::is_any_of(","), boost::token_compress_on); for (const auto& s: subsList) - { - m_Subscriptions.push_back (std::make_shared (*this, s)); - } + if (!s.empty ()) + m_Subscriptions.push_back (std::make_shared (*this, s)); LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded"); } } @@ -823,7 +822,7 @@ namespace client } } - AddressBookSubscription::AddressBookSubscription (AddressBook& book, const std::string& link): + AddressBookSubscription::AddressBookSubscription (AddressBook& book, std::string_view link): m_Book (book), m_Link (link) { } From 0086f8e27ad0f4fd702838c4782bb057df74ca77 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 29 Oct 2024 15:32:06 -0400 Subject: [PATCH 225/527] use std::async for address book download --- libi2pd_client/AddressBook.cpp | 51 +++++++++++++++++++++------------- libi2pd_client/AddressBook.h | 7 +++-- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index 802b7996..c9452cc6 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -305,7 +305,7 @@ namespace client identHash = hash; } - AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_IsDownloading (false), + AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_NumRetries (0), m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr), m_IsEnabled (true) { @@ -344,20 +344,28 @@ namespace client delete m_SubscriptionsUpdateTimer; m_SubscriptionsUpdateTimer = nullptr; } - if (m_IsDownloading) + bool isDownloading = m_Downloading.valid (); + if (isDownloading) { - LogPrint (eLogInfo, "Addressbook: Subscriptions are downloading, abort"); - for (int i = 0; i < 30; i++) - { - if (!m_IsDownloading) + if (m_Downloading.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + isDownloading = false; + else + { + LogPrint (eLogInfo, "Addressbook: Subscriptions are downloading, abort"); + for (int i = 0; i < 30; i++) { - LogPrint (eLogInfo, "Addressbook: Subscriptions download complete"); - break; + if (m_Downloading.wait_for(std::chrono::seconds(1)) == std::future_status::ready) // wait for 1 seconds + { + isDownloading = false; + LogPrint (eLogInfo, "Addressbook: Subscriptions download complete"); + break; + } } - std::this_thread::sleep_for (std::chrono::seconds (1)); // wait for 1 seconds - } - LogPrint (eLogError, "Addressbook: Subscription download timeout"); - m_IsDownloading = false; + } + if (!isDownloading) + m_Downloading.get (); + else + LogPrint (eLogError, "Addressbook: Subscription download timeout"); } if (m_Storage) { @@ -644,7 +652,6 @@ namespace client void AddressBook::DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified) { - m_IsDownloading = false; m_NumRetries++; int nextUpdateTimeout = m_NumRetries*CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT; if (m_NumRetries > CONTINIOUS_SUBSCRIPTION_MAX_NUM_RETRIES || nextUpdateTimeout > CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT) @@ -699,7 +706,13 @@ namespace client LogPrint(eLogWarning, "Addressbook: Missing local destination, skip subscription update"); return; } - if (!m_IsDownloading && dest->IsReady ()) + bool isDownloading = m_Downloading.valid (); + if (isDownloading && m_Downloading.wait_for(std::chrono::seconds(0)) == std::future_status::ready) // still active? + { + m_Downloading.get (); + isDownloading = false; + } + if (!isDownloading && dest->IsReady ()) { if (!m_IsLoaded) { @@ -708,17 +721,15 @@ namespace client std::string defaultSubURL; i2p::config::GetOption("addressbook.defaulturl", defaultSubURL); if (!m_DefaultSubscription) m_DefaultSubscription = std::make_shared(*this, defaultSubURL); - m_IsDownloading = true; - std::thread load_hosts(std::bind (&AddressBookSubscription::CheckUpdates, m_DefaultSubscription)); - load_hosts.detach(); // TODO: use join + m_Downloading = std::async (std::launch::async, + std::bind (&AddressBookSubscription::CheckUpdates, m_DefaultSubscription)); } else if (!m_Subscriptions.empty ()) { // pick random subscription auto ind = rand () % m_Subscriptions.size(); - m_IsDownloading = true; - std::thread load_hosts(std::bind (&AddressBookSubscription::CheckUpdates, m_Subscriptions[ind])); - load_hosts.detach(); // TODO: use join + m_Downloading = std::async (std::launch::async, + std::bind (&AddressBookSubscription::CheckUpdates, m_Subscriptions[ind])); } } else diff --git a/libi2pd_client/AddressBook.h b/libi2pd_client/AddressBook.h index fc4f19a7..553ae51b 100644 --- a/libi2pd_client/AddressBook.h +++ b/libi2pd_client/AddressBook.h @@ -11,10 +11,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include "Base.h" @@ -124,7 +126,8 @@ namespace client std::mutex m_LookupsMutex; std::map m_Lookups; // nonce -> address AddressBookStorage * m_Storage; - volatile bool m_IsLoaded, m_IsDownloading; + volatile bool m_IsLoaded; + std::future m_Downloading; int m_NumRetries; std::vector > m_Subscriptions; std::shared_ptr m_DefaultSubscription; // in case if we don't know any addresses yet @@ -136,7 +139,7 @@ namespace client { public: - AddressBookSubscription (AddressBook& book, const std::string& link); + AddressBookSubscription (AddressBook& book, std::string_view link); void CheckUpdates (); private: From b2a10ac82b48864262a65fef492ac1165df2f013 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 30 Oct 2024 22:00:12 -0400 Subject: [PATCH 226/527] don't update found router again in RequestComplete --- libi2pd/Transports.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 178188f2..73c58ea2 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -491,9 +491,9 @@ namespace transport { auto r = netdb.FindRouter (ident); if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return; // router found but non-reachable - { - auto ts = i2p::util::GetSecondsSinceEpoch (); - peer = std::make_shared(r, ts); + + peer = std::make_shared(r, i2p::util::GetSecondsSinceEpoch ()); + { std::unique_lock l(m_PeersMutex); peer = m_Peers.emplace (ident, peer).first->second; } @@ -722,7 +722,7 @@ namespace transport void Transports::HandleRequestComplete (std::shared_ptr r, i2p::data::IdentHash ident) { auto it = m_Peers.find (ident); - if (it != m_Peers.end ()) + if (it != m_Peers.end () && !it->second->router) { if (r) { From 2419f52af4c6589d2c0936631edd97639a839624 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 31 Oct 2024 15:01:19 -0400 Subject: [PATCH 227/527] fixed potential race condition --- libi2pd/Transports.cpp | 69 +++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 73c58ea2..98007620 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -480,8 +480,13 @@ namespace transport } if(RoutesRestricted() && !IsRestrictedPeer(ident)) return; std::shared_ptr peer; - auto it = m_Peers.find (ident); - if (it == m_Peers.end ()) + { + std::lock_guard l(m_PeersMutex); + auto it = m_Peers.find (ident); + if (it != m_Peers.end ()) + peer = it->second; + } + if (!peer) { // check if not banned if (i2p::data::IsRouterBanned (ident)) return; // don't create peer to unreachable router @@ -494,7 +499,7 @@ namespace transport peer = std::make_shared(r, i2p::util::GetSecondsSinceEpoch ()); { - std::unique_lock l(m_PeersMutex); + std::lock_guard l(m_PeersMutex); peer = m_Peers.emplace (ident, peer).first->second; } if (peer) @@ -506,8 +511,6 @@ namespace transport } if (!connected) return; } - else - peer = it->second; if (!peer) return; if (peer->IsConnected ()) @@ -522,7 +525,7 @@ namespace transport if (i2p::data::IsRouterBanned (ident)) { LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped"); - std::unique_lock l(m_PeersMutex); + std::lock_guard l(m_PeersMutex); m_Peers.erase (ident); return; } @@ -542,7 +545,7 @@ namespace transport { LogPrint (eLogWarning, "Transports: Delayed messages queue size to ", ident.ToBase64 (), " exceeds ", MAX_NUM_DELAYED_MESSAGES); - std::unique_lock l(m_PeersMutex); + std::lock_guard l(m_PeersMutex); m_Peers.erase (ident); } } @@ -617,7 +620,7 @@ namespace transport if (!i2p::context.IsLimitedConnectivity () && peer->router->IsReachableFrom (i2p::context.GetRouterInfo ())) i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed but router claimed them peer->Done (); - std::unique_lock l(m_PeersMutex); + std::lock_guard l(m_PeersMutex); m_Peers.erase (ident); return false; } @@ -625,7 +628,7 @@ namespace transport { LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped"); peer->Done (); - std::unique_lock l(m_PeersMutex); + std::lock_guard l(m_PeersMutex); m_Peers.erase (ident); return false; } @@ -721,23 +724,29 @@ namespace transport void Transports::HandleRequestComplete (std::shared_ptr r, i2p::data::IdentHash ident) { - auto it = m_Peers.find (ident); - if (it != m_Peers.end () && !it->second->router) + std::shared_ptr peer; { - if (r) + std::lock_guard l(m_PeersMutex); + auto it = m_Peers.find (ident); + if (it != m_Peers.end ()) { - LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect"); - it->second->SetRouter (r); - if (!it->second->IsConnected ()) - ConnectToPeer (ident, it->second); - } - else - { - LogPrint (eLogWarning, "Transports: RouterInfo not found, failed to send messages"); - std::unique_lock l(m_PeersMutex); - m_Peers.erase (it); - } + if (r) + peer = it->second; + else + m_Peers.erase (it); + } } + + if (peer && !peer->router && r) + { + LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect"); + peer->SetRouter (r); + if (!peer->IsConnected ()) + ConnectToPeer (ident, peer); + } + else if (!r) + LogPrint (eLogInfo, "Transports: RouterInfo not found, failed to send messages"); + } void Transports::DetectExternalIP () @@ -911,7 +920,7 @@ namespace transport auto peer = std::make_shared(r, ts); peer->sessions.push_back (session); peer->router = nullptr; - std::unique_lock l(m_PeersMutex); + std::lock_guard l(m_PeersMutex); m_Peers.emplace (ident, peer); } }); @@ -940,7 +949,7 @@ namespace transport } else { - std::unique_lock l(m_PeersMutex); + std::lock_guard l(m_PeersMutex); m_Peers.erase (it); } } @@ -950,9 +959,13 @@ namespace transport bool Transports::IsConnected (const i2p::data::IdentHash& ident) const { - std::unique_lock l(m_PeersMutex); + std::lock_guard l(m_PeersMutex); +#if __cplusplus >= 202002L // C++20 + return m_Peers.contains (ident); +#else auto it = m_Peers.find (ident); return it != m_Peers.end (); +#endif } void Transports::HandlePeerCleanupTimer (const boost::system::error_code& ecode) @@ -976,7 +989,7 @@ namespace transport auto profile = i2p::data::GetRouterProfile (it->first); if (profile) profile->Unreachable (); } */ - std::unique_lock l(m_PeersMutex); + std::lock_guard l(m_PeersMutex); it = m_Peers.erase (it); } else @@ -1026,7 +1039,7 @@ namespace transport { uint16_t inds[3]; RAND_bytes ((uint8_t *)inds, sizeof (inds)); - std::unique_lock l(m_PeersMutex); + std::lock_guard l(m_PeersMutex); auto count = m_Peers.size (); if(count == 0) return nullptr; inds[0] %= count; From 4432c5a2c480db5f408e6e817801d065c98d6ea4 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 31 Oct 2024 18:24:02 -0400 Subject: [PATCH 228/527] update last activity time after sending peer test or hole punch message --- libi2pd/SSU2OutOfSession.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index 262f93a9..651ed76c 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -111,7 +111,6 @@ namespace transport SendPeerTest (7, buf + offset, len - offset); else LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6"); - GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ()); GetServer ().RequestRemoveSession (GetConnID ()); break; } @@ -141,7 +140,6 @@ namespace transport } } } - GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ()); GetServer ().RequestRemoveSession (GetConnID ()); break; } @@ -188,6 +186,7 @@ namespace transport i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16); // send GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ()); + UpdateNumSentBytes (payloadSize + 32); } void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, bool delayed) @@ -309,6 +308,7 @@ namespace transport i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16); // send GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep); + UpdateNumSentBytes (payloadSize + 32); } void SSU2HolePunchSession::SendHolePunch (const uint8_t * relayResponseBlock, size_t relayResponseBlockLen) From b8d61e04f0ca5ce652e193198b5cd4f277fe2a18 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 1 Nov 2024 14:46:13 -0400 Subject: [PATCH 229/527] generate x25519 keys more often --- libi2pd/Transports.cpp | 10 +++++----- libi2pd/Transports.h | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 98007620..6b695371 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -66,12 +66,12 @@ namespace transport while (m_IsRunning) { int num, total = 0; - while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 10) + while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < m_QueueSize) { CreateEphemeralKeys (num); total += num; } - if (total >= 10) + if (total > m_QueueSize) { LogPrint (eLogWarning, "Transports: ", total, " ephemeral keys generated at the time"); std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break @@ -124,12 +124,12 @@ namespace transport { if (pair) { - std::unique_lockl(m_AcquiredMutex); + std::unique_lock l(m_AcquiredMutex); if ((int)m_Queue.size () < 2*m_QueueSize) m_Queue.push (pair); } else - LogPrint(eLogError, "Transports: Return null DHKeys"); + LogPrint(eLogError, "Transports: Return null keys"); } void Peer::UpdateParams (std::shared_ptr router) @@ -149,7 +149,7 @@ namespace transport m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_CheckReserved(true), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr), m_UpdateBandwidthTimer (nullptr), m_SSU2Server (nullptr), m_NTCP2Server (nullptr), - m_X25519KeysPairSupplier (15), // 15 pre-generated keys + m_X25519KeysPairSupplier (NUM_X25519_PRE_GENERATED_KEYS), m_TotalSentBytes (0), m_TotalReceivedBytes (0), m_TotalTransitTransmittedBytes (0), m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth (0), m_InBandwidth15s (0), m_OutBandwidth15s (0), m_TransitBandwidth15s (0), diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 095cc81a..c7eb7677 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -108,7 +108,8 @@ 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 NUM_X25519_PRE_GENERATED_KEYS = 25; // pre-generated x25519 keys pairs + const int TRAFFIC_SAMPLE_COUNT = 301; // seconds struct TrafficSample From 0d09a8be00b1b8ef3d29d82ed9ecc3fb1d7f64ae Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 1 Nov 2024 17:53:27 -0400 Subject: [PATCH 230/527] removed own implementation of x25519 --- libi2pd/Crypto.cpp | 36 ------------------- libi2pd/Crypto.h | 6 ---- libi2pd/Ed25519.cpp | 82 +------------------------------------------ libi2pd/Ed25519.h | 12 ++----- tests/CMakeLists.txt | 7 ---- tests/Makefile | 5 +-- tests/test-x25519.cpp | 38 -------------------- 7 files changed, 4 insertions(+), 182 deletions(-) delete mode 100644 tests/test-x25519.cpp diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 8ce290f1..2371b529 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -240,17 +240,12 @@ namespace crypto // x25519 X25519Keys::X25519Keys () { -#if OPENSSL_X25519 m_Ctx = EVP_PKEY_CTX_new_id (NID_X25519, NULL); m_Pkey = nullptr; -#else - m_Ctx = BN_CTX_new (); -#endif } X25519Keys::X25519Keys (const uint8_t * priv, const uint8_t * pub) { -#if OPENSSL_X25519 m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32); m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); if (pub) @@ -260,29 +255,16 @@ namespace crypto size_t len = 32; EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len); } -#else - m_Ctx = BN_CTX_new (); - memcpy (m_PrivateKey, priv, 32); - if (pub) - memcpy (m_PublicKey, pub, 32); - else - GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx); -#endif } X25519Keys::~X25519Keys () { -#if OPENSSL_X25519 EVP_PKEY_CTX_free (m_Ctx); if (m_Pkey) EVP_PKEY_free (m_Pkey); -#else - BN_CTX_free (m_Ctx); -#endif } void X25519Keys::GenerateKeys () { -#if OPENSSL_X25519 if (m_Pkey) { EVP_PKEY_free (m_Pkey); @@ -294,16 +276,11 @@ namespace crypto m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); // TODO: do we really need to re-create m_Ctx? size_t len = 32; EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len); -#else - RAND_bytes (m_PrivateKey, 32); - GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx); -#endif } bool X25519Keys::Agree (const uint8_t * pub, uint8_t * shared) { if (!pub || (pub[31] & 0x80)) return false; // not x25519 key -#if OPENSSL_X25519 EVP_PKEY_derive_init (m_Ctx); auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub, 32); if (!pkey) return false; @@ -311,25 +288,17 @@ namespace crypto size_t len = 32; EVP_PKEY_derive (m_Ctx, shared, &len); EVP_PKEY_free (pkey); -#else - GetEd25519 ()->ScalarMul (pub, m_PrivateKey, shared, m_Ctx); -#endif return true; } void X25519Keys::GetPrivateKey (uint8_t * priv) const { -#if OPENSSL_X25519 size_t len = 32; EVP_PKEY_get_raw_private_key (m_Pkey, priv, &len); -#else - memcpy (priv, m_PrivateKey, 32); -#endif } void X25519Keys::SetPrivateKey (const uint8_t * priv, bool calculatePublic) { -#if OPENSSL_X25519 if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx); if (m_Pkey) EVP_PKEY_free (m_Pkey); m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32); @@ -339,11 +308,6 @@ namespace crypto size_t len = 32; EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len); } -#else - memcpy (m_PrivateKey, priv, 32); - if (calculatePublic) - GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx); -#endif } // ElGamal diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 13d331c8..75bd7bb2 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -31,7 +31,6 @@ #if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1 # define OPENSSL_HKDF 1 # define OPENSSL_EDDSA 1 -# define OPENSSL_X25519 1 # if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL # define OPENSSL_SIPHASH 1 # endif @@ -70,13 +69,8 @@ namespace crypto private: uint8_t m_PublicKey[32]; -#if OPENSSL_X25519 EVP_PKEY_CTX * m_Ctx; EVP_PKEY * m_Pkey; -#else - BN_CTX * m_Ctx; - uint8_t m_PrivateKey[32]; -#endif bool m_IsElligatorIneligible = false; // true if definitely ineligible }; diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 3e0795d5..47edb755 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.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 * @@ -457,86 +457,6 @@ namespace crypto } } -#if !OPENSSL_X25519 - BIGNUM * Ed25519::ScalarMul (const BIGNUM * u, const BIGNUM * k, BN_CTX * ctx) const - { - BN_CTX_start (ctx); - auto x1 = BN_CTX_get (ctx); BN_copy (x1, u); - auto x2 = BN_CTX_get (ctx); BN_one (x2); - auto z2 = BN_CTX_get (ctx); BN_zero (z2); - auto x3 = BN_CTX_get (ctx); BN_copy (x3, u); - auto z3 = BN_CTX_get (ctx); BN_one (z3); - auto c121666 = BN_CTX_get (ctx); BN_set_word (c121666, 121666); - auto tmp0 = BN_CTX_get (ctx); auto tmp1 = BN_CTX_get (ctx); - unsigned int swap = 0; - auto bits = BN_num_bits (k); - while(bits) - { - --bits; - auto k_t = BN_is_bit_set(k, bits) ? 1 : 0; - swap ^= k_t; - if (swap) - { - std::swap (x2, x3); - std::swap (z2, z3); - } - swap = k_t; - BN_mod_sub(tmp0, x3, z3, q, ctx); - BN_mod_sub(tmp1, x2, z2, q, ctx); - BN_mod_add(x2, x2, z2, q, ctx); - BN_mod_add(z2, x3, z3, q, ctx); - BN_mod_mul(z3, tmp0, x2, q, ctx); - BN_mod_mul(z2, z2, tmp1, q, ctx); - BN_mod_sqr(tmp0, tmp1, q, ctx); - BN_mod_sqr(tmp1, x2, q, ctx); - BN_mod_add(x3, z3, z2, q, ctx); - BN_mod_sub(z2, z3, z2, q, ctx); - BN_mod_mul(x2, tmp1, tmp0, q, ctx); - BN_mod_sub(tmp1, tmp1, tmp0, q, ctx); - BN_mod_sqr(z2, z2, q, ctx); - BN_mod_mul(z3, tmp1, c121666, q, ctx); - BN_mod_sqr(x3, x3, q, ctx); - BN_mod_add(tmp0, tmp0, z3, q, ctx); - BN_mod_mul(z3, x1, z2, q, ctx); - BN_mod_mul(z2, tmp1, tmp0, q, ctx); - } - if (swap) - { - std::swap (x2, x3); - std::swap (z2, z3); - } - BN_mod_inverse (z2, z2, q, ctx); - BIGNUM * res = BN_new (); // not from ctx - BN_mod_mul(res, x2, z2, q, ctx); - BN_CTX_end (ctx); - return res; - } - - void Ed25519::ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const - { - BIGNUM * p1 = DecodeBN<32> (p); - uint8_t k[32]; - memcpy (k, e, 32); - k[0] &= 248; k[31] &= 127; k[31] |= 64; - BIGNUM * n = DecodeBN<32> (k); - BIGNUM * q1 = ScalarMul (p1, n, ctx); - EncodeBN (q1, buf, 32); - BN_free (p1); BN_free (n); BN_free (q1); - } - - void Ed25519::ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const - { - BIGNUM *p1 = BN_new (); BN_set_word (p1, 9); - uint8_t k[32]; - memcpy (k, e, 32); - k[0] &= 248; k[31] &= 127; k[31] |= 64; - BIGNUM * n = DecodeBN<32> (k); - BIGNUM * q1 = ScalarMul (p1, n, ctx); - EncodeBN (q1, buf, 32); - BN_free (p1); BN_free (n); BN_free (q1); - } -#endif - void Ed25519::BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded) { BN_CTX * ctx = BN_CTX_new (); diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h index 470d802f..9c0ad801 100644 --- a/libi2pd/Ed25519.h +++ b/libi2pd/Ed25519.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 * @@ -84,10 +84,7 @@ namespace crypto EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const; EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const; void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const; -#if !OPENSSL_X25519 - void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519 - void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; -#endif + void BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32 void BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32 @@ -115,11 +112,6 @@ namespace crypto BIGNUM * DecodeBN (const uint8_t * buf) const; void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const; -#if !OPENSSL_X25519 - // for x25519 - BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const; -#endif - private: BIGNUM * q, * l, * d, * I; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index de319f5d..6353a683 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -49,10 +49,6 @@ set(test-gost-sig_SRCS test-gost-sig.cpp ) -set(test-x25519_SRCS - test-x25519.cpp -) - set(test-aeadchacha20poly1305_SRCS test-aeadchacha20poly1305.cpp ) @@ -77,7 +73,6 @@ add_executable(test-http-url ${test-http-url_SRCS}) add_executable(test-base-64 ${test-base-64_SRCS}) add_executable(test-gost ${test-gost_SRCS}) add_executable(test-gost-sig ${test-gost-sig_SRCS}) -add_executable(test-x25519 ${test-x25519_SRCS}) add_executable(test-aeadchacha20poly1305 ${test-aeadchacha20poly1305_SRCS}) add_executable(test-blinding ${test-blinding_SRCS}) add_executable(test-elligator ${test-elligator_SRCS}) @@ -102,7 +97,6 @@ target_link_libraries(test-http-url ${LIBS}) target_link_libraries(test-base-64 ${LIBS}) target_link_libraries(test-gost ${LIBS}) target_link_libraries(test-gost-sig ${LIBS}) -target_link_libraries(test-x25519 ${LIBS}) target_link_libraries(test-aeadchacha20poly1305 ${LIBS}) target_link_libraries(test-blinding ${LIBS}) target_link_libraries(test-elligator ${LIBS}) @@ -116,7 +110,6 @@ add_test(test-http-url ${TEST_PATH}/test-http-url) add_test(test-base-64 ${TEST_PATH}/test-base-64) add_test(test-gost ${TEST_PATH}/test-gost) add_test(test-gost-sig ${TEST_PATH}/test-gost-sig) -add_test(test-x25519 ${TEST_PATH}/test-x25519) add_test(test-aeadchacha20poly1305 ${TEST_PATH}/test-aeadchacha20poly1305) add_test(test-blinding ${TEST_PATH}/test-blinding) add_test(test-elligator ${TEST_PATH}/test-elligator) diff --git a/tests/Makefile b/tests/Makefile index 798fab42..51a11dfe 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -7,7 +7,7 @@ LIBI2PD = ../libi2pd.a TESTS = \ test-http-merge_chunked test-http-req test-http-res test-http-url test-http-url_decode \ - test-gost test-gost-sig test-base-64 test-x25519 test-aeadchacha20poly1305 test-blinding \ + test-gost test-gost-sig test-base-64 test-aeadchacha20poly1305 test-blinding \ test-elligator test-eddsa ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS))) @@ -44,9 +44,6 @@ test-gost: test-gost.cpp $(LIBI2PD) test-gost-sig: test-gost-sig.cpp $(LIBI2PD) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) -test-x25519: test-x25519.cpp $(LIBI2PD) - $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) - test-aeadchacha20poly1305: test-aeadchacha20poly1305.cpp $(LIBI2PD) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) diff --git a/tests/test-x25519.cpp b/tests/test-x25519.cpp deleted file mode 100644 index a1f3f424..00000000 --- a/tests/test-x25519.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include - -#include "Ed25519.h" - -const uint8_t k[32] = -{ - 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, - 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, - 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 -}; - -const uint8_t u[32] = -{ - 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, - 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, - 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c -}; - -uint8_t p[32] = -{ - 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, - 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, - 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 -}; - -int main () -{ -#if !OPENSSL_X25519 -// we test it for openssl < 1.1.0 - uint8_t buf[32]; - BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMul (u, k, buf, ctx); - BN_CTX_free (ctx); - assert(memcmp (buf, p, 32) == 0); -#endif -} From 29d77113cc9bd5f12eb2b9b70357023466bdeb55 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 2 Nov 2024 11:20:23 -0400 Subject: [PATCH 231/527] memory pool for x25519 keys --- libi2pd/Transports.cpp | 12 ++++++------ libi2pd/Transports.h | 4 +++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 6b695371..b07b1b0b 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -25,7 +25,7 @@ namespace transport { template EphemeralKeysSupplier::EphemeralKeysSupplier (int size): - m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr) + m_QueueSize (size), m_IsRunning (false) { } @@ -39,7 +39,7 @@ namespace transport void EphemeralKeysSupplier::Start () { m_IsRunning = true; - m_Thread = new std::thread (std::bind (&EphemeralKeysSupplier::Run, this)); + m_Thread.reset (new std::thread (std::bind (&EphemeralKeysSupplier::Run, this))); } template @@ -53,8 +53,7 @@ namespace transport if (m_Thread) { m_Thread->join (); - delete m_Thread; - m_Thread = 0; + m_Thread = nullptr; } } @@ -78,6 +77,7 @@ namespace transport } else { + m_KeysPool.CleanUpMt (); std::unique_lock l(m_AcquiredMutex); if (!m_IsRunning) break; m_Acquired.wait (l); // wait for element gets acquired @@ -92,7 +92,7 @@ namespace transport { for (int i = 0; i < num; i++) { - auto pair = std::make_shared (); + auto pair = m_KeysPool.AcquireSharedMt (); pair->GenerateKeys (); std::unique_lock l(m_AcquiredMutex); m_Queue.push (pair); @@ -114,7 +114,7 @@ namespace transport } } // queue is empty, create new - auto pair = std::make_shared (); + auto pair = m_KeysPool.AcquireSharedMt (); pair->GenerateKeys (); return pair; } diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index c7eb7677..8271108d 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -26,6 +26,7 @@ #include "RouterInfo.h" #include "I2NPProtocol.h" #include "Identity.h" +#include "util.h" namespace i2p { @@ -53,9 +54,10 @@ namespace transport const int m_QueueSize; std::queue > m_Queue; + i2p::util::MemoryPoolMt m_KeysPool; bool m_IsRunning; - std::thread * m_Thread; + std::unique_ptr m_Thread; std::condition_variable m_Acquired; std::mutex m_AcquiredMutex; }; From f90386803fbc182f8facba8982db85976832e3f7 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 3 Nov 2024 11:03:12 -0500 Subject: [PATCH 232/527] Resend RelayResponse if relay tag not found. Send Ack block --- libi2pd/SSU2Session.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index aba8195e..58a4a61c 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -337,13 +337,14 @@ namespace transport SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT); SendQueue (); transports.PeerConnected (shared_from_this ()); + + LogPrint(eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), + " (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") established"); if (m_OnEstablished) { m_OnEstablished (); m_OnEstablished = nullptr; } - LogPrint(eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), - " (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") established"); } void SSU2Session::Done () @@ -1944,21 +1945,24 @@ namespace transport void SSU2Session::HandleRelayRequest (const uint8_t * buf, size_t len) { // we are Bob + auto mts = i2p::util::GetMillisecondsSinceEpoch (); + uint32_t nonce = bufbe32toh (buf + 1); // nonce uint32_t relayTag = bufbe32toh (buf + 5); // relay tag auto session = m_Server.FindRelaySession (relayTag); if (!session) { LogPrint (eLogWarning, "SSU2: RelayRequest session with relay tag ", relayTag, " not found"); // send relay response back to Alice - uint8_t payload[SSU2_MAX_PACKET_SIZE]; - size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize, - eSSU2RelayResponseCodeBobRelayTagNotFound, bufbe32toh (buf + 1), 0, false); - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - SendData (payload, payloadSize); + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); + packet->payloadSize = CreateAckBlock (packet->payload, m_MaxPayloadSize); + packet->payloadSize += CreateRelayResponseBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, + eSSU2RelayResponseCodeBobRelayTagNotFound, nonce, 0, false); + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + uint32_t packetNum = SendData (packet->payload, packet->payloadSize); + packet->sendTime = mts; + session->m_SentPackets.emplace (packetNum, packet); return; } - auto mts = i2p::util::GetMillisecondsSinceEpoch (); - uint32_t nonce = bufbe32toh (buf + 1); if (session->m_RelaySessions.emplace (nonce, std::make_pair (shared_from_this (), mts/1000)).second) { // send relay intro to Charlie From 76190ea3652a5fd6e9b5a942858fac98b86bb157 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 3 Nov 2024 11:25:19 -0500 Subject: [PATCH 233/527] don't resend RelayReponse if Alice is older version --- libi2pd/SSU2Session.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 58a4a61c..96f38217 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1959,8 +1959,12 @@ namespace transport eSSU2RelayResponseCodeBobRelayTagNotFound, nonce, 0, false); packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); uint32_t packetNum = SendData (packet->payload, packet->payloadSize); - packet->sendTime = mts; - session->m_SentPackets.emplace (packetNum, packet); + if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION) + { + // sometimes Alice doesn't ack this RelayResponse in older versions + packet->sendTime = mts; + m_SentPackets.emplace (packetNum, packet); + } return; } if (session->m_RelaySessions.emplace (nonce, std::make_pair (shared_from_this (), mts/1000)).second) From 5a4ce66d42739482128754c4608a0df270a9751b Mon Sep 17 00:00:00 2001 From: John Date: Sun, 3 Nov 2024 19:26:18 +0300 Subject: [PATCH 234/527] debian/changelog: Add leading space --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 0fe779da..fd7b8d57 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,7 +2,7 @@ i2pd (2.54.0-1) unstable; urgency=medium * updated to version 2.54.0/0.9.64 --- orignal Sun, 6 Oct 2024 16:00:00 +0000 + -- orignal Sun, 6 Oct 2024 16:00:00 +0000 i2pd (2.53.1-1) unstable; urgency=medium From 2f6bdd1c848e80fdaa402f4628efb1ba98b012da Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 4 Nov 2024 18:20:46 -0500 Subject: [PATCH 235/527] limit last decline time by 1.5 hours. Increased declined recently interval to 5.5 minutes --- libi2pd/Profiling.cpp | 8 +++++--- libi2pd/Profiling.h | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/libi2pd/Profiling.cpp b/libi2pd/Profiling.cpp index 27925434..59d60c6d 100644 --- a/libi2pd/Profiling.cpp +++ b/libi2pd/Profiling.cpp @@ -206,10 +206,9 @@ namespace data return m_NumTunnelsNonReplied > 10*(total + 1); } - bool RouterProfile::IsDeclinedRecently () + bool RouterProfile::IsDeclinedRecently (uint64_t ts) { if (!m_LastDeclineTime) return false; - auto ts = i2p::util::GetSecondsSinceEpoch (); if (ts > m_LastDeclineTime + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL || ts + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL < m_LastDeclineTime) m_LastDeclineTime = 0; @@ -218,7 +217,10 @@ namespace data bool RouterProfile::IsBad () { - if (IsDeclinedRecently () || IsUnreachable () || m_IsDuplicated) return true; + if (IsUnreachable () || m_IsDuplicated) return true; + auto ts = i2p::util::GetSecondsSinceEpoch (); + if (ts > PEER_PROFILE_MAX_DECLINED_INTERVAL + m_LastDeclineTime) return false; + if (IsDeclinedRecently (ts)) return true; auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/; if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1)) { diff --git a/libi2pd/Profiling.h b/libi2pd/Profiling.h index be674d95..5d85cec3 100644 --- a/libi2pd/Profiling.h +++ b/libi2pd/Profiling.h @@ -38,11 +38,13 @@ namespace data const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 900; // in seconds (15 minutes) const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_TIMEOUT = 5400; // in seconds (1.5 hours) const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE = 2400; // in seconds (40 minutes) - const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 150; // in seconds (2.5 minutes) + const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 330; // in seconds (5.5 minutes) + const int PEER_PROFILE_MAX_DECLINED_INTERVAL = 4400; // in second (1.5 hours) const int PEER_PROFILE_PERSIST_INTERVAL = 3300; // in seconds (55 minutes) const int PEER_PROFILE_UNREACHABLE_INTERVAL = 480; // in seconds (8 minutes) const int PEER_PROFILE_USEFUL_THRESHOLD = 3; - + const int PEER_PROFILE_ALWAYS_DECLINING_NUM = 5; // num declines in row to consider always declined + class RouterProfile { public: @@ -81,7 +83,7 @@ namespace data bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; }; bool IsLowPartcipationRate () const; bool IsLowReplyRate () const; - bool IsDeclinedRecently (); + bool IsDeclinedRecently (uint64_t ts); private: From d99a7d9b2013ddad0e7b9ac3e1a95b5d7e3af0f3 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Nov 2024 15:20:05 -0500 Subject: [PATCH 236/527] allow transit for router behind symmetric NAT or proxy --- libi2pd/RouterContext.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index f5f8b4fb..5fa7bc99 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -323,10 +323,6 @@ namespace i2p case eRouterStatusFirewalled: SetUnreachable (true, false); // ipv4 break; - case eRouterStatusProxy: - m_AcceptsTunnels = false; - UpdateCongestion (); - break; default: ; } @@ -1489,7 +1485,7 @@ namespace i2p void RouterContext::UpdateCongestion () { auto c = i2p::data::RouterInfo::eLowCongestion; - if (!AcceptsTunnels () || !m_ShareRatio || (m_Error == eRouterErrorSymmetricNAT && !SupportsV6 () && !SupportsMesh ())) + if (!AcceptsTunnels () || !m_ShareRatio) c = i2p::data::RouterInfo::eRejectAll; else { From be24a3e336fe7e380e0e883ec327e9d3f8cb2c4f Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Nov 2024 19:24:54 -0500 Subject: [PATCH 237/527] publish R cap for yggdrasil-only router and U cap for routers through proxy --- libi2pd/RouterContext.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 5fa7bc99..e69738c6 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -323,6 +323,12 @@ namespace i2p case eRouterStatusFirewalled: SetUnreachable (true, false); // ipv4 break; + case eRouterStatusMesh: + m_RouterInfo.UpdateCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eReachable); + break; + case eRouterStatusProxy: + m_RouterInfo.UpdateCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eUnreachable); + break; default: ; } From 32921ead8010e278d266c4e58db6976d9d18f250 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 7 Nov 2024 19:00:11 -0500 Subject: [PATCH 238/527] move transit tunnel build requests from I2NPProtocol.cpp to TransitTunnel.cpp --- libi2pd/I2NPProtocol.cpp | 274 +------------------------------------- libi2pd/TransitTunnel.cpp | 272 +++++++++++++++++++++++++++++++++++++ libi2pd/TransitTunnel.h | 3 + 3 files changed, 279 insertions(+), 270 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 198f798b..85623f97 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -10,20 +10,15 @@ #include #include "Base.h" #include "Log.h" -#include "Crypto.h" #include "I2PEndian.h" #include "Timestamp.h" #include "RouterContext.h" #include "NetDb.hpp" #include "Tunnel.h" -#include "Transports.h" -#include "Garlic.h" -#include "ECIESX25519AEADRatchetSession.h" +#include "TransitTunnel.h" #include "I2NPProtocol.h" #include "version.h" -using namespace i2p::transport; - namespace i2p { std::shared_ptr NewI2NPMessage () @@ -376,108 +371,8 @@ namespace i2p return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo } - static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText) - { - for (int i = 0; i < num; i++) - { - uint8_t * record = records + i*TUNNEL_BUILD_RECORD_SIZE; - if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16)) - { - LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours"); - if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) - { - LogPrint (eLogWarning, "I2NP: Failed to decrypt tunnel build record"); - return false; - } - if (!memcmp ((const uint8_t *)i2p::context.GetIdentHash (), clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32) && // if next ident is now ours - !(clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG)) // and not endpoint - { - LogPrint (eLogWarning, "I2NP: Next ident is ours in tunnel build record"); - return false; - } - uint8_t retCode = 0; - // decide if we should accept tunnel - bool accept = i2p::context.AcceptsTunnels (); - if (accept) - { - auto congestionLevel = i2p::context.GetCongestionLevel (false); - if (congestionLevel >= CONGESTION_LEVEL_MEDIUM) - { - if (congestionLevel < CONGESTION_LEVEL_FULL) - { - // random reject depending on congestion level - int level = i2p::tunnel::tunnels.GetRng ()() % (CONGESTION_LEVEL_FULL - CONGESTION_LEVEL_MEDIUM) + CONGESTION_LEVEL_MEDIUM; - if (congestionLevel > level) - accept = false; - } - else - accept = false; - } - } - // replace record to reply - if (accept) - { - auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( - bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), - clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, - bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), - clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, - clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET, - clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, - clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); - if (!i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel)) - retCode = 30; - } - else - retCode = 30; // always reject with bandwidth reason (30) - - memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options - record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode; - // encrypt reply - i2p::crypto::CBCEncryption encryption; - for (int j = 0; j < num; j++) - { - uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE; - if (j == i) - { - uint8_t nonce[12]; - memset (nonce, 0, 12); - auto& noiseState = i2p::context.GetCurrentNoiseState (); - if (!i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16, - noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt - { - LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed"); - return false; - } - } - else - { - encryption.SetKey (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET); - encryption.SetIV (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET); - encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply); - } - } - return true; - } - } - return false; - } - static void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len) { - int num = buf[0]; - LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records"); - if (num > i2p::tunnel::MAX_NUM_RECORDS) - { - LogPrint (eLogError, "I2NP: Too many records in VaribleTunnelBuild message ", num); - return; - } - if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1) - { - LogPrint (eLogError, "I2NP: VaribleTunnelBuild message of ", num, " records is too short ", len); - return; - } - auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID); if (tunnel) { @@ -496,24 +391,7 @@ namespace i2p } } else - { - uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; - if (HandleBuildRequestRecords (num, buf + 1, clearText)) - { - if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel - { - // so we send it to reply tunnel - transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, - CreateTunnelGatewayMsg (bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), - eI2NPVariableTunnelBuildReply, buf, len, - bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); - } - else - transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, - CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, - bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); - } - } + i2p::tunnel::HandleVariableTransitTunnelBuildMsg (buf, len); } static void HandleTunnelBuildMsg (uint8_t * buf, size_t len) @@ -559,18 +437,6 @@ namespace i2p static void HandleShortTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len) { - int num = buf[0]; - LogPrint (eLogDebug, "I2NP: ShortTunnelBuild ", num, " records"); - if (num > i2p::tunnel::MAX_NUM_RECORDS) - { - LogPrint (eLogError, "I2NP: Too many records in ShortTunnelBuild message ", num); - return; - } - if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1) - { - LogPrint (eLogError, "I2NP: ShortTunnelBuild message of ", num, " records is too short ", len); - return; - } auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID); if (tunnel) { @@ -589,140 +455,8 @@ namespace i2p } return; } - const uint8_t * record = buf + 1; - for (int i = 0; i < num; i++) - { - if (!memcmp (record, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16)) - { - LogPrint (eLogDebug, "I2NP: Short request record ", i, " is ours"); - uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE]; - if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) - { - LogPrint (eLogWarning, "I2NP: Can't decrypt short request record ", i); - return; - } - if (clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE]) // not AES - { - LogPrint (eLogWarning, "I2NP: Unknown layer encryption type ", clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE], " in short request record"); - return; - } - auto& noiseState = i2p::context.GetCurrentNoiseState (); - uint8_t replyKey[32]; // AEAD/Chacha20/Poly1305 - i2p::crypto::AESKey layerKey, ivKey; // AES - i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelReplyKey", noiseState.m_CK); - memcpy (replyKey, noiseState.m_CK + 32, 32); - i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK); - memcpy (layerKey, noiseState.m_CK + 32, 32); - bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG; - if (isEndpoint) - { - i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "TunnelLayerIVKey", noiseState.m_CK); - memcpy (ivKey, noiseState.m_CK + 32, 32); - } - else - { - if (!memcmp ((const uint8_t *)i2p::context.GetIdentHash (), clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // if next ident is now ours - { - LogPrint (eLogWarning, "I2NP: Next ident is ours in short request record"); - return; - } - memcpy (ivKey, noiseState.m_CK , 32); - } - - // check if we accept this tunnel - std::shared_ptr transitTunnel; - uint8_t retCode = 0; - if (!i2p::context.AcceptsTunnels () || i2p::context.GetCongestionLevel (false) >= CONGESTION_LEVEL_FULL) - retCode = 30; - if (!retCode) - { - // create new transit tunnel - transitTunnel = i2p::tunnel::CreateTransitTunnel ( - bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), - clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, - bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), - layerKey, ivKey, - clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, - clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); - if (!i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel)) - retCode = 30; - } - - // encrypt reply - uint8_t nonce[12]; - memset (nonce, 0, 12); - uint8_t * reply = buf + 1; - for (int j = 0; j < num; j++) - { - nonce[4] = j; // nonce is record # - if (j == i) - { - memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options - reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode; - if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16, - noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt - { - LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed"); - return; - } - } - else - i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply); - reply += SHORT_TUNNEL_BUILD_RECORD_SIZE; - } - // send reply - auto onDrop = [transitTunnel]() - { - if (transitTunnel) - { - auto t = transitTunnel->GetCreationTime (); - if (t > i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT) - // make transit tunnel expired - transitTunnel->SetCreationTime (t - i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT); - } - }; - if (isEndpoint) - { - auto replyMsg = NewI2NPShortMessage (); - replyMsg->Concat (buf, len); - replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)); - if (transitTunnel) replyMsg->onDrop = onDrop; - if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (), - clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local? - { - i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK); - uint64_t tag; - memcpy (&tag, noiseState.m_CK, 8); - // we send it to reply tunnel - transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, - CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), - i2p::garlic::WrapECIESX25519Message (replyMsg, noiseState.m_CK + 32, tag))); - } - else - { - // IBGW is local - uint32_t tunnelID = bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET); - auto tunnel = i2p::tunnel::tunnels.GetTunnel (tunnelID); - if (tunnel) - { - tunnel->SendTunnelDataMsg (replyMsg); - tunnel->FlushTunnelDataMsgs (); - } - else - LogPrint (eLogWarning, "I2NP: Tunnel ", tunnelID, " not found for short tunnel build reply"); - } - } - else - { - auto msg = CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len, - bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)); - if (transitTunnel) msg->onDrop = onDrop; - transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, msg); - } - return; - } - record += SHORT_TUNNEL_BUILD_RECORD_SIZE; - } + else + i2p::tunnel::HandleShortTransitTunnelBuildMsg (buf, len); } std::shared_ptr CreateTunnelDataMsg (const uint8_t * buf) diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index 72d7b8c2..71837a9f 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -8,9 +8,12 @@ #include #include "I2PEndian.h" +#include "Crypto.h" #include "Log.h" #include "RouterContext.h" #include "I2NPProtocol.h" +#include "Garlic.h" +#include "ECIESX25519AEADRatchetSession.h" #include "Tunnel.h" #include "Transports.h" #include "TransitTunnel.h" @@ -118,5 +121,274 @@ namespace tunnel return std::make_shared (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); } } + + void HandleShortTransitTunnelBuildMsg (uint8_t * buf, size_t len) + { + int num = buf[0]; + LogPrint (eLogDebug, "TransitTunnel: ShortTunnelBuild ", num, " records"); + if (num > i2p::tunnel::MAX_NUM_RECORDS) + { + LogPrint (eLogError, "TransitTunnel: Too many records in ShortTunnelBuild message ", num); + return; + } + if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1) + { + LogPrint (eLogError, "TransitTunnel: ShortTunnelBuild message of ", num, " records is too short ", len); + return; + } + const uint8_t * record = buf + 1; + for (int i = 0; i < num; i++) + { + if (!memcmp (record, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16)) + { + LogPrint (eLogDebug, "TransitTunnel: Short request record ", i, " is ours"); + uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE]; + if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) + { + LogPrint (eLogWarning, "TransitTunnel: Can't decrypt short request record ", i); + return; + } + if (clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE]) // not AES + { + LogPrint (eLogWarning, "TransitTunnel: Unknown layer encryption type ", clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE], " in short request record"); + return; + } + auto& noiseState = i2p::context.GetCurrentNoiseState (); + uint8_t replyKey[32]; // AEAD/Chacha20/Poly1305 + i2p::crypto::AESKey layerKey, ivKey; // AES + i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelReplyKey", noiseState.m_CK); + memcpy (replyKey, noiseState.m_CK + 32, 32); + i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK); + memcpy (layerKey, noiseState.m_CK + 32, 32); + bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG; + if (isEndpoint) + { + i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "TunnelLayerIVKey", noiseState.m_CK); + memcpy (ivKey, noiseState.m_CK + 32, 32); + } + else + { + if (!memcmp ((const uint8_t *)i2p::context.GetIdentHash (), clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // if next ident is now ours + { + LogPrint (eLogWarning, "TransitTunnel: Next ident is ours in short request record"); + return; + } + memcpy (ivKey, noiseState.m_CK , 32); + } + + // check if we accept this tunnel + std::shared_ptr transitTunnel; + uint8_t retCode = 0; + if (!i2p::context.AcceptsTunnels () || i2p::context.GetCongestionLevel (false) >= CONGESTION_LEVEL_FULL) + retCode = 30; + if (!retCode) + { + // create new transit tunnel + transitTunnel = i2p::tunnel::CreateTransitTunnel ( + bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), + clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, + bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + layerKey, ivKey, + clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, + clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); + if (!i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel)) + retCode = 30; + } + + // encrypt reply + uint8_t nonce[12]; + memset (nonce, 0, 12); + uint8_t * reply = buf + 1; + for (int j = 0; j < num; j++) + { + nonce[4] = j; // nonce is record # + if (j == i) + { + memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options + reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode; + if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16, + noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt + { + LogPrint (eLogWarning, "TransitTunnel: Short reply AEAD encryption failed"); + return; + } + } + else + i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply); + reply += SHORT_TUNNEL_BUILD_RECORD_SIZE; + } + // send reply + auto onDrop = [transitTunnel]() + { + if (transitTunnel) + { + auto t = transitTunnel->GetCreationTime (); + if (t > i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT) + // make transit tunnel expired + transitTunnel->SetCreationTime (t - i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT); + } + }; + if (isEndpoint) + { + auto replyMsg = NewI2NPShortMessage (); + replyMsg->Concat (buf, len); + replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)); + if (transitTunnel) replyMsg->onDrop = onDrop; + if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (), + clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local? + { + i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK); + uint64_t tag; + memcpy (&tag, noiseState.m_CK, 8); + // we send it to reply tunnel + i2p::transport::transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, + CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + i2p::garlic::WrapECIESX25519Message (replyMsg, noiseState.m_CK + 32, tag))); + } + else + { + // IBGW is local + uint32_t tunnelID = bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET); + auto tunnel = i2p::tunnel::tunnels.GetTunnel (tunnelID); + if (tunnel) + { + tunnel->SendTunnelDataMsg (replyMsg); + tunnel->FlushTunnelDataMsgs (); + } + else + LogPrint (eLogWarning, "I2NP: Tunnel ", tunnelID, " not found for short tunnel build reply"); + } + } + else + { + auto msg = CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len, + bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)); + if (transitTunnel) msg->onDrop = onDrop; + i2p::transport::transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, msg); + } + return; + } + record += SHORT_TUNNEL_BUILD_RECORD_SIZE; + } + } + + static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText) + { + for (int i = 0; i < num; i++) + { + uint8_t * record = records + i*TUNNEL_BUILD_RECORD_SIZE; + if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16)) + { + LogPrint (eLogDebug, "TransitTunnel: Build request record ", i, " is ours"); + if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) + { + LogPrint (eLogWarning, "TransitTunnel: Failed to decrypt tunnel build record"); + return false; + } + if (!memcmp ((const uint8_t *)i2p::context.GetIdentHash (), clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32) && // if next ident is now ours + !(clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG)) // and not endpoint + { + LogPrint (eLogWarning, "TransitTunnel: Next ident is ours in tunnel build record"); + return false; + } + uint8_t retCode = 0; + // decide if we should accept tunnel + bool accept = i2p::context.AcceptsTunnels (); + if (accept) + { + auto congestionLevel = i2p::context.GetCongestionLevel (false); + if (congestionLevel >= CONGESTION_LEVEL_MEDIUM) + { + if (congestionLevel < CONGESTION_LEVEL_FULL) + { + // random reject depending on congestion level + int level = i2p::tunnel::tunnels.GetRng ()() % (CONGESTION_LEVEL_FULL - CONGESTION_LEVEL_MEDIUM) + CONGESTION_LEVEL_MEDIUM; + if (congestionLevel > level) + accept = false; + } + else + accept = false; + } + } + // replace record to reply + if (accept) + { + auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( + bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), + clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, + bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, + clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET, + clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, + clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); + if (!i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel)) + retCode = 30; + } + else + retCode = 30; // always reject with bandwidth reason (30) + + memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options + record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode; + // encrypt reply + i2p::crypto::CBCEncryption encryption; + for (int j = 0; j < num; j++) + { + uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE; + if (j == i) + { + uint8_t nonce[12]; + memset (nonce, 0, 12); + auto& noiseState = i2p::context.GetCurrentNoiseState (); + if (!i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16, + noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt + { + LogPrint (eLogWarning, "TransitTunnel: Reply AEAD encryption failed"); + return false; + } + } + else + { + encryption.SetKey (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET); + encryption.SetIV (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET); + encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply); + } + } + return true; + } + } + return false; + } + + void HandleVariableTransitTunnelBuildMsg (uint8_t * buf, size_t len) + { + int num = buf[0]; + LogPrint (eLogDebug, "TransitTunnel: VariableTunnelBuild ", num, " records"); + if (num > i2p::tunnel::MAX_NUM_RECORDS) + { + LogPrint (eLogError, "TransitTunnle: Too many records in VaribleTunnelBuild message ", num); + return; + } + if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1) + { + LogPrint (eLogError, "TransitTunnel: VaribleTunnelBuild message of ", num, " records is too short ", len); + return; + } + uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; + if (HandleBuildRequestRecords (num, buf + 1, clearText)) + { + if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel + { + // so we send it to reply tunnel + i2p::transport::transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, + CreateTunnelGatewayMsg (bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + eI2NPVariableTunnelBuildReply, buf, len, + bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + } + else + i2p::transport::transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, + CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, + bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + } + } } } diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index b3381fb7..48615d19 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.h @@ -108,6 +108,9 @@ namespace tunnel const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID, const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey, bool isGateway, bool isEndpoint); + + void HandleShortTransitTunnelBuildMsg (uint8_t * buf, size_t len); + void HandleVariableTransitTunnelBuildMsg (uint8_t * buf, size_t len); } } From 002d8c777389957f4ec4089823c65f339c94b51d Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 8 Nov 2024 15:53:01 -0500 Subject: [PATCH 239/527] removed HidUser's reseed --- .../reseed/hiduser0_at_mail.i2p.crt | 32 ------------------- libi2pd/Config.cpp | 1 - 2 files changed, 33 deletions(-) delete mode 100644 contrib/certificates/reseed/hiduser0_at_mail.i2p.crt diff --git a/contrib/certificates/reseed/hiduser0_at_mail.i2p.crt b/contrib/certificates/reseed/hiduser0_at_mail.i2p.crt deleted file mode 100644 index a332805a..00000000 --- a/contrib/certificates/reseed/hiduser0_at_mail.i2p.crt +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFgTCCA2mgAwIBAgIETWAY1DANBgkqhkiG9w0BAQ0FADBxMQswCQYDVQQGEwJY -WDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnlt -b3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEaMBgGA1UEAwwRaGlkdXNlcjBAbWFp -bC5pMnAwHhcNMjExMjEzMTU0MDI3WhcNMzExMjExMTU0MDI3WjBxMQswCQYDVQQG -EwJYWDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5v -bnltb3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEaMBgGA1UEAwwRaGlkdXNlcjBA -bWFpbC5pMnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXnjJ8UQ0f -lHHpfPMiHofBPSuL4sbOJY6fOXwPhSg/h6THh9DS/ZWmJXQ3qRD0glDVtv4/Dr/9 -ldGQ5eltF9iCFXCQlMEy2HjQrBKq0nsl7RpYK12cyMaod0kkzCUk9ITLi9CmHM3Z -gQZcmG8TWjFEpDR+idx/QkQt2pcO4vzWlDit3Vh4ivnbX5jGQHbsVjQEMQWxr+pX -dsS+YQpjZ6RBmrooGTPO8QDOOeYLAn0lCjmffc/kzIH9E/p4/O0rOpyhVYbdxUD1 -5wkqN9l4yrtxmORG/PudnRQQ0r4TUq8vsxfGY0Euo9IbhgXF2Parel1ZhDxB1WZV -VwWtgLIh9jGA1UMa8SYKnEfp8LWNZ3b3mUUnZb3kMrLk6jGYRWNsHmamhd4mC7AZ -qf/8lOkEIw3bPd3YguCDRVcLui5BwIEZmqXg8uoESxfO/sW3pBrN/8M7MkTex9kN -vjitGDDXvenK27qmNgZxbBlX72yTSfys7XTYTLnxZC8AwdAo2Wz9Z6HhGiPonf2h -vZkc9ZxuE0jFIrsbJra4X7iyjXgi4vV4ARNg/9Ft6F4/OIbECgeDcBQqq4TlT2bZ -EfWVrBbqXoj5vNsLigIkd+AyUNwPYEcB5IFSiiOh98pC7BH3pg0m8U5YBjxe1i+9 -EQOOG0Qtx+JigXZHu6bGE0Twy9zy+UzoKQIDAQABoyEwHzAdBgNVHQ4EFgQUGK1b -0DkL6aLalcfBc/Uj/SF08C0wDQYJKoZIhvcNAQENBQADggIBAMpXM82bJDpH1TlH -TvhU3Z7nfZdvEhOQfujaFUYiuNripuEKcFGn948+DvAG0FUN+uNlJoqOVs8D7InD -gWlA9zpqw5Cl5Hij/Wns9QbXuAHJeA23fVUoaM2A6v9ifcIQ1A+rDuRQAo6/64KW -ChTg2e99RBpfGOyqgeh7tLLe0lPPekVpKHFuXabokaKRDuBcVHcUL4tWXe3dcyqa -Ej/PJrrS+nWL0EGZ4q80CEd2LPuDzPxNGCJt/R7ZfadENWajcgcXGceh1QBzozrB -SL/Ya6wF9SrsB7V/r5wX0LM4ZdDaLWbtmUe5Op0h/ZMH25Sa8xAXVz+O9L6sWSoO -FaiYTOvAiyyPz+nsxKa3xYryDHno7eKSt+hGOcaurhxbdZaEFY/CegEc73tCt9xK -e9qF8O/WkDLmixuErw3f5en4IfzGR7p3lJAwW/8WD8C6HS39h/eE7dVZNaWgtQnZ -SgGjgZMTJqTcQ3aZmfuCZefxGFok8w6AIkdbnd1pdMBRjYu8aXgl2hQSB9ZADDE9 -R5d3rXi0PkSFLIvsNjVa5KXrZk/tB0Hpfmepq7CufBqjP/LG9TieRoXzLYUKFF74 -QRwjP+y7AJ+VDUTpY1NV1P+k+2raubU2bOnLF3zL5DtyoyieGPhyeMMvp0fRIxdg -bSl5VHgPXHNM8mcnndMAuzvl7jEK ------END CERTIFICATE----- diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index ab237613..5add5f1e 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -238,7 +238,6 @@ namespace config { "http://[324:71e:281a:9ed3::ace]:7070/," "http://[301:65b9:c7cd:9a36::1]:18801/," "http://[320:8936:ec1a:31f1::216]/," - "http://[306:3834:97b9:a00a::1]/," "http://[316:f9e0:f22e:a74f::216]/" ), "Reseed URLs through the Yggdrasil, separated by comma") ; From c5e464a8b541aa79b8066c03e5e72b7b4dd60c10 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 9 Nov 2024 17:25:43 -0500 Subject: [PATCH 240/527] move tunnel build request/reply code from I2NPProtocol.cpp to Tunnel.cpp --- libi2pd/I2NPProtocol.cpp | 123 -------------------------------------- libi2pd/I2NPProtocol.h | 1 - libi2pd/TransitTunnel.cpp | 10 +++- libi2pd/TransitTunnel.h | 4 +- libi2pd/Tunnel.cpp | 104 ++++++++++++++++++++++++++++++-- libi2pd/Tunnel.h | 5 +- 6 files changed, 114 insertions(+), 133 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 85623f97..e97a3596 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -371,94 +371,6 @@ namespace i2p return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo } - static void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len) - { - auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID); - if (tunnel) - { - // endpoint of inbound tunnel - LogPrint (eLogDebug, "I2NP: VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ()); - if (tunnel->HandleTunnelBuildResponse (buf, len)) - { - LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been created"); - tunnel->SetState (i2p::tunnel::eTunnelStateEstablished); - i2p::tunnel::tunnels.AddInboundTunnel (tunnel); - } - else - { - LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined"); - tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed); - } - } - else - i2p::tunnel::HandleVariableTransitTunnelBuildMsg (buf, len); - } - - static void HandleTunnelBuildMsg (uint8_t * buf, size_t len) - { - LogPrint (eLogWarning, "I2NP: TunnelBuild is too old for ECIES router"); - } - - static void HandleTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len, bool isShort) - { - int num = buf[0]; - LogPrint (eLogDebug, "I2NP: TunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID); - if (num > i2p::tunnel::MAX_NUM_RECORDS) - { - LogPrint (eLogError, "I2NP: Too many records in TunnelBuildReply message ", num); - return; - } - size_t recordSize = isShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE; - if (len < num*recordSize + 1) - { - LogPrint (eLogError, "I2NP: TunnelBuildReply message of ", num, " records is too short ", len); - return; - } - - auto tunnel = i2p::tunnel::tunnels.GetPendingOutboundTunnel (replyMsgID); - if (tunnel) - { - // reply for outbound tunnel - if (tunnel->HandleTunnelBuildResponse (buf, len)) - { - LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been created"); - tunnel->SetState (i2p::tunnel::eTunnelStateEstablished); - i2p::tunnel::tunnels.AddOutboundTunnel (tunnel); - } - else - { - LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been declined"); - tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed); - } - } - else - LogPrint (eLogWarning, "I2NP: Pending tunnel for message ", replyMsgID, " not found"); - } - - static void HandleShortTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len) - { - auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID); - if (tunnel) - { - // endpoint of inbound tunnel - LogPrint (eLogDebug, "I2NP: ShortTunnelBuild reply for tunnel ", tunnel->GetTunnelID ()); - if (tunnel->HandleTunnelBuildResponse (buf, len)) - { - LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been created"); - tunnel->SetState (i2p::tunnel::eTunnelStateEstablished); - i2p::tunnel::tunnels.AddInboundTunnel (tunnel); - } - else - { - LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined"); - tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed); - } - return; - } - else - i2p::tunnel::HandleShortTransitTunnelBuildMsg (buf, len); - } - std::shared_ptr CreateTunnelDataMsg (const uint8_t * buf) { auto msg = NewI2NPTunnelMessage (false); @@ -554,41 +466,6 @@ namespace i2p return l; } - void HandleTunnelBuildI2NPMessage (std::shared_ptr msg) - { - if (msg) - { - uint8_t typeID = msg->GetTypeID(); - uint32_t msgID = msg->GetMsgID(); - LogPrint (eLogDebug, "I2NP: Handling tunnel build message with len=", msg->GetLength(),", type=", (int)typeID, ", msgID=", (unsigned int)msgID); - uint8_t * payload = msg->GetPayload(); - auto size = msg->GetPayloadLength(); - switch (typeID) - { - case eI2NPVariableTunnelBuild: - HandleVariableTunnelBuildMsg (msgID, payload, size); - break; - case eI2NPShortTunnelBuild: - HandleShortTunnelBuildMsg (msgID, payload, size); - break; - case eI2NPVariableTunnelBuildReply: - HandleTunnelBuildReplyMsg (msgID, payload, size, false); - break; - case eI2NPShortTunnelBuildReply: - HandleTunnelBuildReplyMsg (msgID, payload, size, true); - break; - case eI2NPTunnelBuild: - HandleTunnelBuildMsg (payload, size); - break; - case eI2NPTunnelBuildReply: - // TODO: - break; - default: - LogPrint (eLogError, "I2NP: Unexpected message with type", (int)typeID, " during handling TBM; skipping"); - } - } - } - void HandleI2NPMessage (std::shared_ptr msg) { if (msg) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 5971ce17..911a53bf 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -316,7 +316,6 @@ namespace tunnel std::shared_ptr CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr msg); size_t GetI2NPMessageLength (const uint8_t * msg, size_t len); - void HandleTunnelBuildI2NPMessage (std::shared_ptr msg); void HandleI2NPMessage (std::shared_ptr msg); class I2NPMessagesHandler diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index 71837a9f..3b016d95 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -122,8 +122,11 @@ namespace tunnel } } - void HandleShortTransitTunnelBuildMsg (uint8_t * buf, size_t len) + void HandleShortTransitTunnelBuildMsg (std::shared_ptr msg) { + if (!msg) return; + uint8_t * buf = msg->GetPayload(); + size_t len = msg->GetPayloadLength(); int num = buf[0]; LogPrint (eLogDebug, "TransitTunnel: ShortTunnelBuild ", num, " records"); if (num > i2p::tunnel::MAX_NUM_RECORDS) @@ -359,8 +362,11 @@ namespace tunnel return false; } - void HandleVariableTransitTunnelBuildMsg (uint8_t * buf, size_t len) + void HandleVariableTransitTunnelBuildMsg (std::shared_ptr msg) { + if (!msg) return; + uint8_t * buf = msg->GetPayload(); + size_t len = msg->GetPayloadLength(); int num = buf[0]; LogPrint (eLogDebug, "TransitTunnel: VariableTunnelBuild ", num, " records"); if (num > i2p::tunnel::MAX_NUM_RECORDS) diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index 48615d19..1a1b489b 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.h @@ -109,8 +109,8 @@ namespace tunnel const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey, bool isGateway, bool isEndpoint); - void HandleShortTransitTunnelBuildMsg (uint8_t * buf, size_t len); - void HandleVariableTransitTunnelBuildMsg (uint8_t * buf, size_t len); + void HandleShortTransitTunnelBuildMsg (std::shared_ptr msg); + void HandleVariableTransitTunnelBuildMsg (std::shared_ptr msg); } } diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 1e2a75d9..4ce8f526 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -533,14 +533,22 @@ namespace tunnel break; } - case eI2NPVariableTunnelBuild: - case eI2NPVariableTunnelBuildReply: case eI2NPShortTunnelBuild: + HandleShortTunnelBuildMsg (msg); + break; + case eI2NPVariableTunnelBuild: + HandleVariableTunnelBuildMsg (msg); + break; case eI2NPShortTunnelBuildReply: + HandleTunnelBuildReplyMsg (msg, true); + break; + case eI2NPVariableTunnelBuildReply: + HandleTunnelBuildReplyMsg (msg, false); + break; case eI2NPTunnelBuild: case eI2NPTunnelBuildReply: - HandleTunnelBuildI2NPMessage (msg); - break; + LogPrint (eLogWarning, "Tunnel: TunnelBuild is too old for ECIES router"); + break; default: LogPrint (eLogWarning, "Tunnel: Unexpected message type ", (int) typeID); } @@ -613,6 +621,94 @@ namespace tunnel tunnel->SendTunnelDataMsg (msg); } + void Tunnels::HandleShortTunnelBuildMsg (std::shared_ptr msg) + { + if (!msg) return; + auto tunnel = GetPendingInboundTunnel (msg->GetMsgID()); // replyMsgID + if (tunnel) + { + // endpoint of inbound tunnel + LogPrint (eLogDebug, "Tunnel: ShortTunnelBuild reply for tunnel ", tunnel->GetTunnelID ()); + if (tunnel->HandleTunnelBuildResponse (msg->GetPayload(), msg->GetPayloadLength())) + { + LogPrint (eLogInfo, "Tunnel: Inbound tunnel ", tunnel->GetTunnelID (), " has been created"); + tunnel->SetState (eTunnelStateEstablished); + AddInboundTunnel (tunnel); + } + else + { + LogPrint (eLogInfo, "Tunnel: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined"); + tunnel->SetState (eTunnelStateBuildFailed); + } + return; + } + else + i2p::tunnel::HandleShortTransitTunnelBuildMsg (msg); + } + + void Tunnels::HandleVariableTunnelBuildMsg (std::shared_ptr msg) + { + auto tunnel = GetPendingInboundTunnel (msg->GetMsgID()); // replyMsgID + if (tunnel) + { + // endpoint of inbound tunnel + LogPrint (eLogDebug, "Tunnel: VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ()); + if (tunnel->HandleTunnelBuildResponse (msg->GetPayload(), msg->GetPayloadLength())) + { + LogPrint (eLogInfo, "Tunnel: Inbound tunnel ", tunnel->GetTunnelID (), " has been created"); + tunnel->SetState (eTunnelStateEstablished); + AddInboundTunnel (tunnel); + } + else + { + LogPrint (eLogInfo, "Tunnel: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined"); + tunnel->SetState (eTunnelStateBuildFailed); + } + } + else + i2p::tunnel::HandleVariableTransitTunnelBuildMsg (msg); + } + + void Tunnels::HandleTunnelBuildReplyMsg (std::shared_ptr msg, bool isShort) + { + if (!msg) return; + uint8_t * buf = msg->GetPayload(); + size_t len = msg->GetPayloadLength(); + int num = buf[0]; + LogPrint (eLogDebug, "Tunnel: TunnelBuildReplyMsg of ", num, " records replyMsgID=", msg->GetMsgID()); + if (num > i2p::tunnel::MAX_NUM_RECORDS) + { + LogPrint (eLogError, "Tunnel: Too many records in TunnelBuildReply message ", num); + return; + } + size_t recordSize = isShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE; + if (len < num*recordSize + 1) + { + LogPrint (eLogError, "Tunnel: TunnelBuildReply message of ", num, " records is too short ", len); + return; + } + + auto tunnel = GetPendingOutboundTunnel (msg->GetMsgID()); // replyMsgID + if (tunnel) + { + // reply for outbound tunnel + if (tunnel->HandleTunnelBuildResponse (buf, len)) + { + LogPrint (eLogInfo, "Tunnel: Outbound tunnel ", tunnel->GetTunnelID (), " has been created"); + tunnel->SetState (eTunnelStateEstablished); + AddOutboundTunnel (tunnel); + } + else + { + LogPrint (eLogInfo, "Tunnel: Outbound tunnel ", tunnel->GetTunnelID (), " has been declined"); + tunnel->SetState (eTunnelStateBuildFailed); + } + } + else + LogPrint (eLogWarning, "Tunnel: Pending tunnel for message ", msg->GetMsgID(), " not found"); + + } + void Tunnels::ManageTunnels (uint64_t ts) { ManagePendingTunnels (ts); diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 02bfb374..291d1e6e 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -257,7 +257,10 @@ namespace tunnel std::shared_ptr GetPendingTunnel (uint32_t replyMsgID, const std::map >& pendingTunnels); void HandleTunnelGatewayMsg (std::shared_ptr tunnel, std::shared_ptr msg); - + void HandleShortTunnelBuildMsg (std::shared_ptr msg); + void HandleVariableTunnelBuildMsg (std::shared_ptr msg); + void HandleTunnelBuildReplyMsg (std::shared_ptr msg, bool isShort); + void Run (); void ManageTunnels (uint64_t ts); void ManageOutboundTunnels (uint64_t ts); From 0a083834711135afb13e7798d8662a21b2490d09 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 10 Nov 2024 09:15:23 -0500 Subject: [PATCH 241/527] check msg size in HandleTunnelBuildResponse --- libi2pd/Tunnel.cpp | 37 ++++++++++++++++--------------------- libi2pd/TunnelConfig.h | 4 +++- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 4ce8f526..54e276ad 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -130,8 +130,19 @@ namespace tunnel bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len) { - LogPrint (eLogDebug, "Tunnel: TunnelBuildResponse ", (int)msg[0], " records."); - + int num = msg[0]; + LogPrint (eLogDebug, "Tunnel: TunnelBuildResponse ", num, " records."); + if (num > MAX_NUM_RECORDS) + { + LogPrint (eLogError, "Tunnel: Too many records in TunnelBuildResponse", num); + return false; + } + if (len < num*m_Config->GetRecordSize () + 1) + { + LogPrint (eLogError, "Tunnel: TunnelBuildResponse of ", num, " records is too short ", len); + return false; + } + TunnelHopConfig * hop = m_Config->GetLastHop (); while (hop) { @@ -152,7 +163,7 @@ namespace tunnel while (hop1) { auto idx = hop1->recordIndex; - if (idx >= 0 && idx < msg[0]) + if (idx >= 0 && idx < num) hop->DecryptRecord (msg + 1, idx); else LogPrint (eLogWarning, "Tunnel: Hop index ", idx, " is out of range"); @@ -671,28 +682,12 @@ namespace tunnel void Tunnels::HandleTunnelBuildReplyMsg (std::shared_ptr msg, bool isShort) { - if (!msg) return; - uint8_t * buf = msg->GetPayload(); - size_t len = msg->GetPayloadLength(); - int num = buf[0]; - LogPrint (eLogDebug, "Tunnel: TunnelBuildReplyMsg of ", num, " records replyMsgID=", msg->GetMsgID()); - if (num > i2p::tunnel::MAX_NUM_RECORDS) - { - LogPrint (eLogError, "Tunnel: Too many records in TunnelBuildReply message ", num); - return; - } - size_t recordSize = isShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE; - if (len < num*recordSize + 1) - { - LogPrint (eLogError, "Tunnel: TunnelBuildReply message of ", num, " records is too short ", len); - return; - } - auto tunnel = GetPendingOutboundTunnel (msg->GetMsgID()); // replyMsgID if (tunnel) { // reply for outbound tunnel - if (tunnel->HandleTunnelBuildResponse (buf, len)) + LogPrint (eLogDebug, "Tunnel: TunnelBuildReply for tunnel ", tunnel->GetTunnelID ()); + if (tunnel->HandleTunnelBuildResponse (msg->GetPayload(), msg->GetPayloadLength())) { LogPrint (eLogInfo, "Tunnel: Outbound tunnel ", tunnel->GetTunnelID (), " has been created"); tunnel->SetState (eTunnelStateEstablished); diff --git a/libi2pd/TunnelConfig.h b/libi2pd/TunnelConfig.h index 9dcf2c02..718a6fdb 100644 --- a/libi2pd/TunnelConfig.h +++ b/libi2pd/TunnelConfig.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 * @@ -181,6 +181,8 @@ namespace tunnel return peers; } + size_t GetRecordSize () const { return m_IsShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE; }; + protected: // this constructor can't be called from outside From e5743548962b2446e2cd3650e3bcb3c583616ce6 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 10 Nov 2024 11:32:46 -0500 Subject: [PATCH 242/527] limit received SSU2 packets queue --- libi2pd/SSU2.cpp | 15 +++++++++++---- libi2pd/SSU2.h | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index c8f2909b..a53c877c 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -457,13 +457,20 @@ namespace transport void SSU2Server::InsertToReceivedPacketsQueue (std::list& packets) { if (packets.empty ()) return; - bool empty = false; + size_t queueSize = 0; { std::lock_guard l(m_ReceivedPacketsQueueMutex); - empty = m_ReceivedPacketsQueue.empty (); - m_ReceivedPacketsQueue.splice (m_ReceivedPacketsQueue.end (), packets); + queueSize = m_ReceivedPacketsQueue.size (); + if (queueSize < SSU2_MAX_RECEIVED_QUEUE_SIZE) + m_ReceivedPacketsQueue.splice (m_ReceivedPacketsQueue.end (), packets); + else + { + LogPrint (eLogError, "SSU2: Received queue size ", queueSize, " exceeds max size", SSU2_MAX_RECEIVED_QUEUE_SIZE); + m_PacketsPool.ReleaseMt (packets); + queueSize = 0; // invoke processing just in case + } } - if (empty) + if (!queueSize) GetService ().post([this]() { HandleReceivedPacketsQueue (); }); } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 319a4780..95f053a9 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -37,6 +37,7 @@ namespace transport const uint64_t SSU2_SOCKET_MAX_BUFFER_SIZE = 4 * 1024 * 1024; const size_t SSU2_MAX_NUM_INTRODUCERS = 3; const size_t SSU2_MIN_RECEIVED_PACKET_SIZE = 40; // 16 byte short header + 8 byte minimum payload + 16 byte MAC + const size_t SSU2_MAX_RECEIVED_QUEUE_SIZE = 2500; // in packets 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 a411fff1d9157e07349f929f100bcebf76950745 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 10 Nov 2024 16:49:44 -0500 Subject: [PATCH 243/527] limit number of incoming streams. don't request LeaseSet for incoming stream --- libi2pd/Streaming.cpp | 37 ++++++++++++++++++++++++++----------- libi2pd/Streaming.h | 2 ++ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 966c172d..0e829004 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -71,7 +71,7 @@ namespace stream m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed - m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), + m_Status (eStreamStatusNew), m_IsIncoming (false), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), @@ -99,7 +99,7 @@ namespace stream m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed - m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), + m_Status (eStreamStatusNew), m_IsIncoming (true), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_LocalDestination (local), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), @@ -1471,17 +1471,26 @@ namespace stream if (!remoteLeaseSet) { LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), m_RemoteLeaseSet ? " expired" : " not found"); - if (m_RemoteLeaseSet && m_RemoteLeaseSet->IsPublishedEncrypted ()) - { - m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet ( - std::make_shared(m_RemoteIdentity)); - return; // we keep m_RemoteLeaseSet for possible next request + if (!m_IsIncoming) // outgoing + { + if (m_RemoteLeaseSet && m_RemoteLeaseSet->IsPublishedEncrypted ()) + { + m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet ( + std::make_shared(m_RemoteIdentity)); + return; // we keep m_RemoteLeaseSet for possible next request + } + else + { + m_RemoteLeaseSet = nullptr; + m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt + } } - else + else // incoming { - m_RemoteLeaseSet = nullptr; - m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt - } + // just close the socket without sending FIN or RST + m_Status = eStreamStatusClosed; + AsyncClose (); + } } else { @@ -1696,6 +1705,12 @@ namespace stream DeletePacket (packet); // drop it, because previous should be connected return; } + if (m_IncomingStreams.size () > MAX_NUM_INCOMING_STREAMS) // TODO: configurable + { + LogPrint(eLogWarning, "Streaming: Number of incoming streams exceeds ", MAX_NUM_INCOMING_STREAMS); + DeletePacket (packet); + return; + } auto incomingStream = CreateNewIncomingStream (receiveStreamID); incomingStream->HandleNextPacket (packet); // SYN auto ident = incomingStream->GetRemoteIdentity(); diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index a686d71b..c6a88498 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -66,6 +66,7 @@ namespace stream const int MIN_SEND_ACK_TIMEOUT = 2; // in milliseconds const int SYN_TIMEOUT = 200; // how long we wait for SYN after follow-on, in milliseconds const size_t MAX_PENDING_INCOMING_BACKLOG = 1024; + const size_t MAX_NUM_INCOMING_STREAMS = 2048; const int PENDING_INCOMING_TIMEOUT = 10; // in seconds const int MAX_RECEIVE_TIMEOUT = 20; // in seconds const uint16_t DELAY_CHOKING = 60000; // in milliseconds @@ -262,6 +263,7 @@ namespace stream int32_t m_PreviousReceivedSequenceNumber; int32_t m_LastConfirmedReceivedSequenceNumber; // for limit inbound speed StreamStatus m_Status; + bool m_IsIncoming; bool m_IsAckSendScheduled; bool m_IsNAcked; bool m_IsFirstACK; From 09b7d44dad667bf2e385b0f1fbf9a44775c88f3b Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 10 Nov 2024 19:15:44 -0500 Subject: [PATCH 244/527] delete ECIESX25519 session without destination shortly --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 1 + libi2pd/ECIESX25519AEADRatchetSession.h | 5 +++-- libi2pd/Garlic.cpp | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 138d21e9..63b739d7 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -1112,6 +1112,7 @@ namespace garlic bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts) { CleanupUnconfirmedLeaseSet (ts); + if (!m_Destination && ts > m_LastActivityTimestamp + ECIESX25519_SESSION_CREATE_TIMEOUT) return true; // m_LastActivityTimestamp is NS receive time return ts > m_LastActivityTimestamp + ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT && // seconds ts*1000 > m_LastSentTimestamp + ECIESX25519_SEND_EXPIRATION_TIMEOUT*1000; // milliseconds } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index bcc07b30..b55bfca2 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -30,6 +30,7 @@ namespace garlic const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds + const int ECIESX25519_SESSION_CREATE_TIMEOUT = 3; // in seconds, NSR must be send after NS received const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // in seconds const int ECIESX25519_ACK_REQUEST_INTERVAL = 33000; // in milliseconds const int ECIESX25519_ACK_REQUEST_MAX_NUM_ATTEMPTS = 3; @@ -169,7 +170,7 @@ namespace garlic void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); } void Terminate () { m_IsTerminated = true; } - void SetDestination (const i2p::data::IdentHash& dest) // TODO: + void SetDestination (const i2p::data::IdentHash& dest) { if (!m_Destination) m_Destination.reset (new i2p::data::IdentHash (dest)); } @@ -224,7 +225,7 @@ namespace garlic uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0, // incoming (in seconds) m_LastSentTimestamp = 0; // in milliseconds std::shared_ptr m_SendTagset, m_NSRSendTagset; - std::unique_ptr m_Destination;// TODO: might not need it + std::unique_ptr m_Destination;// must be set for NS if outgoing and NSR if incoming std::list > m_AckRequests; // incoming (tagsetid, index) bool m_SendReverseKey = false, m_SendForwardKey = false, m_IsTerminated = false; std::unique_ptr m_NextReceiveRatchet, m_NextSendRatchet; diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 04884acd..0d626234 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -761,7 +761,7 @@ namespace garlic session->SetRemoteStaticKey (staticKey); } if (destination->IsDestination ()) - session->SetDestination (destination->GetIdentHash ()); // TODO: remove + session->SetDestination (destination->GetIdentHash ()); // NS or NSR return session; } else From dbef3fe9d2158dca3df26a26b160c5dbe8874ec2 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 10 Nov 2024 20:15:50 -0500 Subject: [PATCH 245/527] temirminate incoming right a way if no remote LeaseSet --- libi2pd/Streaming.cpp | 10 ++++++++-- libi2pd/Streaming.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 0e829004..3c8a4c47 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1713,7 +1713,12 @@ namespace stream } auto incomingStream = CreateNewIncomingStream (receiveStreamID); incomingStream->HandleNextPacket (packet); // SYN - auto ident = incomingStream->GetRemoteIdentity(); + if (!incomingStream->GetRemoteLeaseSet ()) + { + LogPrint (eLogWarning, "Streaming: No remote LeaseSet for incoming stream. Terminated"); + incomingStream->Terminate (); // can't send FIN anyway + return; + } // handle saved packets if any { @@ -1815,7 +1820,8 @@ namespace stream { std::unique_lock l(m_StreamsMutex); m_Streams.erase (stream->GetRecvStreamID ()); - m_IncomingStreams.erase (stream->GetSendStreamID ()); + if (stream->IsIncoming ()) + m_IncomingStreams.erase (stream->GetSendStreamID ()); if (m_LastStream == stream) m_LastStream = nullptr; } auto ts = i2p::util::GetSecondsSinceEpoch (); diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index c6a88498..867634a5 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -187,6 +187,7 @@ namespace stream std::shared_ptr GetRemoteIdentity () const { return m_RemoteIdentity; }; bool IsOpen () const { return m_Status == eStreamStatusOpen; }; bool IsEstablished () const { return m_SendStreamID; }; + bool IsIncoming () const { return m_IsIncoming; }; StreamStatus GetStatus () const { return m_Status; }; StreamingDestination& GetLocalDestination () { return m_LocalDestination; }; void ResetRoutingPath (); From 2778b092e3a39bba2ae92eacb3becd02bce2173c Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Nov 2024 13:41:27 -0500 Subject: [PATCH 246/527] i2p.streaming.maxConcurrentStreams I2CP param --- libi2pd/Destination.cpp | 3 +++ libi2pd/Destination.h | 9 +++++---- libi2pd/Streaming.cpp | 4 ++-- libi2pd/Streaming.h | 1 - libi2pd_client/ClientContext.cpp | 1 + 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 01ff2d2a..80add061 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -988,6 +988,7 @@ namespace client m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_StreamingOutboundSpeed (DEFAULT_MAX_OUTBOUND_SPEED), m_StreamingInboundSpeed (DEFAULT_MAX_INBOUND_SPEED), + m_StreamingMaxConcurrentStreams (DEFAULT_MAX_CONCURRENT_STREAMS), m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0), m_DatagramDestination (nullptr), m_RefCounter (0), m_LastPublishedTimestamp (0), m_ReadyChecker(service) @@ -1059,6 +1060,8 @@ namespace client it = params->find (I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED); if (it != params->end ()) m_StreamingInboundSpeed = std::stoi(it->second); + if (it != params->end ()) + m_StreamingMaxConcurrentStreams = std::stoi(it->second); it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS); if (it != params->end ()) m_IsStreamingAnswerPings = std::stoi (it->second); // 1 for true diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index c6a8cab7..da9f85fb 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -94,7 +94,9 @@ namespace client const int STREAMING_PROFILE_BULK = 1; // high bandwidth const int STREAMING_PROFILE_INTERACTIVE = 2; // low bandwidth const int DEFAULT_STREAMING_PROFILE = STREAMING_PROFILE_BULK; - + const char I2CP_PARAM_STREAMING_MAX_CONCURRENT_STREAMS[] = "i2p.streaming.maxConcurrentStreams"; + const int DEFAULT_MAX_CONCURRENT_STREAMS = 2048; + typedef std::function stream)> StreamRequestComplete; class LeaseSetDestination: public i2p::garlic::GarlicDestination, @@ -269,6 +271,7 @@ namespace client int GetStreamingAckDelay () const { return m_StreamingAckDelay; } int GetStreamingOutboundSpeed () const { return m_StreamingOutboundSpeed; } int GetStreamingInboundSpeed () const { return m_StreamingInboundSpeed; } + int GetStreamingMaxConcurrentStreams () const { return m_StreamingMaxConcurrentStreams; } bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; } // datagram @@ -305,9 +308,7 @@ namespace client std::unique_ptr m_StandardEncryptionKey; std::unique_ptr m_ECIESx25519EncryptionKey; - int m_StreamingAckDelay; - int m_StreamingOutboundSpeed; - int m_StreamingInboundSpeed; + int m_StreamingAckDelay,m_StreamingOutboundSpeed, m_StreamingInboundSpeed, m_StreamingMaxConcurrentStreams; bool m_IsStreamingAnswerPings; std::shared_ptr m_StreamingDestination; // default std::map > m_StreamingDestinationsByPorts; diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 3c8a4c47..8073a40a 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1705,9 +1705,9 @@ namespace stream DeletePacket (packet); // drop it, because previous should be connected return; } - if (m_IncomingStreams.size () > MAX_NUM_INCOMING_STREAMS) // TODO: configurable + if ((int)m_Streams.size () > m_Owner->GetStreamingMaxConcurrentStreams ()) { - LogPrint(eLogWarning, "Streaming: Number of incoming streams exceeds ", MAX_NUM_INCOMING_STREAMS); + LogPrint(eLogWarning, "Streaming: Number of streams exceeds ", m_Owner->GetStreamingMaxConcurrentStreams ()); DeletePacket (packet); return; } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 867634a5..11fc04d1 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -66,7 +66,6 @@ namespace stream const int MIN_SEND_ACK_TIMEOUT = 2; // in milliseconds const int SYN_TIMEOUT = 200; // how long we wait for SYN after follow-on, in milliseconds const size_t MAX_PENDING_INCOMING_BACKLOG = 1024; - const size_t MAX_NUM_INCOMING_STREAMS = 2048; const int PENDING_INCOMING_TIMEOUT = 10; // in seconds const int MAX_RECEIVE_TIMEOUT = 20; // in seconds const uint16_t DELAY_CHOKING = 60000; // in milliseconds diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index cf72d204..ae6bfaa6 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -473,6 +473,7 @@ namespace client options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY); options[I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED, DEFAULT_MAX_OUTBOUND_SPEED); options[I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED, DEFAULT_MAX_INBOUND_SPEED); + options[I2CP_PARAM_STREAMING_MAX_CONCURRENT_STREAMS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_CONCURRENT_STREAMS, DEFAULT_MAX_CONCURRENT_STREAMS); options[I2CP_PARAM_STREAMING_ANSWER_PINGS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_ANSWER_PINGS, isServer ? DEFAULT_ANSWER_PINGS : false); options[I2CP_PARAM_STREAMING_PROFILE] = GetI2CPOption(section, I2CP_PARAM_STREAMING_PROFILE, DEFAULT_STREAMING_PROFILE); options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE); From 7285caa4f11dd01bdb5387b248b8777b0a4141e1 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Nov 2024 14:43:20 -0500 Subject: [PATCH 247/527] if i2p.streaming.maxConcurrentStreams is zeor or negative than unlimited --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 8073a40a..788d6613 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1705,7 +1705,7 @@ namespace stream DeletePacket (packet); // drop it, because previous should be connected return; } - if ((int)m_Streams.size () > m_Owner->GetStreamingMaxConcurrentStreams ()) + if (m_Owner->GetStreamingMaxConcurrentStreams () > 0 && (int)m_Streams.size () > m_Owner->GetStreamingMaxConcurrentStreams ()) { LogPrint(eLogWarning, "Streaming: Number of streams exceeds ", m_Owner->GetStreamingMaxConcurrentStreams ()); DeletePacket (packet); From 574d12298b685f5c8f3b1d01ab5b03f107c33bad Mon Sep 17 00:00:00 2001 From: r4sas Date: Tue, 12 Nov 2024 00:36:07 +0300 Subject: [PATCH 248/527] Destinations: set thread name from tunnel name Signed-off-by: r4sas --- libi2pd/Destination.cpp | 50 +++++++++++++++++--------------- libi2pd/util.h | 8 +++-- libi2pd_client/ClientContext.cpp | 21 +++++++++++--- 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 80add061..e413342d 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -37,7 +37,7 @@ namespace client int inVar = DEFAULT_INBOUND_TUNNELS_LENGTH_VARIANCE; int outVar = DEFAULT_OUTBOUND_TUNNELS_LENGTH_VARIANCE; int numTags = DEFAULT_TAGS_TO_SEND; - bool isHighBandwidth = true; + bool isHighBandwidth = true; std::shared_ptr > explicitPeers; try { @@ -471,7 +471,7 @@ namespace client { auto it2 = m_LeaseSetRequests.find (key); if (it2 != m_LeaseSetRequests.end ()) - { + { request = it2->second; m_LeaseSetRequests.erase (it2); if (request->requestedBlindedKey) @@ -493,14 +493,14 @@ namespace client // publishing verification doesn't have requestedBlindedKey auto localLeaseSet = GetLeaseSetMt (); if (localLeaseSet->GetStoreHash () == key) - { - auto ls = std::make_shared (i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2, + { + auto ls = std::make_shared (i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2, localLeaseSet->GetBuffer (), localLeaseSet->GetBufferLen (), false); - leaseSet = ls; - } + leaseSet = ls; + } else LogPrint (eLogWarning, "Destination: Encrypted LeaseSet2 received for request without blinded key"); - } + } } else LogPrint (eLogWarning, "Destination: Couldn't find request for encrypted LeaseSet2"); @@ -511,14 +511,14 @@ namespace client } if (!request) - { + { auto it1 = m_LeaseSetRequests.find (key); if (it1 != m_LeaseSetRequests.end ()) - { + { request = it1->second; m_LeaseSetRequests.erase (it1); - } - } + } + } if (request) { request->requestTimeoutTimer.cancel (); @@ -550,7 +550,7 @@ namespace client LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found"); } - void LeaseSetDestination::SendNextLeaseSetRequest (const i2p::data::IdentHash& key, + void LeaseSetDestination::SendNextLeaseSetRequest (const i2p::data::IdentHash& key, std::shared_ptr request) { bool found = false; @@ -570,8 +570,8 @@ namespace client request->Complete (nullptr); m_LeaseSetRequests.erase (key); } - } - + } + void LeaseSetDestination::HandleDeliveryStatusMessage (uint32_t msgID) { if (msgID == m_PublishReplyToken) @@ -592,7 +592,7 @@ namespace client { if (post) m_Service.post([s = shared_from_this ()]() { s->UpdateLeaseSet (); }); - else + else UpdateLeaseSet (); } @@ -631,7 +631,7 @@ namespace client if (!outbound || !inbound) { if (!m_Pool->GetInboundTunnels ().empty () && !m_Pool->GetOutboundTunnels ().empty ()) - { + { LogPrint (eLogInfo, "Destination: No compatible tunnels with ", floodfill->GetIdentHash ().ToBase64 (), ". Trying another floodfill"); m_ExcludedFloodfills.insert (floodfill->GetIdentHash ()); floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetStoreHash (), m_ExcludedFloodfills); @@ -649,10 +649,10 @@ namespace client } else LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found"); - } + } else LogPrint (eLogDebug, "Destination: No tunnels in pool"); - + if (!floodfill || !outbound || !inbound) { // we can't publish now @@ -880,8 +880,8 @@ namespace client AddECIESx25519Key (replyKey, replyTag); else AddSessionKey (replyKey, replyTag); - - auto msg = WrapMessageForRouter (nextFloodfill, + + auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, request->replyTunnel, replyKey, replyTag, isECIES)); auto s = shared_from_this (); msg->onDrop = [s, dest, request]() @@ -890,7 +890,7 @@ namespace client { s->SendNextLeaseSetRequest (dest, request); }); - }; + }; request->outboundTunnel->SendTunnelDataMsgs ( { i2p::tunnel::TunnelMessageBlock @@ -988,7 +988,7 @@ namespace client m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_StreamingOutboundSpeed (DEFAULT_MAX_OUTBOUND_SPEED), m_StreamingInboundSpeed (DEFAULT_MAX_INBOUND_SPEED), - m_StreamingMaxConcurrentStreams (DEFAULT_MAX_CONCURRENT_STREAMS), + m_StreamingMaxConcurrentStreams (DEFAULT_MAX_CONCURRENT_STREAMS), m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0), m_DatagramDestination (nullptr), m_RefCounter (0), m_LastPublishedTimestamp (0), m_ReadyChecker(service) @@ -1441,11 +1441,11 @@ namespace client keySections.push_back ({m_StandardEncryptionKey->keyType, (uint16_t)m_StandardEncryptionKey->decryptor->GetPublicKeyLen (), m_StandardEncryptionKey->pub} ); auto publishedTimestamp = i2p::util::GetSecondsSinceEpoch (); - if (publishedTimestamp <= m_LastPublishedTimestamp) + if (publishedTimestamp <= m_LastPublishedTimestamp) { LogPrint (eLogDebug, "Destination: LeaseSet update at the same second"); publishedTimestamp++; // force newer timestamp - } + } bool isPublishedEncrypted = GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; auto ls2 = std::make_shared (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2, m_Keys, keySections, tunnels, IsPublic (), publishedTimestamp, isPublishedEncrypted); @@ -1517,6 +1517,8 @@ namespace client RunnableService ("Destination"), ClientDestination (GetIOService (), keys, isPublic, params) { + if (!GetNickname ().empty ()) + RunnableService::SetName (GetNickname ()); } RunnableClientDestination::~RunnableClientDestination () diff --git a/libi2pd/util.h b/libi2pd/util.h index e39a9259..cb636aaa 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -137,8 +137,8 @@ namespace util std::lock_guard l(m_Mutex); for (size_t i = 0; i < num; i++) this->Release (arr[i]); - } - + } + templateclass C, typename... R> void ReleaseMt(const C& c) { @@ -146,7 +146,7 @@ namespace util for (auto& it: c) this->Release (it); } - + template std::shared_ptr AcquireSharedMt (TArgs&&... args) { @@ -183,6 +183,8 @@ namespace util void StartIOService (); void StopIOService (); + void SetName (std::string_view name) { m_Name = name; }; + private: void Run (); diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index ae6bfaa6..dac0b1bf 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -421,7 +421,8 @@ namespace client { I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, "3" }, { I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, "3" }, { I2CP_PARAM_LEASESET_TYPE, "3" }, - { I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "0,4" } + { I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "0,4" }, + { I2CP_PARAM_OUTBOUND_NICKNAME, "SharedDest" } }; m_SharedLocalDestination = CreateNewLocalDestination (false, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL, ¶ms); // non-public, EDDSA @@ -475,7 +476,7 @@ namespace client options[I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED, DEFAULT_MAX_INBOUND_SPEED); options[I2CP_PARAM_STREAMING_MAX_CONCURRENT_STREAMS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_CONCURRENT_STREAMS, DEFAULT_MAX_CONCURRENT_STREAMS); options[I2CP_PARAM_STREAMING_ANSWER_PINGS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_ANSWER_PINGS, isServer ? DEFAULT_ANSWER_PINGS : false); - options[I2CP_PARAM_STREAMING_PROFILE] = GetI2CPOption(section, I2CP_PARAM_STREAMING_PROFILE, DEFAULT_STREAMING_PROFILE); + options[I2CP_PARAM_STREAMING_PROFILE] = GetI2CPOption(section, I2CP_PARAM_STREAMING_PROFILE, DEFAULT_STREAMING_PROFILE); options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE); std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, isServer ? "4" : "0,4"); if (encType.length () > 0) options[I2CP_PARAM_LEASESET_ENCRYPTION_TYPE] = encType; @@ -596,6 +597,11 @@ namespace client std::map options; ReadI2CPOptions (section, false, options); + // Set I2CP name if not set + auto itopt = options.find (I2CP_PARAM_OUTBOUND_NICKNAME); + if (itopt == options.end ()) + options[I2CP_PARAM_OUTBOUND_NICKNAME] = name; + std::shared_ptr localDestination = nullptr; if (keys.length () > 0) { @@ -668,7 +674,7 @@ namespace client std::string outproxy = section.second.get("outproxy", ""); bool addresshelper = section.second.get("addresshelper", true); bool senduseragent = section.second.get("senduseragent", false); - auto tun = std::make_shared(name, address, port, + auto tun = std::make_shared(name, address, port, outproxy, addresshelper, senduseragent, localDestination); clientTunnel = tun; clientEndpoint = tun->GetLocalEndpoint (); @@ -750,6 +756,11 @@ namespace client std::map options; ReadI2CPOptions (section, true, options); + // Set I2CP name if not set + auto itopt = options.find (I2CP_PARAM_INBOUND_NICKNAME); + if (itopt == options.end ()) + options[I2CP_PARAM_INBOUND_NICKNAME] = name; + std::shared_ptr localDestination = nullptr; auto it = destinations.find (keys); if (it != destinations.end ()) @@ -897,6 +908,7 @@ namespace client { std::map params; ReadI2CPOptionsFromConfig ("httpproxy.", params); + params[I2CP_PARAM_OUTBOUND_NICKNAME] = "HTTPProxy"; localDestination = CreateNewLocalDestination (keys, false, ¶ms); if (localDestination) localDestination->Acquire (); } @@ -905,7 +917,7 @@ namespace client } try { - m_HttpProxy = new i2p::proxy::HTTPProxy("HTTP Proxy", httpProxyAddr, httpProxyPort, + m_HttpProxy = new i2p::proxy::HTTPProxy("HTTP Proxy", httpProxyAddr, httpProxyPort, httpOutProxyURL, httpAddresshelper, httpSendUserAgent, localDestination); m_HttpProxy->Start(); } @@ -945,6 +957,7 @@ namespace client { std::map params; ReadI2CPOptionsFromConfig ("socksproxy.", params); + params[I2CP_PARAM_OUTBOUND_NICKNAME] = "SOCKSProxy"; localDestination = CreateNewLocalDestination (keys, false, ¶ms); if (localDestination) localDestination->Acquire (); } From d88ba768d7a472c0e75832cc39e546bce5e551b2 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Nov 2024 18:50:53 -0500 Subject: [PATCH 249/527] set i2p.streaming.profile=2 for shared local destination --- libi2pd_client/ClientContext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index dac0b1bf..aa49f83e 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -422,7 +422,8 @@ namespace client { I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, "3" }, { I2CP_PARAM_LEASESET_TYPE, "3" }, { I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "0,4" }, - { I2CP_PARAM_OUTBOUND_NICKNAME, "SharedDest" } + { I2CP_PARAM_OUTBOUND_NICKNAME, "SharedDest" }, + { I2CP_PARAM_STREAMING_PROFILE, "2" } }; m_SharedLocalDestination = CreateNewLocalDestination (false, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL, ¶ms); // non-public, EDDSA From ce96f93c802ea599b300b9668955548600bafd6b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Nov 2024 21:59:19 -0500 Subject: [PATCH 250/527] cleanup tags and ECIES sessions more often --- libi2pd/Destination.cpp | 3 ++- libi2pd/Destination.h | 3 ++- libi2pd/RouterContext.cpp | 2 +- libi2pd/RouterContext.h | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index e413342d..558f8ac9 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -953,7 +953,8 @@ namespace client CleanupExpiredTags (); CleanupRemoteLeaseSets (); CleanupDestination (); - m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT)); + m_CleanupTimer.expires_from_now (boost::posix_time::seconds (DESTINATION_CLEANUP_TIMEOUT + + (m_Pool ? m_Pool->GetRng ()() % DESTINATION_CLEANUP_TIMEOUT_VARIANCE : 0))); m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer, shared_from_this (), std::placeholders::_1)); } diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index da9f85fb..2921d803 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -42,7 +42,8 @@ namespace client const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds - const int DESTINATION_CLEANUP_TIMEOUT = 3; // in minutes + const int DESTINATION_CLEANUP_TIMEOUT = 44; // in seconds + const int DESTINATION_CLEANUP_TIMEOUT_VARIANCE = 30; // in seconds const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7; // I2CP diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index e69738c6..558e9608 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -1510,7 +1510,7 @@ namespace i2p if (m_CleanupTimer) { m_CleanupTimer->cancel (); - m_CleanupTimer->expires_from_now (boost::posix_time::minutes(ROUTER_INFO_CLEANUP_INTERVAL)); + m_CleanupTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CLEANUP_INTERVAL)); m_CleanupTimer->async_wait (std::bind (&RouterContext::HandleCleanupTimer, this, std::placeholders::_1)); } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index f828a182..0dfef254 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -37,7 +37,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 + const int ROUTER_INFO_CLEANUP_INTERVAL = 102; // in seconds enum RouterStatus { From ce0461bf86ff82962dd4f13c436b98ac1fe1a4a7 Mon Sep 17 00:00:00 2001 From: r4sas Date: Tue, 12 Nov 2024 21:09:21 +0000 Subject: [PATCH 251/527] Destination: cut name for thread name Signed-off-by: r4sas --- libi2pd/util.cpp | 10 +++++++++- libi2pd/util.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index d1ed9992..47cecbbe 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.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 * @@ -171,6 +171,14 @@ namespace util } } + void RunnableService::SetName (std::string_view name) + { + if (name.length() < 16) + m_Name = name; + else + m_Name = name.substr(0,15); + } + void SetThreadName (const char *name) { #if defined(__APPLE__) # if (!defined(MAC_OS_X_VERSION_10_6) || \ diff --git a/libi2pd/util.h b/libi2pd/util.h index cb636aaa..48bcb801 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -183,7 +183,7 @@ namespace util void StartIOService (); void StopIOService (); - void SetName (std::string_view name) { m_Name = name; }; + void SetName (std::string_view name); private: From 3c608ec07cc39c2dbad91599ccf8f0d561481485 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Nov 2024 21:17:58 -0500 Subject: [PATCH 252/527] received garlic messages queue for destination --- libi2pd/Destination.cpp | 19 ++++++++++++++++++- libi2pd/Destination.h | 3 +++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 558f8ac9..cff6d73a 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -347,7 +347,24 @@ namespace client void LeaseSetDestination::ProcessGarlicMessage (std::shared_ptr msg) { - m_Service.post (std::bind (&LeaseSetDestination::HandleGarlicMessage, shared_from_this (), msg)); + if (!msg) return; + bool empty = false; + { + std::lock_guard l(m_IncomingMsgsQueueMutex); + empty = m_IncomingMsgsQueue.empty (); + m_IncomingMsgsQueue.push_back (msg); + } + if (empty) + m_Service.post([s = shared_from_this ()]() + { + std::list > receivedMsgs; + { + std::lock_guard l(s->m_IncomingMsgsQueueMutex); + s->m_IncomingMsgsQueue.swap (receivedMsgs); + } + for (auto& it: receivedMsgs) + s->HandleGarlicMessage (it); + }); } void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr msg) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 2921d803..8d49ef82 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -200,6 +200,9 @@ namespace client std::unordered_map > m_RemoteLeaseSets; std::unordered_map > m_LeaseSetRequests; + std::list > m_IncomingMsgsQueue; + mutable std::mutex m_IncomingMsgsQueueMutex; + std::shared_ptr m_Pool; std::mutex m_LeaseSetMutex; std::shared_ptr m_LeaseSet; From 0c5f39ad81cf0a645738f92c7676c6d21505be2d Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 16 Nov 2024 16:05:46 -0500 Subject: [PATCH 253/527] separate class TransitTunnelBuildMsgHandler for tunnel build messages --- libi2pd/TransitTunnel.cpp | 6 +++--- libi2pd/TransitTunnel.h | 16 ++++++++++++++-- libi2pd/Tunnel.cpp | 6 ++++-- libi2pd/Tunnel.h | 3 ++- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index 3b016d95..62192e92 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -122,7 +122,7 @@ namespace tunnel } } - void HandleShortTransitTunnelBuildMsg (std::shared_ptr msg) + void TransitTunnelBuildMsgHandler::HandleShortTransitTunnelBuildMsg (std::shared_ptr&& msg) { if (!msg) return; uint8_t * buf = msg->GetPayload(); @@ -275,7 +275,7 @@ namespace tunnel } } - static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText) + bool TransitTunnelBuildMsgHandler::HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText) { for (int i = 0; i < num; i++) { @@ -362,7 +362,7 @@ namespace tunnel return false; } - void HandleVariableTransitTunnelBuildMsg (std::shared_ptr msg) + void TransitTunnelBuildMsgHandler::HandleVariableTransitTunnelBuildMsg (std::shared_ptr&& msg) { if (!msg) return; uint8_t * buf = msg->GetPayload(); diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index 1a1b489b..fb5589dc 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.h @@ -109,8 +109,20 @@ namespace tunnel const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey, bool isGateway, bool isEndpoint); - void HandleShortTransitTunnelBuildMsg (std::shared_ptr msg); - void HandleVariableTransitTunnelBuildMsg (std::shared_ptr msg); + class TransitTunnelBuildMsgHandler + { + public: + + void Start () {}; + void Stop () {}; + + void HandleShortTransitTunnelBuildMsg (std::shared_ptr&& msg); + void HandleVariableTransitTunnelBuildMsg (std::shared_ptr&& msg); + + private: + + bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText); + }; } } diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 54e276ad..c743691e 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -482,10 +482,12 @@ namespace tunnel { m_IsRunning = true; m_Thread = new std::thread (std::bind (&Tunnels::Run, this)); + m_TransitTunnelBuildMsgHandler.Start (); } void Tunnels::Stop () { + m_TransitTunnelBuildMsgHandler.Stop (); m_IsRunning = false; m_Queue.WakeUp (); if (m_Thread) @@ -654,7 +656,7 @@ namespace tunnel return; } else - i2p::tunnel::HandleShortTransitTunnelBuildMsg (msg); + m_TransitTunnelBuildMsgHandler.HandleShortTransitTunnelBuildMsg (std::move (msg)); } void Tunnels::HandleVariableTunnelBuildMsg (std::shared_ptr msg) @@ -677,7 +679,7 @@ namespace tunnel } } else - i2p::tunnel::HandleVariableTransitTunnelBuildMsg (msg); + m_TransitTunnelBuildMsgHandler.HandleVariableTransitTunnelBuildMsg (std::move (msg)); } void Tunnels::HandleTunnelBuildReplyMsg (std::shared_ptr msg, bool isShort) diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 291d1e6e..f4d94ba7 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -314,7 +314,8 @@ namespace tunnel double m_TunnelCreationSuccessRate; int m_TunnelCreationAttemptsNum; std::mt19937 m_Rng; - + TransitTunnelBuildMsgHandler m_TransitTunnelBuildMsgHandler; + public: // for HTTP only From 72a39609ed2044df6922fe4016601fd96da3af8c Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 16 Nov 2024 20:56:35 -0500 Subject: [PATCH 254/527] moved all transit tunnels code to TransitTunnels class --- libi2pd/TransitTunnel.cpp | 64 +++++++++++++++++++++++++++++++--- libi2pd/TransitTunnel.h | 20 +++++++++-- libi2pd/Tunnel.cpp | 72 ++++++++++++--------------------------- libi2pd/Tunnel.h | 11 +++--- 4 files changed, 102 insertions(+), 65 deletions(-) diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index 62192e92..edf96c31 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -122,7 +122,16 @@ namespace tunnel } } - void TransitTunnelBuildMsgHandler::HandleShortTransitTunnelBuildMsg (std::shared_ptr&& msg) + void TransitTunnels::Start () + { + } + + void TransitTunnels::Stop () + { + m_TransitTunnels.clear (); + } + + void TransitTunnels::HandleShortTransitTunnelBuildMsg (std::shared_ptr&& msg) { if (!msg) return; uint8_t * buf = msg->GetPayload(); @@ -194,7 +203,7 @@ namespace tunnel layerKey, ivKey, clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); - if (!i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel)) + if (!AddTransitTunnel (transitTunnel)) retCode = 30; } @@ -275,7 +284,7 @@ namespace tunnel } } - bool TransitTunnelBuildMsgHandler::HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText) + bool TransitTunnels::HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText) { for (int i = 0; i < num; i++) { @@ -324,7 +333,7 @@ namespace tunnel clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET, clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); - if (!i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel)) + if (!AddTransitTunnel (transitTunnel)) retCode = 30; } else @@ -362,7 +371,7 @@ namespace tunnel return false; } - void TransitTunnelBuildMsgHandler::HandleVariableTransitTunnelBuildMsg (std::shared_ptr&& msg) + void TransitTunnels::HandleVariableTransitTunnelBuildMsg (std::shared_ptr&& msg) { if (!msg) return; uint8_t * buf = msg->GetPayload(); @@ -396,5 +405,50 @@ namespace tunnel bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); } } + + bool TransitTunnels::AddTransitTunnel (std::shared_ptr tunnel) + { + if (tunnels.AddTunnel (tunnel)) + m_TransitTunnels.push_back (tunnel); + else + { + LogPrint (eLogError, "TransitTunnel: Tunnel with id ", tunnel->GetTunnelID (), " already exists"); + return false; + } + return true; + } + + void TransitTunnels::ManageTransitTunnels (uint64_t ts) + { + for (auto it = m_TransitTunnels.begin (); it != m_TransitTunnels.end ();) + { + auto tunnel = *it; + if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT || + ts + TUNNEL_EXPIRATION_TIMEOUT < tunnel->GetCreationTime ()) + { + LogPrint (eLogDebug, "TransitTunnel: Transit tunnel with id ", tunnel->GetTunnelID (), " expired"); + tunnels.RemoveTunnel (tunnel->GetTunnelID ()); + it = m_TransitTunnels.erase (it); + } + else + { + tunnel->Cleanup (); + it++; + } + } + } + + int TransitTunnels::GetTransitTunnelsExpirationTimeout () + { + int timeout = 0; + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + // TODO: possible race condition with I2PControl + for (const auto& it : m_TransitTunnels) + { + int t = it->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT - ts; + if (t > timeout) timeout = t; + } + return timeout; + } } } diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index fb5589dc..fc8676d0 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.h @@ -109,19 +109,33 @@ namespace tunnel const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey, bool isGateway, bool isEndpoint); - class TransitTunnelBuildMsgHandler + class TransitTunnels { public: - void Start () {}; - void Stop () {}; + void Start (); + void Stop (); + void ManageTransitTunnels (uint64_t ts); + + size_t GetNumTransitTunnels () const { return m_TransitTunnels.size (); } + int GetTransitTunnelsExpirationTimeout (); void HandleShortTransitTunnelBuildMsg (std::shared_ptr&& msg); void HandleVariableTransitTunnelBuildMsg (std::shared_ptr&& msg); private: + bool AddTransitTunnel (std::shared_ptr tunnel); bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText); + + private: + + std::list > m_TransitTunnels; + + public: + + // for HTTP only + auto& GetTransitTunnels () const { return m_TransitTunnels; }; }; } } diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index c743691e..d809e48a 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -379,6 +379,17 @@ namespace tunnel return nullptr; } + bool Tunnels::AddTunnel (std::shared_ptr tunnel) + { + if (!tunnel) return false; + return m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second; + } + + void Tunnels::RemoveTunnel (uint32_t tunnelID) + { + m_Tunnels.erase (tunnelID); + } + std::shared_ptr Tunnels::GetPendingInboundTunnel (uint32_t replyMsgID) { return GetPendingTunnel (replyMsgID, m_PendingInboundTunnels); @@ -466,28 +477,16 @@ namespace tunnel } } - bool Tunnels::AddTransitTunnel (std::shared_ptr tunnel) - { - if (m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second) - m_TransitTunnels.push_back (tunnel); - else - { - LogPrint (eLogError, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " already exists"); - return false; - } - return true; - } - void Tunnels::Start () { m_IsRunning = true; m_Thread = new std::thread (std::bind (&Tunnels::Run, this)); - m_TransitTunnelBuildMsgHandler.Start (); + m_TransitTunnels.Start (); } void Tunnels::Stop () { - m_TransitTunnelBuildMsgHandler.Stop (); + m_TransitTunnels.Stop (); m_IsRunning = false; m_Queue.WakeUp (); if (m_Thread) @@ -656,7 +655,7 @@ namespace tunnel return; } else - m_TransitTunnelBuildMsgHandler.HandleShortTransitTunnelBuildMsg (std::move (msg)); + m_TransitTunnels.HandleShortTransitTunnelBuildMsg (std::move (msg)); } void Tunnels::HandleVariableTunnelBuildMsg (std::shared_ptr msg) @@ -679,7 +678,7 @@ namespace tunnel } } else - m_TransitTunnelBuildMsgHandler.HandleVariableTransitTunnelBuildMsg (std::move (msg)); + m_TransitTunnels.HandleVariableTransitTunnelBuildMsg (std::move (msg)); } void Tunnels::HandleTunnelBuildReplyMsg (std::shared_ptr msg, bool isShort) @@ -711,7 +710,7 @@ namespace tunnel ManagePendingTunnels (ts); ManageInboundTunnels (ts); ManageOutboundTunnels (ts); - ManageTransitTunnels (ts); + m_TransitTunnels.ManageTransitTunnels (ts); } void Tunnels::ManagePendingTunnels (uint64_t ts) @@ -838,7 +837,7 @@ namespace tunnel auto pool = tunnel->GetTunnelPool (); if (pool) pool->TunnelExpired (tunnel); - m_Tunnels.erase (tunnel->GetTunnelID ()); + RemoveTunnel (tunnel->GetTunnelID ()); it = m_InboundTunnels.erase (it); } else @@ -900,26 +899,6 @@ namespace tunnel } } - void Tunnels::ManageTransitTunnels (uint64_t ts) - { - for (auto it = m_TransitTunnels.begin (); it != m_TransitTunnels.end ();) - { - auto tunnel = *it; - if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT || - ts + TUNNEL_EXPIRATION_TIMEOUT < tunnel->GetCreationTime ()) - { - LogPrint (eLogDebug, "Tunnel: Transit tunnel with id ", tunnel->GetTunnelID (), " expired"); - m_Tunnels.erase (tunnel->GetTunnelID ()); - it = m_TransitTunnels.erase (it); - } - else - { - tunnel->Cleanup (); - it++; - } - } - } - void Tunnels::ManageTunnelPools (uint64_t ts) { std::unique_lock l(m_PoolsMutex); @@ -993,7 +972,7 @@ namespace tunnel void Tunnels::AddInboundTunnel (std::shared_ptr newTunnel) { - if (m_Tunnels.emplace (newTunnel->GetTunnelID (), newTunnel).second) + if (AddTunnel (newTunnel)) { m_InboundTunnels.push_back (newTunnel); auto pool = newTunnel->GetTunnelPool (); @@ -1023,7 +1002,7 @@ namespace tunnel inboundTunnel->SetTunnelPool (pool); inboundTunnel->SetState (eTunnelStateEstablished); m_InboundTunnels.push_back (inboundTunnel); - m_Tunnels[inboundTunnel->GetTunnelID ()] = inboundTunnel; + AddTunnel (inboundTunnel); return inboundTunnel; } @@ -1057,21 +1036,12 @@ namespace tunnel int Tunnels::GetTransitTunnelsExpirationTimeout () { - int timeout = 0; - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - // TODO: possible race condition with I2PControl - for (const auto& it : m_TransitTunnels) - { - int t = it->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT - ts; - if (t > timeout) timeout = t; - } - return timeout; + return m_TransitTunnels.GetTransitTunnelsExpirationTimeout (); } size_t Tunnels::CountTransitTunnels() const { - // TODO: locking - return m_TransitTunnels.size(); + return m_TransitTunnels.GetNumTransitTunnels (); } size_t Tunnels::CountInboundTunnels() const diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index f4d94ba7..fcccd236 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -223,8 +223,9 @@ namespace tunnel std::shared_ptr GetNextOutboundTunnel (); std::shared_ptr GetExploratoryPool () const { return m_ExploratoryPool; }; std::shared_ptr GetTunnel (uint32_t tunnelID); + bool AddTunnel (std::shared_ptr tunnel); + void RemoveTunnel (uint32_t tunnelID); int GetTransitTunnelsExpirationTimeout (); - bool AddTransitTunnel (std::shared_ptr tunnel); void AddOutboundTunnel (std::shared_ptr newTunnel); void AddInboundTunnel (std::shared_ptr newTunnel); std::shared_ptr CreateInboundTunnel (std::shared_ptr config, std::shared_ptr pool, std::shared_ptr outboundTunnel); @@ -243,7 +244,7 @@ namespace tunnel void SetMaxNumTransitTunnels (uint32_t maxNumTransitTunnels); uint32_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; }; - int GetCongestionLevel() const { return m_MaxNumTransitTunnels ? CONGESTION_LEVEL_FULL * m_TransitTunnels.size() / m_MaxNumTransitTunnels : CONGESTION_LEVEL_FULL; } + int GetCongestionLevel() const { return m_MaxNumTransitTunnels ? CONGESTION_LEVEL_FULL * m_TransitTunnels.GetNumTransitTunnels () / m_MaxNumTransitTunnels : CONGESTION_LEVEL_FULL; } std::mt19937& GetRng () { return m_Rng; }; @@ -265,7 +266,6 @@ namespace tunnel void ManageTunnels (uint64_t ts); void ManageOutboundTunnels (uint64_t ts); void ManageInboundTunnels (uint64_t ts); - void ManageTransitTunnels (uint64_t ts); void ManagePendingTunnels (uint64_t ts); template void ManagePendingTunnels (PendingTunnels& pendingTunnels, uint64_t ts); @@ -300,7 +300,6 @@ namespace tunnel std::map > m_PendingOutboundTunnels; // by replyMsgID std::list > m_InboundTunnels; std::list > m_OutboundTunnels; - std::list > m_TransitTunnels; std::unordered_map > m_Tunnels; // tunnelID->tunnel known by this id std::mutex m_PoolsMutex; std::list> m_Pools; @@ -314,14 +313,14 @@ namespace tunnel double m_TunnelCreationSuccessRate; int m_TunnelCreationAttemptsNum; std::mt19937 m_Rng; - TransitTunnelBuildMsgHandler m_TransitTunnelBuildMsgHandler; + TransitTunnels m_TransitTunnels; public: // for HTTP only const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; }; const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; }; - const decltype(m_TransitTunnels)& GetTransitTunnels () const { return m_TransitTunnels; }; + auto& GetTransitTunnels () const { return m_TransitTunnels.GetTransitTunnels (); }; size_t CountTransitTunnels() const; size_t CountInboundTunnels() const; From 391e3b7814da490c069eba5bd0ce2bdb9c49104a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 17 Nov 2024 17:29:04 -0500 Subject: [PATCH 255/527] don't schedule send for first SYN reply --- libi2pd/Streaming.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 788d6613..206f8197 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -705,7 +705,8 @@ namespace stream void Stream::SendBuffer () { - ScheduleSend (); + if (m_RemoteLeaseSet) // don't scheudle send for first SYN for incoming stream + ScheduleSend (); auto ts = i2p::util::GetMillisecondsSinceEpoch (); int numMsgs = m_WindowSize - m_SentPackets.size (); if (numMsgs <= 0 || !m_IsSendTime) // window is full From 3c4926f377177be9c98d29357567cac840093e44 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 17 Nov 2024 18:53:21 -0500 Subject: [PATCH 256/527] limit number of incoming ECIES sessions. Don't try to create ECIES session for incoming stream --- libi2pd/Garlic.cpp | 25 ++++++++++++++++++------- libi2pd/Garlic.h | 5 ++++- libi2pd/Streaming.cpp | 22 ++++++++++++++++++---- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 0d626234..b6f6d131 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -426,7 +426,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_LastIncomingSessionTimestamp (0), + m_NumRatchetInboundTags (0) // 0 means standard { } @@ -539,9 +540,17 @@ namespace garlic else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) { // otherwise ECIESx25519 - auto session = std::make_shared (this, false); // incoming - if (!session->HandleNextMessage (buf, length, nullptr, 0)) - LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + if (ts > m_LastIncomingSessionTimestamp + INCOMING_SESSIONS_MINIMAL_INTERVAL) + { + auto session = std::make_shared (this, false); // incoming + if (session->HandleNextMessage (buf, length, nullptr, 0)) + m_LastIncomingSessionTimestamp = ts; + else + LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); + } + else + LogPrint (eLogWarning, "Garlic: Incoming sessions come too ofter"); } else LogPrint (eLogError, "Garlic: Failed to decrypt message"); @@ -737,7 +746,8 @@ namespace garlic } std::shared_ptr GarlicDestination::GetRoutingSession ( - std::shared_ptr destination, bool attachLeaseSet) + 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)) @@ -752,15 +762,16 @@ namespace garlic if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ())) { LogPrint (eLogDebug, "Garlic: Session restarted"); + requestNewIfNotFound = true; // it's not a new session session = nullptr; } } - if (!session) + if (!session && requestNewIfNotFound) { session = std::make_shared (this, true); session->SetRemoteStaticKey (staticKey); } - if (destination->IsDestination ()) + if (session && destination->IsDestination ()) session->SetDestination (destination->GetIdentHash ()); // NS or NSR return session; } diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 80fc15da..57c3fddc 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -52,6 +52,7 @@ namespace garlic const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds const int LEASESET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds const int ROUTING_PATH_EXPIRATION_TIMEOUT = 120; // in seconds + const int INCOMING_SESSIONS_MINIMAL_INTERVAL = 200; // in milliseconds struct SessionTag: public i2p::data::Tag<32> { @@ -234,7 +235,8 @@ namespace garlic int GetNumTags () const { return m_NumTags; }; void SetNumRatchetInboundTags (int numTags) { m_NumRatchetInboundTags = numTags; }; int GetNumRatchetInboundTags () const { return m_NumRatchetInboundTags; }; - std::shared_ptr GetRoutingSession (std::shared_ptr destination, bool attachLeaseSet); + std::shared_ptr GetRoutingSession (std::shared_ptr destination, + bool attachLeaseSet, bool requestNewIfNotFound = true); void CleanupExpiredTags (); void RemoveDeliveryStatusSession (uint32_t msgID); std::shared_ptr WrapMessageForRouter (std::shared_ptr router, @@ -284,6 +286,7 @@ namespace garlic std::unordered_map m_Sessions; std::unordered_map, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session uint8_t * m_PayloadBuffer; // for ECIESX25519AEADRatchet + uint64_t m_LastIncomingSessionTimestamp; // in millseconds // incoming int m_NumRatchetInboundTags; std::unordered_map, std::hash > > m_Tags; diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 206f8197..3187f895 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -757,8 +757,8 @@ namespace stream if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());; if (m_RemoteLeaseSet) { - m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true); - m_MTU = m_RoutingSession->IsRatchets () ? STREAMING_MTU_RATCHETS : STREAMING_MTU; + m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true, !m_IsIncoming); + m_MTU = (m_RoutingSession && m_RoutingSession->IsRatchets ()) ? STREAMING_MTU_RATCHETS : STREAMING_MTU; } uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED | PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED; @@ -1115,7 +1115,15 @@ namespace stream } } if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ()) // expired and detached or new session sent - m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true); + { + m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true, !m_IsIncoming); + if (!m_RoutingSession) + { + LogPrint (eLogError, "Streaming: Can't obtain routing session, sSID=", m_SendStreamID); + Terminate (); + return; + } + } if (!m_CurrentOutboundTunnel && m_RoutingSession) // first message to send { // try to get shared path first @@ -1416,7 +1424,13 @@ namespace stream SendPackets (packets); m_LastSendTime = ts; m_IsSendTime = false; - if (m_IsNAcked || m_IsResendNeeded) ScheduleSend (); + if (m_IsNAcked || m_IsResendNeeded) + { + if (m_SequenceNumber > 1) // doesn't resend agressively very first packet + ScheduleSend (); + else + ScheduleResend (); + } } else SendBuffer (); From 5b2d0c579be971bb3ade319d20abd642209fed4a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 17 Nov 2024 20:51:59 -0500 Subject: [PATCH 257/527] close stream if SYACK is not acked --- libi2pd/Streaming.cpp | 185 +++++++++++++++++++++--------------------- 1 file changed, 93 insertions(+), 92 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 3187f895..b99c32c0 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1337,104 +1337,105 @@ namespace stream void Stream::ResendPacket () { - // check for resend attempts - if (m_NumResendAttempts >= MAX_NUM_RESEND_ATTEMPTS) - { - LogPrint (eLogWarning, "Streaming: packet was not ACKed after ", MAX_NUM_RESEND_ATTEMPTS, " attempts, terminate, rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID); - m_Status = eStreamStatusReset; - Close (); - return; - } + // check for resend attempts + if (m_SequenceNumber == 1 && m_NumResendAttempts > 0) + { + LogPrint (eLogWarning, "Streaming: SYNACK packet was not ACKed after ", m_NumResendAttempts, " attempts, terminate, rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID); + m_Status = eStreamStatusReset; + Close (); + return; + } + if (m_NumResendAttempts >= MAX_NUM_RESEND_ATTEMPTS) + { + LogPrint (eLogWarning, "Streaming: packet was not ACKed after ", MAX_NUM_RESEND_ATTEMPTS, " attempts, terminate, rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID); + m_Status = eStreamStatusReset; + Close (); + return; + } - // collect packets to resend - auto ts = i2p::util::GetMillisecondsSinceEpoch (); - std::vector packets; - if (m_IsNAcked) + // collect packets to resend + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + std::vector packets; + if (m_IsNAcked) + { + for (auto it : m_NACKedPackets) { - for (auto it : m_NACKedPackets) + if (ts >= it->sendTime + m_RTO) { - if (ts >= it->sendTime + m_RTO) - { - if (ts < it->sendTime + m_RTO*2) - it->resent = true; - else - it->resent = false; - it->sendTime = ts; - packets.push_back (it); - if ((int)packets.size () >= m_NumPacketsToSend) break; - } - } - } - else - { - for (auto it : m_SentPackets) - { - if (ts >= it->sendTime + m_RTO) - { - if (ts < it->sendTime + m_RTO*2) - it->resent = true; - else - it->resent = false; - it->sendTime = ts; - packets.push_back (it); - if ((int)packets.size () >= m_NumPacketsToSend) break; - } - } - } - - // select tunnels if necessary and send - if (packets.size () > 0 && m_IsSendTime) - { - if (m_IsNAcked) m_NumResendAttempts = 1; - else if (m_IsTimeOutResend) m_NumResendAttempts++; - if (m_NumResendAttempts == 1 && m_RTO != INITIAL_RTO) - { - // loss-based CC - if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED) - ProcessWindowDrop (); - } - else if (m_IsTimeOutResend) - { - m_IsTimeOutResend = false; - m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change - m_WindowDropTargetSize = INITIAL_WINDOW_SIZE; - m_LastWindowDropSize = 0; - m_WindowIncCounter = 0; - m_IsWinDropped = true; - m_IsFirstRttSample = true; - m_DropWindowDelaySequenceNumber = 0; - m_IsFirstACK = true; - UpdatePacingTime (); - if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); - if (m_NumResendAttempts & 1) - { - // pick another outbound tunnel - m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel); - LogPrint (eLogWarning, "Streaming: Resend #", m_NumResendAttempts, - ", another outbound tunnel has been selected for stream with sSID=", m_SendStreamID); - } + if (ts < it->sendTime + m_RTO*2) + it->resent = true; else - { - CancelRemoteLeaseChange (); - UpdateCurrentRemoteLease (); // pick another lease - LogPrint (eLogWarning, "Streaming: Resend #", m_NumResendAttempts, - ", another remote lease has been selected for stream with rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID); - } + it->resent = false; + it->sendTime = ts; + packets.push_back (it); + if ((int)packets.size () >= m_NumPacketsToSend) break; } - SendPackets (packets); - m_LastSendTime = ts; - m_IsSendTime = false; - if (m_IsNAcked || m_IsResendNeeded) - { - if (m_SequenceNumber > 1) // doesn't resend agressively very first packet - ScheduleSend (); - else - ScheduleResend (); - } } - else - SendBuffer (); - if (!m_IsNAcked && !m_IsResendNeeded) ScheduleResend (); + } + else + { + for (auto it : m_SentPackets) + { + if (ts >= it->sendTime + m_RTO) + { + if (ts < it->sendTime + m_RTO*2) + it->resent = true; + else + it->resent = false; + it->sendTime = ts; + packets.push_back (it); + if ((int)packets.size () >= m_NumPacketsToSend) break; + } + } + } + + // select tunnels if necessary and send + if (packets.size () > 0 && m_IsSendTime) + { + if (m_IsNAcked) m_NumResendAttempts = 1; + else if (m_IsTimeOutResend) m_NumResendAttempts++; + if (m_NumResendAttempts == 1 && m_RTO != INITIAL_RTO) + { + // loss-based CC + if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED) + ProcessWindowDrop (); + } + else if (m_IsTimeOutResend) + { + m_IsTimeOutResend = false; + m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change + m_WindowDropTargetSize = INITIAL_WINDOW_SIZE; + m_LastWindowDropSize = 0; + m_WindowIncCounter = 0; + m_IsWinDropped = true; + m_IsFirstRttSample = true; + m_DropWindowDelaySequenceNumber = 0; + m_IsFirstACK = true; + UpdatePacingTime (); + if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); + if (m_NumResendAttempts & 1) + { + // pick another outbound tunnel + m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel); + LogPrint (eLogWarning, "Streaming: Resend #", m_NumResendAttempts, + ", another outbound tunnel has been selected for stream with sSID=", m_SendStreamID); + } + else + { + CancelRemoteLeaseChange (); + UpdateCurrentRemoteLease (); // pick another lease + LogPrint (eLogWarning, "Streaming: Resend #", m_NumResendAttempts, + ", another remote lease has been selected for stream with rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID); + } + } + SendPackets (packets); + m_LastSendTime = ts; + m_IsSendTime = false; + if (m_IsNAcked || m_IsResendNeeded) ScheduleSend (); + } + else + SendBuffer (); + if (!m_IsNAcked && !m_IsResendNeeded) ScheduleResend (); } void Stream::ScheduleAck (int timeout) From 86080b26ae9734d6d0ce823a7a1d94aa978af277 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 17 Nov 2024 22:11:30 -0500 Subject: [PATCH 258/527] terminate non-established sessions sortly --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 1 + libi2pd/ECIESX25519AEADRatchetSession.h | 1 + 2 files changed, 2 insertions(+) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 63b739d7..ffd47a31 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -1113,6 +1113,7 @@ namespace garlic { CleanupUnconfirmedLeaseSet (ts); if (!m_Destination && ts > m_LastActivityTimestamp + ECIESX25519_SESSION_CREATE_TIMEOUT) return true; // m_LastActivityTimestamp is NS receive time + if (m_State != eSessionStateEstablished && m_SessionCreatedTimestamp && ts > m_SessionCreatedTimestamp + ECIESX25519_SESSION_ESTABLISH_TIMEOUT) return true; return ts > m_LastActivityTimestamp + ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT && // seconds ts*1000 > m_LastSentTimestamp + ECIESX25519_SEND_EXPIRATION_TIMEOUT*1000; // milliseconds } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index b55bfca2..960dedb8 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -31,6 +31,7 @@ namespace garlic const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds const int ECIESX25519_SESSION_CREATE_TIMEOUT = 3; // in seconds, NSR must be send after NS received + const int ECIESX25519_SESSION_ESTABLISH_TIMEOUT = 15; // in seconds const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // in seconds const int ECIESX25519_ACK_REQUEST_INTERVAL = 33000; // in milliseconds const int ECIESX25519_ACK_REQUEST_MAX_NUM_ATTEMPTS = 3; From 5d5970bed447a3b4eb07f61fa732fd5ab127e7d1 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 18 Nov 2024 07:59:39 -0500 Subject: [PATCH 259/527] more SYN resend attempts for outgoing stream --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index b99c32c0..6232859e 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1338,7 +1338,7 @@ namespace stream void Stream::ResendPacket () { // check for resend attempts - if (m_SequenceNumber == 1 && m_NumResendAttempts > 0) + if (m_IsIncoming && m_SequenceNumber == 1 && m_NumResendAttempts > 0) { LogPrint (eLogWarning, "Streaming: SYNACK packet was not ACKed after ", m_NumResendAttempts, " attempts, terminate, rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID); m_Status = eStreamStatusReset; From a05bb937928a6ee4ed895e3014407d7aa030a019 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 18 Nov 2024 12:16:05 -0500 Subject: [PATCH 260/527] check LeaseSet expiration time --- libi2pd/LeaseSet.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 66faed84..5b1c5635 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -425,6 +425,11 @@ namespace data if (offset + 1 > len) return 0; int numLeases = buf[offset]; offset++; auto ts = i2p::util::GetMillisecondsSinceEpoch (); + if (GetExpirationTime () > ts + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT*1000LL) + { + LogPrint (eLogWarning, "LeaseSet2: Expiration time is too long ", GetExpirationTime ()/1000LL); + SetExpirationTime (ts + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT*1000LL); + } if (IsStoreLeases ()) { UpdateLeasesBegin (); From 5265dc71e9cf619b24337005b8d39e56d8a24867 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 18 Nov 2024 15:49:11 -0500 Subject: [PATCH 261/527] drop too old LeaseSet or from future --- libi2pd/LeaseSet.cpp | 16 +++++++++++++--- libi2pd/LeaseSet.h | 5 +++-- libi2pd/NetDb.cpp | 3 +-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 5b1c5635..ee1964fc 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -425,10 +425,15 @@ namespace data if (offset + 1 > len) return 0; int numLeases = buf[offset]; offset++; auto ts = i2p::util::GetMillisecondsSinceEpoch (); - if (GetExpirationTime () > ts + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT*1000LL) + if (GetExpirationTime () > ts + LEASESET_EXPIRATION_TIME_THRESHOLD) { - LogPrint (eLogWarning, "LeaseSet2: Expiration time is too long ", GetExpirationTime ()/1000LL); - SetExpirationTime (ts + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT*1000LL); + LogPrint (eLogWarning, "LeaseSet2: Expiration time is from future ", GetExpirationTime ()/1000LL); + return 0; + } + if (ts > m_PublishedTimestamp*1000LL + LEASESET_EXPIRATION_TIME_THRESHOLD) + { + LogPrint (eLogWarning, "LeaseSet2: Published time is too old ", m_PublishedTimestamp); + return 0; } if (IsStoreLeases ()) { @@ -440,6 +445,11 @@ namespace data lease.tunnelGateway = buf + offset; offset += 32; // gateway lease.tunnelID = bufbe32toh (buf + offset); offset += 4; // tunnel ID lease.endDate = bufbe32toh (buf + offset)*1000LL; offset += 4; // end date + if (lease.endDate > ts + LEASESET_EXPIRATION_TIME_THRESHOLD) + { + LogPrint (eLogWarning, "LeaseSet2: Lease end date is from future ", lease.endDate); + return 0; + } UpdateLease (lease, ts); } UpdateLeasesEnd (); diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index 7eea3aed..a365ae77 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -62,7 +62,8 @@ namespace data 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; - + const uint64_t LEASESET_EXPIRATION_TIME_THRESHOLD = 12*60*1000; // in milliseconds + const uint8_t NETDB_STORE_TYPE_LEASESET = 1; class LeaseSet: public RoutingDestination { @@ -180,7 +181,7 @@ namespace data private: uint8_t m_StoreType; - uint32_t m_PublishedTimestamp = 0; + uint32_t m_PublishedTimestamp = 0; // seconds bool m_IsPublic = true, m_IsPublishedEncrypted = false; std::shared_ptr m_TransientVerifier; CryptoKeyType m_EncryptionType; diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index c96bcf95..18d6308b 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -384,8 +384,7 @@ namespace data if (it == m_LeaseSets.end () || it->second->GetStoreType () != storeType || leaseSet->GetPublishedTimestamp () > it->second->GetPublishedTimestamp ()) { - if (leaseSet->IsPublic () && !leaseSet->IsExpired () && - i2p::util::GetSecondsSinceEpoch () + NETDB_EXPIRATION_TIMEOUT_THRESHOLD > leaseSet->GetPublishedTimestamp ()) + if (leaseSet->IsPublic () && !leaseSet->IsExpired ()) { // TODO: implement actual update if (CheckLogLevel (eLogInfo)) From f2596e0187cc5687cfff4699c4a7e88b91c1a2d8 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 18 Nov 2024 21:34:41 -0500 Subject: [PATCH 262/527] fixed typo with cleanup timer expiration --- libi2pd/Destination.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index cff6d73a..08acc0ed 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -168,7 +168,7 @@ namespace client LoadTags (); m_Pool->SetLocalDestination (shared_from_this ()); m_Pool->SetActive (true); - m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT)); + m_CleanupTimer.expires_from_now (boost::posix_time::seconds (DESTINATION_CLEANUP_TIMEOUT)); m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer, shared_from_this (), std::placeholders::_1)); } @@ -985,7 +985,7 @@ namespace client { if (it->second->IsEmpty () || ts > it->second->GetExpirationTime ()) // leaseset expired { - LogPrint (eLogWarning, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired"); + LogPrint (eLogDebug, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired"); it = m_RemoteLeaseSets.erase (it); } else From b80278421dd6c45064ee3f6959e523f5f4bba67a Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 19 Nov 2024 13:00:13 -0500 Subject: [PATCH 263/527] re-create ECIES session for follow-on packets --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 6232859e..ece2979d 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1116,7 +1116,7 @@ namespace stream } if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ()) // expired and detached or new session sent { - m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true, !m_IsIncoming); + m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true, !m_IsIncoming || m_SequenceNumber > 1); if (!m_RoutingSession) { LogPrint (eLogError, "Streaming: Can't obtain routing session, sSID=", m_SendStreamID); From d241e5d5cbf7c78de7badf19608a164d355dbf54 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 19 Nov 2024 19:11:09 -0500 Subject: [PATCH 264/527] handle transit tunnel build messages in separate thread --- libi2pd/TransitTunnel.cpp | 73 +++++++++++++++++++++++++++++++++++++++ libi2pd/TransitTunnel.h | 27 +++++++++++---- libi2pd/Tunnel.cpp | 8 +++-- libi2pd/Tunnel.h | 5 +-- 4 files changed, 101 insertions(+), 12 deletions(-) diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index edf96c31..8284dc14 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -122,14 +122,86 @@ namespace tunnel } } + TransitTunnels::TransitTunnels (): + m_IsRunning (false) + { + } + + TransitTunnels::~TransitTunnels () + { + Stop (); + } + void TransitTunnels::Start () { + m_IsRunning = true; + m_Thread.reset (new std::thread (std::bind (&TransitTunnels::Run, this))); } void TransitTunnels::Stop () { + m_IsRunning = false; + m_TunnelBuildMsgQueue.WakeUp (); + if (m_Thread) + { + m_Thread->join (); + m_Thread = nullptr; + } m_TransitTunnels.clear (); } + + void TransitTunnels::Run () + { + i2p::util::SetThreadName("TBM"); + uint64_t lastTs = 0; + std::list > msgs; + while (m_IsRunning) + { + try + { + if (m_TunnelBuildMsgQueue.Wait (TRANSIT_TUNNELS_QUEUE_WAIT_INTERVAL, 0)) + { + m_TunnelBuildMsgQueue.GetWholeQueue (msgs); + while (!msgs.empty ()) + { + auto msg = msgs.front (); msgs.pop_front (); + if (!msg) continue; + uint8_t typeID = msg->GetTypeID (); + switch (typeID) + { + case eI2NPShortTunnelBuild: + HandleShortTransitTunnelBuildMsg (std::move (msg)); + break; + case eI2NPVariableTunnelBuild: + HandleVariableTransitTunnelBuildMsg (std::move (msg)); + break; + default: + LogPrint (eLogWarning, "TransitTunnel: Unexpected message type ", (int) typeID); + } + if (!m_IsRunning) break; + } + } + if (m_IsRunning) + { + uint64_t ts = i2p::util::GetSecondsSinceEpoch (); + if (ts >= lastTs + TUNNEL_MANAGE_INTERVAL || ts + TUNNEL_MANAGE_INTERVAL < lastTs) + { + ManageTransitTunnels (ts); + lastTs = ts; + } + } + } + catch (std::exception& ex) + { + LogPrint (eLogError, "TransitTunnel: Runtime exception: ", ex.what ()); + } + } + } + + void TransitTunnels::PostTransitTunnelBuildMsg (std::shared_ptr&& msg) + { + if (msg) m_TunnelBuildMsgQueue.Put (msg); + } void TransitTunnels::HandleShortTransitTunnelBuildMsg (std::shared_ptr&& msg) { @@ -234,6 +306,7 @@ namespace tunnel { if (transitTunnel) { + LogPrint (eLogDebug, "TransitTunnel: Failed to send reply for transit tunnel ", transitTunnel->GetTunnelID ()); auto t = transitTunnel->GetCreationTime (); if (t > i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT) // make transit tunnel expired diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index fc8676d0..bff1a8dd 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.h @@ -14,6 +14,7 @@ #include #include #include "Crypto.h" +#include "Queue.h" #include "I2NPProtocol.h" #include "TunnelEndpoint.h" #include "TunnelGateway.h" @@ -109,33 +110,45 @@ namespace tunnel const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey, bool isGateway, bool isEndpoint); + + const int TRANSIT_TUNNELS_QUEUE_WAIT_INTERVAL = 10; // in seconds + class TransitTunnels { public: + TransitTunnels (); + ~TransitTunnels (); + void Start (); void Stop (); - void ManageTransitTunnels (uint64_t ts); - + void PostTransitTunnelBuildMsg (std::shared_ptr&& msg); + size_t GetNumTransitTunnels () const { return m_TransitTunnels.size (); } int GetTransitTunnelsExpirationTimeout (); - - void HandleShortTransitTunnelBuildMsg (std::shared_ptr&& msg); - void HandleVariableTransitTunnelBuildMsg (std::shared_ptr&& msg); private: bool AddTransitTunnel (std::shared_ptr tunnel); + void ManageTransitTunnels (uint64_t ts); + + void HandleShortTransitTunnelBuildMsg (std::shared_ptr&& msg); + void HandleVariableTransitTunnelBuildMsg (std::shared_ptr&& msg); bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText); + void Run (); + private: + volatile bool m_IsRunning; + std::unique_ptr m_Thread; std::list > m_TransitTunnels; - + i2p::util::Queue > m_TunnelBuildMsgQueue; + public: // for HTTP only - auto& GetTransitTunnels () const { return m_TransitTunnels; }; + const auto& GetTransitTunnels () const { return m_TransitTunnels; }; }; } } diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index d809e48a..e7443b6c 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -373,6 +373,7 @@ namespace tunnel std::shared_ptr Tunnels::GetTunnel (uint32_t tunnelID) { + std::lock_guard l(m_TunnelsMutex); auto it = m_Tunnels.find(tunnelID); if (it != m_Tunnels.end ()) return it->second; @@ -382,11 +383,13 @@ namespace tunnel bool Tunnels::AddTunnel (std::shared_ptr tunnel) { if (!tunnel) return false; + std::lock_guard l(m_TunnelsMutex); return m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second; } void Tunnels::RemoveTunnel (uint32_t tunnelID) { + std::lock_guard l(m_TunnelsMutex); m_Tunnels.erase (tunnelID); } @@ -655,7 +658,7 @@ namespace tunnel return; } else - m_TransitTunnels.HandleShortTransitTunnelBuildMsg (std::move (msg)); + m_TransitTunnels.PostTransitTunnelBuildMsg (std::move (msg)); } void Tunnels::HandleVariableTunnelBuildMsg (std::shared_ptr msg) @@ -678,7 +681,7 @@ namespace tunnel } } else - m_TransitTunnels.HandleVariableTransitTunnelBuildMsg (std::move (msg)); + m_TransitTunnels.PostTransitTunnelBuildMsg (std::move (msg)); } void Tunnels::HandleTunnelBuildReplyMsg (std::shared_ptr msg, bool isShort) @@ -710,7 +713,6 @@ namespace tunnel ManagePendingTunnels (ts); ManageInboundTunnels (ts); ManageOutboundTunnels (ts); - m_TransitTunnels.ManageTransitTunnels (ts); } void Tunnels::ManagePendingTunnels (uint64_t ts) diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index fcccd236..a25012a4 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -300,8 +300,9 @@ namespace tunnel std::map > m_PendingOutboundTunnels; // by replyMsgID std::list > m_InboundTunnels; std::list > m_OutboundTunnels; + mutable std::mutex m_TunnelsMutex; std::unordered_map > m_Tunnels; // tunnelID->tunnel known by this id - std::mutex m_PoolsMutex; + mutable std::mutex m_PoolsMutex; std::list> m_Pools; std::shared_ptr m_ExploratoryPool; i2p::util::Queue > m_Queue; @@ -320,7 +321,7 @@ namespace tunnel // for HTTP only const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; }; const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; }; - auto& GetTransitTunnels () const { return m_TransitTunnels.GetTransitTunnels (); }; + const auto& GetTransitTunnels () const { return m_TransitTunnels.GetTransitTunnels (); }; size_t CountTransitTunnels() const; size_t CountInboundTunnels() const; From 09ae278306c3467a65881ead01779e52a73e7e96 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 20 Nov 2024 13:27:25 -0500 Subject: [PATCH 265/527] const GetSize() --- libi2pd/Queue.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/Queue.h b/libi2pd/Queue.h index ec62bddf..0e3e4fde 100644 --- a/libi2pd/Queue.h +++ b/libi2pd/Queue.h @@ -84,7 +84,7 @@ namespace util return m_Queue.empty (); } - int GetSize () + int GetSize () const { std::unique_lock l(m_QueueMutex); return m_Queue.size (); @@ -134,7 +134,7 @@ namespace util private: std::list m_Queue; - std::mutex m_QueueMutex; + mutable std::mutex m_QueueMutex; std::condition_variable m_NonEmpty; }; } From a248a2a73253afbbb92dcac77128cd012b78edd9 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 20 Nov 2024 13:28:01 -0500 Subject: [PATCH 266/527] Show TBM Queue size --- daemon/HTTPServer.cpp | 1 + libi2pd/TransitTunnel.h | 1 + libi2pd/Tunnel.h | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 21c7b6c6..a13e8e57 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -701,6 +701,7 @@ namespace http { { s << "" << tr("Tunnels") << ":
\r\n"; s << "" << tr("Queue size") << ": " << i2p::tunnel::tunnels.GetQueueSize () << "
\r\n
\r\n"; + s << "" << tr("TBM Queue size") << ": " << i2p::tunnel::tunnels.GetTBMQueueSize () << "
\r\n
\r\n"; auto ExplPool = i2p::tunnel::tunnels.GetExploratoryPool (); diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index bff1a8dd..c4a6e156 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.h @@ -149,6 +149,7 @@ namespace tunnel // for HTTP only const auto& GetTransitTunnels () const { return m_TransitTunnels; }; + size_t GetTunnelBuildMsgQueueSize () const { return m_TunnelBuildMsgQueue.GetSize (); }; }; } } diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index a25012a4..2d0641e3 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -327,7 +327,8 @@ namespace tunnel size_t CountInboundTunnels() const; size_t CountOutboundTunnels() const; - int GetQueueSize () { return m_Queue.GetSize (); }; + size_t GetQueueSize () const { return m_Queue.GetSize (); }; + size_t GetTBMQueueSize () const { return m_TransitTunnels.GetTunnelBuildMsgQueueSize (); }; int GetTunnelCreationSuccessRate () const { return std::round(m_TunnelCreationSuccessRate * 100); } // in percents double GetPreciseTunnelCreationSuccessRate () const { return m_TunnelCreationSuccessRate * 100; } // in percents int GetTotalTunnelCreationSuccessRate () const // in percents From 6fb3c7c3ba44e1d3b2d9d70395e876689fc22327 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 23 Nov 2024 18:34:33 -0500 Subject: [PATCH 267/527] removed dependancy from boost_system for newer compliers --- Makefile.linux | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Makefile.linux b/Makefile.linux index aa67626a..9c3e6895 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -13,12 +13,9 @@ LDFLAGS ?= ${LD_DEBUG} CXXVER := $(shell $(CXX) -dumpversion) ifeq ($(shell expr match $(CXX) 'clang'),5) NEEDED_CXXFLAGS += -std=c++17 -else ifeq ($(shell expr match ${CXXVER} "7"),1) # gcc 7 - NEEDED_CXXFLAGS += -std=c++17 - LDLIBS = -lboost_filesystem else ifeq ($(shell expr match ${CXXVER} "[8-9]"),1) # gcc 8 - 9 NEEDED_CXXFLAGS += -std=c++17 - LDLIBS = -lstdc++fs + LDLIBS = -lboost_system -lstdc++fs else ifeq ($(shell expr match ${CXXVER} "1[0-2]"),2) # gcc 10 - 12 NEEDED_CXXFLAGS += -std=c++17 else ifeq ($(shell expr match ${CXXVER} "1[3-9]"),2) # gcc 13+ @@ -34,7 +31,6 @@ ifeq ($(USE_STATIC),yes) # Using 'getaddrinfo' in statically linked applications requires at runtime # the shared libraries from the glibc version used for linking LIBDIR := /usr/lib/$(SYS) - LDLIBS += $(LIBDIR)/libboost_system.a LDLIBS += $(LIBDIR)/libboost_program_options.a LDLIBS += $(LIBDIR)/libssl.a LDLIBS += $(LIBDIR)/libcrypto.a @@ -44,7 +40,7 @@ ifeq ($(USE_UPNP),yes) endif LDLIBS += -lpthread -ldl else - LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_program_options -lpthread -latomic + LDLIBS += -lcrypto -lssl -lz -lboost_program_options -lpthread -latomic ifeq ($(USE_UPNP),yes) LDLIBS += -lminiupnpc endif From 5f1b31213f8d69bca35acf5589356da9162a64cc Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 25 Nov 2024 08:12:40 -0500 Subject: [PATCH 268/527] more adequate initial RTT --- libi2pd/Streaming.cpp | 4 ++-- libi2pd/Streaming.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index ece2979d..0569c873 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -537,7 +537,7 @@ namespace stream m_LocalDestination.DeletePacket (sentPacket); acknowledged = true; if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK) - if (m_RTT < m_LocalDestination.GetRandom () % INITIAL_RTT) // dirty + if (m_RTT < m_LocalDestination.GetRandom () % INITIAL_RTO) // dirty m_WindowIncCounter++; } else @@ -1143,7 +1143,7 @@ namespace stream CancelRemoteLeaseChange (); UpdateCurrentRemoteLease (true); } - if (m_RemoteLeaseChangeTime && m_IsRemoteLeaseChangeInProgress && ts > m_RemoteLeaseChangeTime + INITIAL_RTT) + if (m_RemoteLeaseChangeTime && m_IsRemoteLeaseChangeInProgress && ts > m_RemoteLeaseChangeTime + INITIAL_RTO) { CancelRemoteLeaseChange (); m_CurrentRemoteLease = m_NextRemoteLease; diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 11fc04d1..14a4e80b 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -60,7 +60,7 @@ namespace stream const double SLOWRTT_EWMA_ALPHA = 0.05; const double PREV_SPEED_KEEP_TIME_COEFF = 0.35; // 0.1 - 1 // how long will the window size stay around the previous drop level, less is longer const int MIN_RTO = 20; // in milliseconds - const int INITIAL_RTT = 8000; // in milliseconds + const int INITIAL_RTT = 1500; // in milliseconds const int INITIAL_RTO = 9000; // in milliseconds const int INITIAL_PACING_TIME = 1000 * INITIAL_RTT / INITIAL_WINDOW_SIZE; // in microseconds const int MIN_SEND_ACK_TIMEOUT = 2; // in milliseconds From 34745386974845ab3b9e1e2b15c2013f3b2a2f7b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 25 Nov 2024 10:08:27 -0500 Subject: [PATCH 269/527] replaced boost::asio::io_service by boost::asio:io_context --- daemon/UPnP.h | 2 +- libi2pd/Destination.cpp | 4 ++-- libi2pd/Destination.h | 10 +++++----- libi2pd/NTCP2.h | 2 +- libi2pd/Reseed.cpp | 4 ++-- libi2pd/SSU2.h | 4 ++-- libi2pd/Streaming.cpp | 4 ++-- libi2pd/Streaming.h | 6 +++--- libi2pd/Timestamp.cpp | 2 +- libi2pd/Timestamp.h | 2 +- libi2pd/Transports.cpp | 4 ++-- libi2pd/Transports.h | 6 +++--- libi2pd/util.h | 6 +++--- libi2pd_client/BOB.h | 4 ++-- libi2pd_client/ClientContext.cpp | 4 ++-- libi2pd_client/ClientContext.h | 4 ++-- libi2pd_client/I2CP.cpp | 2 +- libi2pd_client/I2CP.h | 4 ++-- libi2pd_client/I2PService.h | 2 +- libi2pd_client/SAM.h | 2 +- 20 files changed, 39 insertions(+), 39 deletions(-) diff --git a/daemon/UPnP.h b/daemon/UPnP.h index d865df40..2a5fe9f3 100644 --- a/daemon/UPnP.h +++ b/daemon/UPnP.h @@ -67,7 +67,7 @@ namespace transport std::unique_ptr m_Thread; std::condition_variable m_Started; std::mutex m_StartedMutex; - boost::asio::io_service m_Service; + boost::asio::io_context m_Service; boost::asio::deadline_timer m_Timer; bool m_upnpUrlsInitialized = false; struct UPNPUrls m_upnpUrls; diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 08acc0ed..a165d5b9 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -23,7 +23,7 @@ namespace i2p { namespace client { - LeaseSetDestination::LeaseSetDestination (boost::asio::io_service& service, + LeaseSetDestination::LeaseSetDestination (boost::asio::io_context& service, bool isPublic, const std::map * params): m_Service (service), m_IsPublic (isPublic), m_PublishReplyToken (0), m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service), @@ -1000,7 +1000,7 @@ namespace client return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL; } - ClientDestination::ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys, + 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), diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 8d49ef82..7516c90f 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -107,7 +107,7 @@ namespace client // leaseSet = nullptr means not found struct LeaseSetRequest { - LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {}; + LeaseSetRequest (boost::asio::io_context& service): requestTime (0), requestTimeoutTimer (service) {}; std::unordered_set excluded; uint64_t requestTime; boost::asio::deadline_timer requestTimeoutTimer; @@ -125,10 +125,10 @@ namespace client public: - LeaseSetDestination (boost::asio::io_service& service, bool isPublic, const std::map * params = nullptr); + LeaseSetDestination (boost::asio::io_context& service, bool isPublic, const std::map * params = nullptr); ~LeaseSetDestination (); const std::string& GetNickname () const { return m_Nickname; }; - boost::asio::io_service& GetService () { return m_Service; }; + auto& GetService () { return m_Service; }; virtual void Start (); virtual void Stop (); @@ -195,7 +195,7 @@ namespace client private: - boost::asio::io_service& m_Service; + boost::asio::io_context& m_Service; mutable std::mutex m_RemoteLeaseSetsMutex; std::unordered_map > m_RemoteLeaseSets; std::unordered_map > m_LeaseSetRequests; @@ -241,7 +241,7 @@ namespace client public: - ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys, + ClientDestination (boost::asio::io_context& service, const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params = nullptr); ~ClientDestination (); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 27acb529..e1718bb0 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -253,7 +253,7 @@ namespace transport void Start (); void Stop (); - boost::asio::io_service& GetService () { return GetIOService (); }; + auto& GetService () { return GetIOService (); }; std::mt19937& GetRng () { return m_Rng; }; bool AddNTCP2Session (std::shared_ptr session, bool incoming = false); diff --git a/libi2pd/Reseed.cpp b/libi2pd/Reseed.cpp index f8307a56..13e18d99 100644 --- a/libi2pd/Reseed.cpp +++ b/libi2pd/Reseed.cpp @@ -552,7 +552,7 @@ namespace data if (!url.port) url.port = 443; - boost::asio::io_service service; + boost::asio::io_context service; boost::system::error_code ecode; boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); @@ -746,7 +746,7 @@ namespace data if (!url.port) url.port = 80; boost::system::error_code ecode; - boost::asio::io_service service; + boost::asio::io_context service; boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6()); auto it = boost::asio::ip::tcp::resolver(service).resolve ( diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 95f053a9..715e72ab 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -61,7 +61,7 @@ namespace transport public: ReceiveService (const std::string& name): RunnableService (name) {}; - boost::asio::io_service& GetService () { return GetIOService (); }; + auto& GetService () { return GetIOService (); }; void Start () { StartIOService (); }; void Stop () { StopIOService (); }; }; @@ -73,7 +73,7 @@ namespace transport void Start (); void Stop (); - boost::asio::io_service& GetService () { return GetIOService (); }; + auto& GetService () { return GetIOService (); }; void SetLocalAddress (const boost::asio::ip::address& localAddress); bool SetProxy (const std::string& address, uint16_t port); bool UsesProxy () const { return m_IsThroughProxy; }; diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 0569c873..8caccfcf 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -66,7 +66,7 @@ namespace stream } } - Stream::Stream (boost::asio::io_service& service, StreamingDestination& local, + Stream::Stream (boost::asio::io_context& service, StreamingDestination& local, std::shared_ptr remote, int port): m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), @@ -95,7 +95,7 @@ namespace stream m_PacketACKInterval = (1000000LL*STREAMING_MTU)/inboundSpeed; } - Stream::Stream (boost::asio::io_service& service, StreamingDestination& local): + Stream::Stream (boost::asio::io_context& service, StreamingDestination& local): m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 14a4e80b..d2fcc6b9 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -175,9 +175,9 @@ namespace stream { public: - Stream (boost::asio::io_service& service, StreamingDestination& local, + Stream (boost::asio::io_context& service, StreamingDestination& local, std::shared_ptr remote, int port = 0); // outgoing - Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming + Stream (boost::asio::io_context& service, StreamingDestination& local); // incoming ~Stream (); uint32_t GetSendStreamID () const { return m_SendStreamID; }; @@ -255,7 +255,7 @@ namespace stream private: - boost::asio::io_service& m_Service; + boost::asio::io_context& m_Service; uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber; uint32_t m_DropWindowDelaySequenceNumber; uint32_t m_TunnelsChangeSequenceNumber; diff --git a/libi2pd/Timestamp.cpp b/libi2pd/Timestamp.cpp index c5c37cd7..51f68ded 100644 --- a/libi2pd/Timestamp.cpp +++ b/libi2pd/Timestamp.cpp @@ -60,7 +60,7 @@ namespace util static void SyncTimeWithNTP (const std::string& address) { LogPrint (eLogInfo, "Timestamp: NTP request to ", address); - boost::asio::io_service service; + boost::asio::io_context service; boost::system::error_code ec; auto it = boost::asio::ip::udp::resolver (service).resolve ( boost::asio::ip::udp::resolver::query (address, "ntp"), ec); diff --git a/libi2pd/Timestamp.h b/libi2pd/Timestamp.h index d949d416..00c60433 100644 --- a/libi2pd/Timestamp.h +++ b/libi2pd/Timestamp.h @@ -52,7 +52,7 @@ namespace util bool m_IsRunning; std::unique_ptr m_Thread; - boost::asio::io_service m_Service; + boost::asio::io_context m_Service; boost::asio::deadline_timer m_Timer; int m_SyncInterval; std::vector m_NTPServersList; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index b07b1b0b..cd879cb3 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -174,8 +174,8 @@ namespace transport { if (!m_Service) { - m_Service = new boost::asio::io_service (); - m_Work = new boost::asio::io_service::work (*m_Service); + m_Service = new boost::asio::io_context (); + m_Work = new boost::asio::io_context::work (*m_Service); m_PeerCleanupTimer = new boost::asio::deadline_timer (*m_Service); m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service); m_UpdateBandwidthTimer = new boost::asio::deadline_timer (*m_Service); diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 8271108d..431237a3 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -139,7 +139,7 @@ namespace transport bool IsOnline() const { return m_IsOnline; }; void SetOnline (bool online); - boost::asio::io_service& GetService () { return *m_Service; }; + auto& GetService () { return *m_Service; }; std::shared_ptr GetNextX25519KeysPair (); void ReuseX25519KeysPair (std::shared_ptr pair); @@ -207,8 +207,8 @@ namespace transport volatile bool m_IsOnline; bool m_IsRunning, m_IsNAT, m_CheckReserved; std::thread * m_Thread; - boost::asio::io_service * m_Service; - boost::asio::io_service::work * m_Work; + boost::asio::io_context * m_Service; + boost::asio::io_context::work * m_Work; boost::asio::deadline_timer * m_PeerCleanupTimer, * m_PeerTestTimer, * m_UpdateBandwidthTimer; SSU2Server * m_SSU2Server; diff --git a/libi2pd/util.h b/libi2pd/util.h index 48bcb801..dd065052 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -177,7 +177,7 @@ namespace util RunnableService (const std::string& name): m_Name (name), m_IsRunning (false) {} virtual ~RunnableService () {} - boost::asio::io_service& GetIOService () { return m_Service; } + auto& GetIOService () { return m_Service; } bool IsRunning () const { return m_IsRunning; }; void StartIOService (); @@ -194,7 +194,7 @@ namespace util std::string m_Name; volatile bool m_IsRunning; std::unique_ptr m_Thread; - boost::asio::io_service m_Service; + boost::asio::io_context m_Service; }; class RunnableServiceWithWork: public RunnableService @@ -206,7 +206,7 @@ namespace util private: - boost::asio::io_service::work m_Work; + boost::asio::io_context::work m_Work; }; void SetThreadName (const char *name); diff --git a/libi2pd_client/BOB.h b/libi2pd_client/BOB.h index 1f5fda5f..79066154 100644 --- a/libi2pd_client/BOB.h +++ b/libi2pd_client/BOB.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 * @@ -254,7 +254,7 @@ namespace client void Start (); void Stop (); - boost::asio::io_service& GetService () { return GetIOService (); }; + auto& GetService () { return GetIOService (); }; void AddDestination (const std::string& name, std::shared_ptr dest); void DeleteDestination (const std::string& name); std::shared_ptr FindDestination (const std::string& name); diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index aa49f83e..72051805 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -345,7 +345,7 @@ namespace client } std::shared_ptr ClientContext::CreateNewLocalDestination ( - boost::asio::io_service& service, bool isPublic, + boost::asio::io_context& service, bool isPublic, i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType, const std::map * params) { @@ -399,7 +399,7 @@ namespace client return localDestination; } - std::shared_ptr ClientContext::CreateNewLocalDestination (boost::asio::io_service& service, + std::shared_ptr ClientContext::CreateNewLocalDestination (boost::asio::io_context& service, const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params) { auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ()); diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index adec607a..febd5f16 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.h @@ -79,13 +79,13 @@ namespace client i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL, const std::map * params = nullptr); // used by SAM only - std::shared_ptr CreateNewLocalDestination (boost::asio::io_service& service, + std::shared_ptr CreateNewLocalDestination (boost::asio::io_context& service, bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL, const std::map * params = nullptr); // same as previous but on external io_service std::shared_ptr CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true, const std::map * params = nullptr); - std::shared_ptr CreateNewLocalDestination (boost::asio::io_service& service, + std::shared_ptr CreateNewLocalDestination (boost::asio::io_context& service, const i2p::data::PrivateKeys& keys, bool isPublic = true, const std::map * params = nullptr); // same as previous but on external io_service std::shared_ptr CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index fc6d1b40..7aec7549 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -24,7 +24,7 @@ namespace i2p namespace client { - I2CPDestination::I2CPDestination (boost::asio::io_service& service, std::shared_ptr owner, + I2CPDestination::I2CPDestination (boost::asio::io_context& service, std::shared_ptr owner, std::shared_ptr identity, bool isPublic, bool isSameThread, const std::map& params): LeaseSetDestination (service, isPublic, ¶ms), diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 620ff52e..e929c1e1 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -81,7 +81,7 @@ namespace client { public: - I2CPDestination (boost::asio::io_service& service, std::shared_ptr owner, + I2CPDestination (boost::asio::io_context& service, std::shared_ptr owner, std::shared_ptr identity, bool isPublic, bool isSameThread, const std::map& params); ~I2CPDestination () {}; @@ -227,7 +227,7 @@ namespace client void Start (); void Stop (); - boost::asio::io_service& GetService () { return GetIOService (); }; + auto& GetService () { return GetIOService (); }; bool IsSingleThread () const { return m_IsSingleThread; }; bool InsertSession (std::shared_ptr session); diff --git a/libi2pd_client/I2PService.h b/libi2pd_client/I2PService.h index d35c954d..adcc3da7 100644 --- a/libi2pd_client/I2PService.h +++ b/libi2pd_client/I2PService.h @@ -61,7 +61,7 @@ namespace client } void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, uint16_t port = 0); void CreateStream(StreamRequestComplete complete, std::shared_ptr address, uint16_t port); - inline boost::asio::io_service& GetService () { return m_LocalDestination->GetService (); } + auto& GetService () { return m_LocalDestination->GetService (); } virtual void Start () = 0; virtual void Stop () = 0; diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 3ed8f00c..10ef4957 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -246,7 +246,7 @@ namespace client void Start (); void Stop (); - boost::asio::io_service& GetService () { return GetIOService (); }; + auto& GetService () { return GetIOService (); }; std::shared_ptr CreateSession (const std::string& id, SAMSessionType type, const std::string& destination, // empty string means transient const std::map * params); bool AddSession (std::shared_ptr session); From ffd18baf30d0259f140e74f5c47ff455e54f2dd8 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 25 Nov 2024 16:00:06 -0500 Subject: [PATCH 270/527] support boost 1.87 --- daemon/HTTPServer.cpp | 4 ++-- daemon/HTTPServer.h | 4 ++-- daemon/I2PControl.cpp | 2 +- daemon/I2PControl.h | 4 ++-- libi2pd/Destination.cpp | 30 ++++++++++++------------ libi2pd/NTCP2.cpp | 21 ++++++++--------- libi2pd/NetDbRequests.cpp | 8 +++---- libi2pd/Reseed.cpp | 20 ++++++---------- libi2pd/RouterContext.cpp | 24 +++++++++---------- libi2pd/RouterContext.h | 2 +- libi2pd/RouterInfo.cpp | 2 +- libi2pd/SSU2.cpp | 24 +++++++++---------- libi2pd/Streaming.cpp | 12 +++++----- libi2pd/Streaming.h | 10 ++++---- libi2pd/Timestamp.cpp | 8 +++---- libi2pd/Transports.cpp | 20 ++++++++-------- libi2pd/Transports.h | 2 +- libi2pd/util.cpp | 10 ++++---- libi2pd/util.h | 4 ++-- libi2pd_client/BOB.cpp | 12 +++++----- libi2pd_client/ClientContext.cpp | 6 ++--- libi2pd_client/HTTPProxy.cpp | 24 ++++++++++--------- libi2pd_client/I2CP.cpp | 6 ++--- libi2pd_client/I2PService.h | 2 +- libi2pd_client/I2PTunnel.cpp | 15 ++++++------ libi2pd_client/I2PTunnel.h | 4 ++-- libi2pd_client/SAM.cpp | 16 ++++++------- libi2pd_client/SOCKS.cpp | 40 ++++++++++++++++---------------- 28 files changed, 164 insertions(+), 172 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index a13e8e57..e32bd459 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -1486,8 +1486,8 @@ namespace http { } HTTPServer::HTTPServer (const std::string& address, int port): - m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), - m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)), + m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service.get_executor ()), + m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::make_address(address), port)), m_Hostname(address) { } diff --git a/daemon/HTTPServer.h b/daemon/HTTPServer.h index f751c5a8..38b790d4 100644 --- a/daemon/HTTPServer.h +++ b/daemon/HTTPServer.h @@ -83,8 +83,8 @@ namespace http bool m_IsRunning; std::unique_ptr m_Thread; - boost::asio::io_service m_Service; - boost::asio::io_service::work m_Work; + boost::asio::io_context m_Service; + boost::asio::executor_work_guard m_Work; boost::asio::ip::tcp::acceptor m_Acceptor; std::string m_Hostname; }; diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 43c74199..1ea75bbb 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -31,7 +31,7 @@ namespace client { I2PControlService::I2PControlService (const std::string& address, int port): m_IsRunning (false), m_Thread (nullptr), - m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)), + m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(address), port)), m_SSLContext (boost::asio::ssl::context::sslv23), m_ShutdownTimer (m_Service) { diff --git a/daemon/I2PControl.h b/daemon/I2PControl.h index af152631..ff32c131 100644 --- a/daemon/I2PControl.h +++ b/daemon/I2PControl.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 * @@ -88,7 +88,7 @@ namespace client bool m_IsRunning; std::thread * m_Thread; - boost::asio::io_service m_Service; + boost::asio::io_context m_Service; boost::asio::ip::tcp::acceptor m_Acceptor; boost::asio::ssl::context m_SSLContext; boost::asio::deadline_timer m_ShutdownTimer; diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index a165d5b9..2d1aa2c8 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -294,7 +294,7 @@ namespace client if (m_IsPublic) { auto s = shared_from_this (); - m_Service.post ([s](void) + boost::asio::post (m_Service, [s](void) { s->m_PublishVerificationTimer.cancel (); s->Publish (); @@ -322,7 +322,7 @@ namespace client memcpy (data.k, key, 32); memcpy (data.t, tag, 32); auto s = shared_from_this (); - m_Service.post ([s,data](void) + boost::asio::post (m_Service, [s,data](void) { s->AddSessionKey (data.k, data.t); }); @@ -339,7 +339,7 @@ namespace client memcpy (data.k, key, 32); data.t = tag; auto s = shared_from_this (); - m_Service.post ([s,data](void) + boost::asio::post (m_Service, [s,data](void) { s->AddECIESx25519Key (data.k, data.t); }); @@ -355,7 +355,7 @@ namespace client m_IncomingMsgsQueue.push_back (msg); } if (empty) - m_Service.post([s = shared_from_this ()]() + boost::asio::post (m_Service, [s = shared_from_this ()]() { std::list > receivedMsgs; { @@ -370,7 +370,7 @@ namespace client void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr msg) { uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET); - m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msgID)); + boost::asio::post (m_Service, std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msgID)); } void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len) @@ -608,7 +608,7 @@ namespace client void LeaseSetDestination::SetLeaseSetUpdated (bool post) { if (post) - m_Service.post([s = shared_from_this ()]() { s->UpdateLeaseSet (); }); + boost::asio::post (m_Service, [s = shared_from_this ()]() { s->UpdateLeaseSet (); }); else UpdateLeaseSet (); } @@ -690,7 +690,7 @@ namespace client auto s = shared_from_this (); msg->onDrop = [s]() { - s->GetService ().post([s]() + boost::asio::post (s->GetService (), [s]() { s->m_PublishConfirmationTimer.cancel (); s->HandlePublishConfirmationTimer (boost::system::error_code()); @@ -775,10 +775,10 @@ namespace client if (!m_Pool || !IsReady ()) { if (requestComplete) - m_Service.post ([requestComplete](void){requestComplete (nullptr);}); + boost::asio::post (m_Service, [requestComplete](void){requestComplete (nullptr);}); return false; } - m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete, nullptr)); + boost::asio::post (m_Service, std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete, nullptr)); return true; } @@ -787,7 +787,7 @@ namespace client if (!dest || !m_Pool || !IsReady ()) { if (requestComplete) - m_Service.post ([requestComplete](void){requestComplete (nullptr);}); + boost::asio::post (m_Service, [requestComplete](void){requestComplete (nullptr);}); return false; } auto storeHash = dest->GetStoreHash (); @@ -795,17 +795,17 @@ namespace client if (leaseSet) { if (requestComplete) - m_Service.post ([requestComplete, leaseSet](void){requestComplete (leaseSet);}); + boost::asio::post (m_Service, [requestComplete, leaseSet](void){requestComplete (leaseSet);}); return true; } - m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), storeHash, requestComplete, dest)); + boost::asio::post (m_Service, std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), storeHash, requestComplete, dest)); return true; } void LeaseSetDestination::CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify) { auto s = shared_from_this (); - m_Service.post ([dest, notify, s](void) + boost::asio::post (m_Service, [dest, notify, s](void) { auto it = s->m_LeaseSetRequests.find (dest); if (it != s->m_LeaseSetRequests.end ()) @@ -903,7 +903,7 @@ namespace client auto s = shared_from_this (); msg->onDrop = [s, dest, request]() { - s->GetService ().post([s, dest, request]() + boost::asio::post (s->GetService (), [s, dest, request]() { s->SendNextLeaseSetRequest (dest, request); }); @@ -1215,7 +1215,7 @@ namespace client if (leaseSet) { auto stream = CreateStream (leaseSet, port); - GetService ().post ([streamRequestComplete, stream]() + boost::asio::post (GetService (), [streamRequestComplete, stream]() { streamRequestComplete(stream); }); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 33c33596..38efc825 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -406,7 +406,7 @@ namespace transport void NTCP2Session::Done () { - m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); } void NTCP2Session::Established () @@ -508,7 +508,7 @@ namespace transport { // we don't care about padding, send SessionCreated and close session SendSessionCreated (); - m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); } else if (paddingLen > 0) { @@ -1296,7 +1296,7 @@ namespace transport void NTCP2Session::SendTerminationAndTerminate (NTCP2TerminationReason reason) { SendTermination (reason); - m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); // let termination message go + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); // let termination message go } void NTCP2Session::SendI2NPMessages (std::list >& msgs) @@ -1313,7 +1313,7 @@ namespace transport m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs); } if (empty) - m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this ())); + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this ())); } void NTCP2Session::PostI2NPMessages () @@ -1350,7 +1350,7 @@ namespace transport void NTCP2Session::SendLocalRouterInfo (bool update) { if (update || !IsOutgoing ()) // we send it in SessionConfirmed for outgoing session - m_Server.GetService ().post (std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ())); + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ())); } NTCP2Server::NTCP2Server (): @@ -1374,14 +1374,13 @@ namespace transport { LogPrint(eLogInfo, "NTCP2: Using proxy to connect to peers"); // TODO: resolve proxy until it is resolved - boost::asio::ip::tcp::resolver::query q(m_ProxyAddress, std::to_string(m_ProxyPort)); boost::system::error_code e; - auto itr = m_Resolver.resolve(q, e); + auto itr = m_Resolver.resolve(m_ProxyAddress, std::to_string(m_ProxyPort), e); if(e) LogPrint(eLogCritical, "NTCP2: Failed to resolve proxy ", e.message()); else { - m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint(*itr)); + m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint(*itr.begin ())); if (m_ProxyEndpoint) LogPrint(eLogDebug, "NTCP2: m_ProxyEndpoint ", *m_ProxyEndpoint); } @@ -1541,7 +1540,7 @@ namespace transport } LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint (), " (", i2p::data::GetIdentHashAbbreviation (conn->GetRemoteIdentity ()->GetIdentHash ()), ")"); - GetService ().post([this, conn]() + boost::asio::post (GetService (), [this, conn]() { if (this->AddNTCP2Session (conn)) { @@ -1762,7 +1761,7 @@ namespace transport LogPrint (eLogError, "NTCP2: Can't connect to unspecified address"); return; } - GetService().post([this, conn]() + boost::asio::post (GetService(), [this, conn]() { if (this->AddNTCP2Session (conn)) { @@ -1860,7 +1859,7 @@ namespace transport { readbuff->commit(transferred); i2p::http::HTTPRes res; - if(res.parse(boost::asio::buffer_cast(readbuff->data()), readbuff->size()) > 0) + if(res.parse(std::string {boost::asio::buffers_begin(readbuff->data ()), boost::asio::buffers_begin(readbuff->data ()) + readbuff->size ()}) > 0) { if(res.code == 200) { diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index 0e632c26..63d161cd 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -179,7 +179,7 @@ namespace data void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr r) { - GetIOService ().post ([this, ident, r]() + boost::asio::post (GetIOService (), [this, ident, r]() { std::shared_ptr request; auto it = m_RequestedDestinations.find (ident); @@ -267,7 +267,7 @@ namespace data { if (dest->IsActive ()) { - s->GetIOService ().post ([s, dest]() + boost::asio::post (s->GetIOService (), [s, dest]() { if (dest->IsActive ()) s->SendNextRequest (dest); }); @@ -345,7 +345,7 @@ namespace data void NetDbRequests::PostDatabaseSearchReplyMsg (std::shared_ptr msg) { - GetIOService ().post ([this, msg]() + boost::asio::post (GetIOService (), [this, msg]() { HandleDatabaseSearchReplyMsg (msg); }); @@ -431,7 +431,7 @@ namespace data void NetDbRequests::PostRequestDestination (const IdentHash& destination, const RequestedDestination::RequestComplete& requestComplete, bool direct) { - GetIOService ().post ([this, destination, requestComplete, direct]() + boost::asio::post (GetIOService (), [this, destination, requestComplete, direct]() { RequestDestination (destination, requestComplete, direct); }); diff --git a/libi2pd/Reseed.cpp b/libi2pd/Reseed.cpp index 13e18d99..6cf277bf 100644 --- a/libi2pd/Reseed.cpp +++ b/libi2pd/Reseed.cpp @@ -562,11 +562,10 @@ namespace data if(proxyUrl.schema.size()) { // proxy connection - auto it = boost::asio::ip::tcp::resolver(service).resolve ( - boost::asio::ip::tcp::resolver::query (proxyUrl.host, std::to_string(proxyUrl.port)), ecode); + auto it = boost::asio::ip::tcp::resolver(service).resolve (proxyUrl.host, std::to_string(proxyUrl.port), ecode); if(!ecode) { - s.lowest_layer().connect(*it, ecode); + s.lowest_layer().connect(*it.begin (), ecode); if(!ecode) { auto & sock = s.next_layer(); @@ -599,7 +598,7 @@ namespace data LogPrint(eLogError, "Reseed: HTTP CONNECT read error: ", ecode.message()); return ""; } - if(proxyRes.parse(boost::asio::buffer_cast(readbuf.data()), readbuf.size()) <= 0) + if(proxyRes.parse(std::string {boost::asio::buffers_begin(readbuf.data ()), boost::asio::buffers_begin(readbuf.data ()) + readbuf.size ()}) <= 0) { sock.close(); LogPrint(eLogError, "Reseed: HTTP CONNECT malformed reply"); @@ -638,13 +637,11 @@ namespace data else { // direct connection - auto it = boost::asio::ip::tcp::resolver(service).resolve ( - boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode); + auto endpoints = boost::asio::ip::tcp::resolver(service).resolve (url.host, std::to_string(url.port), ecode); if (!ecode) { bool connected = false; - boost::asio::ip::tcp::resolver::iterator end; - while (it != end) + for (auto it = endpoints.begin (); it != endpoints.end ();) { boost::asio::ip::tcp::endpoint ep = *it; bool supported = false; @@ -749,14 +746,11 @@ namespace data boost::asio::io_context service; boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6()); - auto it = boost::asio::ip::tcp::resolver(service).resolve ( - boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode); - + auto endpoints = boost::asio::ip::tcp::resolver(service).resolve (url.host, std::to_string(url.port), ecode); if (!ecode) { bool connected = false; - boost::asio::ip::tcp::resolver::iterator end; - while (it != end) + for (auto it = endpoints.begin (); it != endpoints.end ();) { boost::asio::ip::tcp::endpoint ep = *it; if ( diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 558e9608..fdcdb145 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -140,7 +140,7 @@ namespace i2p { boost::asio::ip::address addr; if (!host.empty ()) - addr = boost::asio::ip::address::from_string (host); + addr = boost::asio::ip::make_address (host); if (!addr.is_v4()) addr = boost::asio::ip::address_v4 (); routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port); @@ -161,7 +161,7 @@ namespace i2p { boost::asio::ip::address addr; if (!host.empty ()) - addr = boost::asio::ip::address::from_string (host); + addr = boost::asio::ip::make_address (host); if (!addr.is_v4()) addr = boost::asio::ip::address_v4 (); routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port); @@ -192,7 +192,7 @@ namespace i2p ntcp2Host = host; boost::asio::ip::address addr; if (!ntcp2Host.empty ()) - addr = boost::asio::ip::address::from_string (ntcp2Host); + addr = boost::asio::ip::make_address (ntcp2Host); if (!addr.is_v6()) addr = boost::asio::ip::address_v6 (); routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port); @@ -211,7 +211,7 @@ namespace i2p { boost::asio::ip::address addr; if (!host.empty ()) - addr = boost::asio::ip::address::from_string (host); + addr = boost::asio::ip::make_address (host); if (!addr.is_v6()) addr = boost::asio::ip::address_v6 (); routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port); @@ -802,7 +802,7 @@ namespace i2p i2p::config::GetOption("host", ntcp2Host); if (!ntcp2Host.empty () && ntcp2Port) { - auto addr = boost::asio::ip::address::from_string (ntcp2Host); + auto addr = boost::asio::ip::make_address (ntcp2Host); if (addr.is_v6 ()) { m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port); @@ -831,7 +831,7 @@ namespace i2p std::string host; i2p::config::GetOption("host", host); if (!host.empty ()) { - auto addr = boost::asio::ip::address::from_string (host); + auto addr = boost::asio::ip::make_address (host); if (addr.is_v6 ()) { m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port); @@ -900,7 +900,7 @@ namespace i2p std::string host; i2p::config::GetOption("host", host); if (!host.empty ()) { - auto addr = boost::asio::ip::address::from_string (host); + auto addr = boost::asio::ip::make_address (host); if (addr.is_v4 ()) { m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port); @@ -930,7 +930,7 @@ namespace i2p std::string host; i2p::config::GetOption("host", host); if (!host.empty ()) { - auto addr = boost::asio::ip::address::from_string (host); + auto addr = boost::asio::ip::make_address (host); if (addr.is_v4 ()) { m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port); @@ -1185,7 +1185,7 @@ namespace i2p void RouterContext::ProcessGarlicMessage (std::shared_ptr msg) { if (m_Service) - m_Service->GetService ().post (std::bind (&RouterContext::PostGarlicMessage, this, msg)); + boost::asio::post (m_Service->GetService (), std::bind (&RouterContext::PostGarlicMessage, this, msg)); else LogPrint (eLogError, "Router: service is NULL"); } @@ -1213,7 +1213,7 @@ namespace i2p void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr msg) { if (m_Service) - m_Service->GetService ().post (std::bind (&RouterContext::PostDeliveryStatusMessage, this, msg)); + boost::asio::post (m_Service->GetService (), std::bind (&RouterContext::PostDeliveryStatusMessage, this, msg)); else LogPrint (eLogError, "Router: service is NULL"); } @@ -1242,7 +1242,7 @@ namespace i2p } data; memcpy (data.k, key, 32); data.t = tag; - m_Service->GetService ().post ([this,data](void) + boost::asio::post (m_Service->GetService (), [this,data](void) { AddECIESx25519Key (data.k, data.t); }); @@ -1408,7 +1408,7 @@ namespace i2p auto onDrop = [this]() { if (m_Service) - m_Service->GetService ().post ([this]() { HandlePublishResendTimer (boost::system::error_code ()); }); + boost::asio::post (m_Service->GetService (), [this]() { HandlePublishResendTimer (boost::system::error_code ()); }); }; if (i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()) || // already connected (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) && // are we able to connect diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 0dfef254..5060866a 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -90,7 +90,7 @@ namespace garlic public: RouterService (): RunnableServiceWithWork ("Router") {}; - boost::asio::io_service& GetService () { return GetIOService (); }; + auto& GetService () { return GetIOService (); }; void Start () { StartIOService (); }; void Stop () { StopIOService (); }; }; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 2321a1e0..0d53f6cd 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -257,7 +257,7 @@ namespace data if (!strcmp (key, "host")) { boost::system::error_code ecode; - address->host = boost::asio::ip::address::from_string (value, ecode); + address->host = boost::asio::ip::make_address (value, ecode); if (!ecode && !address->host.is_unspecified ()) { if (!i2p::transport::transports.IsInReservedRange (address->host) || diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index a53c877c..982940c5 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -81,7 +81,7 @@ namespace transport found = true; LogPrint (eLogDebug, "SSU2: Opening IPv4 socket at Start"); OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV4, port)); - m_ReceiveService.GetService ().post( + boost::asio::post (m_ReceiveService.GetService (), [this]() { Receive (m_SocketV4); @@ -93,8 +93,8 @@ namespace transport found = true; LogPrint (eLogDebug, "SSU2: Opening IPv6 socket at Start"); OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV6, port)); - m_ReceiveService.GetService ().post( - [this]() + boost::asio::post (m_ReceiveService.GetService (), + [this]() { Receive (m_SocketV6); }); @@ -451,7 +451,7 @@ namespace transport m_ReceivedPacketsQueue.push_back (packet); } if (empty) - GetService ().post([this]() { HandleReceivedPacketsQueue (); }); + boost::asio::post (GetService (), [this]() { HandleReceivedPacketsQueue (); }); } void SSU2Server::InsertToReceivedPacketsQueue (std::list& packets) @@ -471,7 +471,7 @@ namespace transport } } if (!queueSize) - GetService ().post([this]() { HandleReceivedPacketsQueue (); }); + boost::asio::post (GetService (), [this]() { HandleReceivedPacketsQueue (); }); } void SSU2Server::HandleReceivedPacketsQueue () @@ -522,7 +522,7 @@ namespace transport void SSU2Server::RequestRemoveSession (uint64_t connID) { - GetService ().post ([connID, this]() { RemoveSession (connID); }); + boost::asio::post (GetService (), [connID, this]() { RemoveSession (connID); }); } void SSU2Server::AddSessionByRouterHash (std::shared_ptr session) @@ -550,7 +550,7 @@ namespace transport // move unsent msgs to new session oldSession->MoveSendQueue (session); // terminate existing - GetService ().post (std::bind (&SSU2Session::RequestTermination, oldSession, eSSU2TerminationReasonReplacedByNewSession)); + boost::asio::post (GetService (), std::bind (&SSU2Session::RequestTermination, oldSession, eSSU2TerminationReasonReplacedByNewSession)); } } } @@ -878,7 +878,7 @@ namespace transport { // session with router found, trying to send peer test if requested if (peerTest && existingSession->IsEstablished ()) - GetService ().post ([existingSession]() { existingSession->SendPeerTest (); }); + boost::asio::post (GetService (), [existingSession]() { existingSession->SendPeerTest (); }); return false; } // check is no pending session @@ -905,9 +905,9 @@ namespace transport session->SetOnEstablished ([session]() {session->SendPeerTest (); }); if (isValidEndpoint) // we know endpoint - GetService ().post ([session]() { session->Connect (); }); + boost::asio::post (GetService (), [session]() { session->Connect (); }); else if (address->UsesIntroducer ()) // we don't know endpoint yet - GetService ().post (std::bind (&SSU2Server::ConnectThroughIntroducer, this, session)); + boost::asio::post (GetService (), std::bind (&SSU2Server::ConnectThroughIntroducer, this, session)); else return false; } @@ -1050,7 +1050,7 @@ namespace transport if (!remoteAddr || !remoteAddr->IsPeerTesting () || (v4 && !remoteAddr->IsV4 ()) || (!v4 && !remoteAddr->IsV6 ())) return false; if (session->IsEstablished ()) - GetService ().post ([session]() { session->SendPeerTest (); }); + boost::asio::post (GetService (), [session]() { session->SendPeerTest (); }); else session->SetOnEstablished ([session]() { session->SendPeerTest (); }); return true; @@ -1764,7 +1764,7 @@ namespace transport bool SSU2Server::SetProxy (const std::string& address, uint16_t port) { boost::system::error_code ecode; - auto addr = boost::asio::ip::address::from_string (address, ecode); + auto addr = boost::asio::ip::make_address (address, ecode); if (!ecode && !addr.is_unspecified () && port) { m_IsThroughProxy = true; diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 8caccfcf..efa190cf 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -667,7 +667,7 @@ namespace stream { // make sure that AsycReceive complete auto s = shared_from_this(); - m_Service.post ([s]() + boost::asio::post (m_Service, [s]() { s->m_ReceiveTimer.cancel (); }); @@ -695,7 +695,7 @@ namespace stream else if (handler) handler(boost::system::error_code ()); auto s = shared_from_this (); - m_Service.post ([s, buffer]() + boost::asio::post (m_Service, [s, buffer]() { if (buffer) s->m_SendBuffer.Add (buffer); @@ -1058,7 +1058,7 @@ namespace stream m_LocalDestination.GetOwner ()->Sign (packet, size, signature); p->len = size; - m_Service.post (std::bind (&Stream::SendPacket, shared_from_this (), p)); + boost::asio::post (m_Service, std::bind (&Stream::SendPacket, shared_from_this (), p)); LogPrint (eLogDebug, "Streaming: FIN sent, sSID=", m_SendStreamID); } @@ -1855,7 +1855,7 @@ namespace stream if (it == m_Streams.end ()) return false; auto s = it->second; - m_Owner->GetService ().post ([this, s] () + boost::asio::post (m_Owner->GetService (), [this, s] () { s->Close (); // try to send FIN s->Terminate (false); @@ -1868,7 +1868,7 @@ namespace stream { m_Acceptor = acceptor; // we must set it immediately for IsAcceptorSet auto s = shared_from_this (); - m_Owner->GetService ().post([s](void) + boost::asio::post (m_Owner->GetService (), [s](void) { // take care about incoming queue for (auto& it: s->m_PendingIncomingStreams) @@ -1887,7 +1887,7 @@ namespace stream void StreamingDestination::AcceptOnce (const Acceptor& acceptor) { - m_Owner->GetService ().post([acceptor, this](void) + boost::asio::post (m_Owner->GetService (), [acceptor, this](void) { if (!m_PendingIncomingStreams.empty ()) { diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index d2fcc6b9..e5dba39f 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -202,7 +202,7 @@ namespace stream size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); }; size_t Receive (uint8_t * buf, size_t len, int timeout); - void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); }; + void AsyncClose() { boost::asio::post(m_Service, std::bind(&Stream::Close, shared_from_this())); }; /** only call close from destination thread, use Stream::AsyncClose for other threads */ void Close (); @@ -238,7 +238,7 @@ namespace stream void UpdateCurrentRemoteLease (bool expired = false); template - void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout); + void HandleReceiveTimer (const boost::system::error_code& ecode, Buffer& buffer, ReceiveHandler handler, int remainingTimeout); void ScheduleSend (); void HandleSendTimer (const boost::system::error_code& ecode); @@ -375,7 +375,7 @@ namespace stream void Stream::AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout) { auto s = shared_from_this(); - m_Service.post ([s, buffer, handler, timeout](void) + boost::asio::post (m_Service, [s, buffer, handler, timeout](void) { if (!s->m_ReceiveQueue.empty () || s->m_Status == eStreamStatusReset) s->HandleReceiveTimer (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), buffer, handler, 0); @@ -394,9 +394,9 @@ namespace stream } template - void Stream::HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout) + void Stream::HandleReceiveTimer (const boost::system::error_code& ecode, Buffer& buffer, ReceiveHandler handler, int remainingTimeout) { - size_t received = ConcatenatePackets (boost::asio::buffer_cast(buffer), boost::asio::buffer_size(buffer)); + size_t received = ConcatenatePackets ((uint8_t *)buffer.data (), buffer.size ()); if (received > 0) handler (boost::system::error_code (), received); else if (ecode == boost::asio::error::operation_aborted) diff --git a/libi2pd/Timestamp.cpp b/libi2pd/Timestamp.cpp index 51f68ded..210ef3b9 100644 --- a/libi2pd/Timestamp.cpp +++ b/libi2pd/Timestamp.cpp @@ -62,14 +62,12 @@ namespace util LogPrint (eLogInfo, "Timestamp: NTP request to ", address); boost::asio::io_context service; boost::system::error_code ec; - auto it = boost::asio::ip::udp::resolver (service).resolve ( - boost::asio::ip::udp::resolver::query (address, "ntp"), ec); + auto endpoints = boost::asio::ip::udp::resolver (service).resolve (address, "ntp", ec); if (!ec) { bool found = false; - boost::asio::ip::udp::resolver::iterator end; boost::asio::ip::udp::endpoint ep; - while (it != end) + for (auto it = endpoints.begin (); it != endpoints.end ();) { ep = *it; if (!ep.address ().is_unspecified ()) @@ -154,7 +152,7 @@ namespace util { m_IsRunning = true; LogPrint(eLogInfo, "Timestamp: NTP time sync starting"); - m_Service.post (std::bind (&NTPTimeSync::Sync, this)); + boost::asio::post (m_Service, std::bind (&NTPTimeSync::Sync, this)); m_Thread.reset (new std::thread (std::bind (&NTPTimeSync::Run, this))); } else diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index cd879cb3..e2f8c730 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -175,7 +175,7 @@ namespace transport if (!m_Service) { m_Service = new boost::asio::io_context (); - m_Work = new boost::asio::io_context::work (*m_Service); + m_Work = new boost::asio::executor_work_guard (m_Service->get_executor ()); m_PeerCleanupTimer = new boost::asio::deadline_timer (*m_Service); m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service); m_UpdateBandwidthTimer = new boost::asio::deadline_timer (*m_Service); @@ -249,7 +249,7 @@ namespace transport if (!address.empty ()) { boost::system::error_code ec; - auto addr = boost::asio::ip::address::from_string (address, ec); + auto addr = boost::asio::ip::make_address (address, ec); if (!ec) { if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr); @@ -275,7 +275,7 @@ namespace transport if (!address.empty ()) { boost::system::error_code ec; - auto addr = boost::asio::ip::address::from_string (address, ec); + auto addr = boost::asio::ip::make_address (address, ec); if (!ec) { if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr); @@ -302,7 +302,7 @@ namespace transport if (!address.empty ()) { boost::system::error_code ec; - auto addr = boost::asio::ip::address::from_string (address, ec); + auto addr = boost::asio::ip::make_address (address, ec); if (!ec && m_NTCP2Server && i2p::util::net::IsYggdrasilAddress (addr)) m_NTCP2Server->SetLocalAddress (addr); } @@ -462,7 +462,7 @@ namespace transport void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list >&& msgs) { - m_Service->post ([this, ident, msgs = std::move(msgs)] () mutable + boost::asio::post (*m_Service, [this, ident, msgs = std::move(msgs)] () mutable { PostMessages (ident, msgs); }); @@ -719,7 +719,7 @@ namespace transport void Transports::RequestComplete (std::shared_ptr r, const i2p::data::IdentHash& ident) { - m_Service->post (std::bind (&Transports::HandleRequestComplete, this, r, ident)); + boost::asio::post (*m_Service, std::bind (&Transports::HandleRequestComplete, this, r, ident)); } void Transports::HandleRequestComplete (std::shared_ptr r, i2p::data::IdentHash ident) @@ -856,7 +856,7 @@ namespace transport void Transports::PeerConnected (std::shared_ptr session) { - m_Service->post([session, this]() + boost::asio::post (*m_Service, [session, this]() { auto remoteIdentity = session->GetRemoteIdentity (); if (!remoteIdentity) return; @@ -928,7 +928,7 @@ namespace transport void Transports::PeerDisconnected (std::shared_ptr session) { - m_Service->post([session, this]() + boost::asio::post (*m_Service, [session, this]() { auto remoteIdentity = session->GetRemoteIdentity (); if (!remoteIdentity) return; @@ -1276,7 +1276,7 @@ namespace transport std::string yggaddress; i2p::config::GetOption ("meshnets.yggaddress", yggaddress); if (!yggaddress.empty ()) { - yggaddr = boost::asio::ip::address_v6::from_string (yggaddress); + yggaddr = boost::asio::ip::make_address (yggaddress).to_v6 (); if (yggaddr.is_unspecified () || !i2p::util::net::IsYggdrasilAddress (yggaddr) || !i2p::util::net::IsLocalAddress (yggaddr)) { @@ -1321,7 +1321,7 @@ namespace transport if (ipv6) { std::string ipv6Addr; i2p::config::GetOption("ntcp2.addressv6", ipv6Addr); - auto addr = boost::asio::ip::address_v6::from_string (ipv6Addr); + auto addr = boost::asio::ip::make_address (ipv6Addr).to_v6 (); if (!addr.is_unspecified () && addr != boost::asio::ip::address_v6::any ()) i2p::context.UpdateNTCP2V6Address (addr); // set ipv6 address if configured } diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 431237a3..5829b9f3 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -208,7 +208,7 @@ namespace transport bool m_IsRunning, m_IsNAT, m_CheckReserved; std::thread * m_Thread; boost::asio::io_context * m_Service; - boost::asio::io_context::work * m_Work; + boost::asio::executor_work_guard * m_Work; boost::asio::deadline_timer * m_PeerCleanupTimer, * m_PeerTestTimer, * m_UpdateBandwidthTimer; SSU2Server * m_SSU2Server; diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 47cecbbe..aff3d0e0 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -123,8 +123,8 @@ const char *inet_ntop_xp(int af, const void *src, char *dst, socklen_t size) #endif #endif -#define address_pair_v4(a,b) { boost::asio::ip::address_v4::from_string (a).to_ulong (), boost::asio::ip::address_v4::from_string (b).to_ulong () } -#define address_pair_v6(a,b) { boost::asio::ip::address_v6::from_string (a).to_bytes (), boost::asio::ip::address_v6::from_string (b).to_bytes () } +#define address_pair_v4(a,b) { boost::asio::ip::make_address (a).to_v4 ().to_uint (), boost::asio::ip::make_address(b).to_v4 ().to_uint () } +#define address_pair_v6(a,b) { boost::asio::ip::make_address (a).to_v6 ().to_bytes (), boost::asio::ip::make_address(b).to_v6 ().to_bytes () } namespace i2p { @@ -478,7 +478,7 @@ namespace net inet_ntop(af, &((sockaddr_in6 *)cur->ifa_addr)->sin6_addr, addr, INET6_ADDRSTRLEN); freeifaddrs(addrs); std::string cur_ifaddr(addr); - return boost::asio::ip::address::from_string(cur_ifaddr); + return boost::asio::ip::make_address(cur_ifaddr); } } } @@ -498,7 +498,7 @@ namespace net fallback = "127.0.0.1"; LogPrint(eLogWarning, "NetIface: Cannot find IPv4 address for interface ", ifname); } - return boost::asio::ip::address::from_string(fallback); + return boost::asio::ip::make_address(fallback); #endif } @@ -664,7 +664,7 @@ namespace net address_pair_v4("224.0.0.0", "255.255.255.255") }; - uint32_t ipv4_address = host.to_v4 ().to_ulong (); + uint32_t ipv4_address = host.to_v4 ().to_uint (); for (const auto& it : reservedIPv4Ranges) { if (ipv4_address >= it.first && ipv4_address <= it.second) return true; diff --git a/libi2pd/util.h b/libi2pd/util.h index dd065052..7bd35e67 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -202,11 +202,11 @@ namespace util protected: RunnableServiceWithWork (const std::string& name): - RunnableService (name), m_Work (GetIOService ()) {} + RunnableService (name), m_Work (GetIOService ().get_executor ()) {} private: - boost::asio::io_context::work m_Work; + boost::asio::executor_work_guard m_Work; }; void SetThreadName (const char *name); diff --git a/libi2pd_client/BOB.cpp b/libi2pd_client/BOB.cpp index 23c3b72f..f2dab223 100644 --- a/libi2pd_client/BOB.cpp +++ b/libi2pd_client/BOB.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 * @@ -129,7 +129,7 @@ namespace client BOBI2POutboundTunnel::BOBI2POutboundTunnel (const std::string& outhost, uint16_t port, std::shared_ptr localDestination, bool quiet): BOBI2PTunnel (localDestination), - m_Endpoint (boost::asio::ip::address::from_string (outhost), port), m_IsQuiet (quiet) + m_Endpoint (boost::asio::ip::make_address (outhost), port), m_IsQuiet (quiet) { } @@ -220,7 +220,7 @@ namespace client if (!inhost.empty ()) { boost::system::error_code ec; - auto addr = boost::asio::ip::address::from_string (inhost, ec); + auto addr = boost::asio::ip::make_address (inhost, ec); if (!ec) ep.address (addr); else @@ -425,7 +425,7 @@ namespace client { // TODO: FIXME: temporary validation, until hostname support is added boost::system::error_code ec; - boost::asio::ip::address::from_string(m_InHost, ec); + boost::asio::ip::make_address(m_InHost, ec); if (ec) { SendReplyError("inhost must be a valid IPv4 address."); @@ -436,7 +436,7 @@ namespace client { // TODO: FIXME: temporary validation, until hostname support is added boost::system::error_code ec; - boost::asio::ip::address::from_string(m_OutHost, ec); + boost::asio::ip::make_address(m_OutHost, ec); if (ec) { SendReplyError("outhost must be a IPv4 address."); @@ -828,7 +828,7 @@ namespace client BOBCommandChannel::BOBCommandChannel (const std::string& address, uint16_t port): RunnableService ("BOB"), - m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)) + m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(address), port)) { // command -> handler m_CommandHandlers[BOB_COMMAND_ZAP] = &BOBCommandSession::ZapCommandHandler; diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 72051805..8c8c2bfa 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -631,7 +631,7 @@ namespace client if (type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) { // udp client // TODO: hostnames - boost::asio::ip::udp::endpoint end (boost::asio::ip::address::from_string(address), port); + boost::asio::ip::udp::endpoint end (boost::asio::ip::make_address(address), port); if (!localDestination) localDestination = m_SharedLocalDestination; @@ -787,7 +787,7 @@ namespace client { // udp server tunnel // TODO: hostnames - boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port); + boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::make_address(host), port); if (address.empty ()) { if (!endpoint.address ().is_unspecified () && endpoint.address ().is_v6 ()) @@ -795,7 +795,7 @@ namespace client else address = "127.0.0.1"; } - auto localAddress = boost::asio::ip::address::from_string(address); + auto localAddress = boost::asio::ip::make_address(address); auto serverTunnel = std::make_shared(name, localDestination, localAddress, endpoint, inPort, gzip); if(!isUniqueLocal) { diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index dba65815..13e0f571 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -98,7 +98,7 @@ namespace proxy { typedef std::function ProxyResolvedHandler; - void HandleUpstreamProxyResolved(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr, ProxyResolvedHandler handler); + void HandleUpstreamProxyResolved(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::results_type endpoints, ProxyResolvedHandler handler); void SocksProxySuccess(); void HandoverToUpstreamProxy(); @@ -584,20 +584,22 @@ namespace proxy { } else { - boost::asio::ip::tcp::resolver::query q(m_ProxyURL.host, std::to_string(m_ProxyURL.port)); - m_proxy_resolver.async_resolve(q, std::bind(&HTTPReqHandler::HandleUpstreamProxyResolved, this, std::placeholders::_1, std::placeholders::_2, [&](boost::asio::ip::tcp::endpoint ep) { - m_proxysock->async_connect(ep, std::bind(&HTTPReqHandler::HandleUpstreamHTTPProxyConnect, this, std::placeholders::_1)); - })); + m_proxy_resolver.async_resolve(m_ProxyURL.host, std::to_string(m_ProxyURL.port), std::bind(&HTTPReqHandler::HandleUpstreamProxyResolved, this, + std::placeholders::_1, std::placeholders::_2, [&](boost::asio::ip::tcp::endpoint ep) + { + m_proxysock->async_connect(ep, std::bind(&HTTPReqHandler::HandleUpstreamHTTPProxyConnect, this, std::placeholders::_1)); + })); } } else if (m_ProxyURL.schema == "socks") { /* handle upstream socks proxy */ if (!m_ProxyURL.port) m_ProxyURL.port = 9050; // default to tor default if not specified - boost::asio::ip::tcp::resolver::query q(m_ProxyURL.host, std::to_string(m_ProxyURL.port)); - m_proxy_resolver.async_resolve(q, std::bind(&HTTPReqHandler::HandleUpstreamProxyResolved, this, std::placeholders::_1, std::placeholders::_2, [&](boost::asio::ip::tcp::endpoint ep) { - m_proxysock->async_connect(ep, std::bind(&HTTPReqHandler::HandleUpstreamSocksProxyConnect, this, std::placeholders::_1)); - })); + m_proxy_resolver.async_resolve(m_ProxyURL.host, std::to_string(m_ProxyURL.port), std::bind(&HTTPReqHandler::HandleUpstreamProxyResolved, this, + std::placeholders::_1, std::placeholders::_2, [&](boost::asio::ip::tcp::endpoint ep) + { + m_proxysock->async_connect(ep, std::bind(&HTTPReqHandler::HandleUpstreamSocksProxyConnect, this, std::placeholders::_1)); + })); } else { @@ -606,10 +608,10 @@ namespace proxy { } } - void HTTPReqHandler::HandleUpstreamProxyResolved(const boost::system::error_code & ec, boost::asio::ip::tcp::resolver::iterator it, ProxyResolvedHandler handler) + void HTTPReqHandler::HandleUpstreamProxyResolved(const boost::system::error_code & ec, boost::asio::ip::tcp::resolver::results_type endpoints, ProxyResolvedHandler handler) { if(ec) GenericProxyError(tr("Cannot resolve upstream proxy"), ec.message()); - else handler(*it); + else handler(*endpoints.begin ()); } void HTTPReqHandler::HandleUpstreamSocksProxyConnect(const boost::system::error_code & ec) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 7aec7549..1949746a 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -88,7 +88,7 @@ namespace client void I2CPDestination::CreateNewLeaseSet (const std::vector >& tunnels) { - GetService ().post (std::bind (&I2CPDestination::PostCreateNewLeaseSet, this, tunnels)); + boost::asio::post (GetService (), std::bind (&I2CPDestination::PostCreateNewLeaseSet, this, tunnels)); } void I2CPDestination::PostCreateNewLeaseSet (std::vector > tunnels) @@ -170,7 +170,7 @@ namespace client { // send in destination's thread auto s = GetSharedFromThis (); - GetService ().post ( + boost::asio::post (GetService (), [s, msg, remote, nonce]() { bool sent = s->SendMsg (msg, remote); @@ -1079,7 +1079,7 @@ namespace client I2CPServer::I2CPServer (const std::string& interface, uint16_t port, bool isSingleThread): RunnableService ("I2CP"), m_IsSingleThread (isSingleThread), m_Acceptor (GetIOService (), - boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(interface), port)) + boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(interface), port)) { memset (m_MessagesHandlers, 0, sizeof (m_MessagesHandlers)); m_MessagesHandlers[I2CP_GET_DATE_MESSAGE] = &I2CPSession::GetDateMessageHandler; diff --git a/libi2pd_client/I2PService.h b/libi2pd_client/I2PService.h index adcc3da7..d3ed36fa 100644 --- a/libi2pd_client/I2PService.h +++ b/libi2pd_client/I2PService.h @@ -283,7 +283,7 @@ namespace client public: TCPIPAcceptor (const std::string& address, uint16_t port, std::shared_ptr localDestination = nullptr) : - ServiceAcceptor (boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port), localDestination) {} + ServiceAcceptor (boost::asio::ip::tcp::endpoint (boost::asio::ip::make_address(address), port), localDestination) {} }; } } diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 5ba83e1f..ed0533a7 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -717,7 +717,7 @@ namespace client { m_Endpoint.port (m_Port); boost::system::error_code ec; - auto addr = boost::asio::ip::address::from_string (m_Address, ec); + auto addr = boost::asio::ip::make_address (m_Address, ec); if (!ec) { m_Endpoint.address (addr); @@ -726,7 +726,7 @@ namespace client else { auto resolver = std::make_shared(GetService ()); - resolver->async_resolve (boost::asio::ip::tcp::resolver::query (m_Address, ""), + resolver->async_resolve (m_Address, "", std::bind (&I2PServerTunnel::HandleResolve, this, std::placeholders::_1, std::placeholders::_2, resolver)); } @@ -743,7 +743,7 @@ namespace client ClearHandlers (); } - void I2PServerTunnel::HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, + void I2PServerTunnel::HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::results_type endpoints, std::shared_ptr resolver) { if (!ecode) @@ -752,8 +752,7 @@ namespace client boost::asio::ip::tcp::endpoint ep; if (m_LocalAddress) { - boost::asio::ip::tcp::resolver::iterator end; - while (it != end) + for (auto it = endpoints.begin (); it != endpoints.end ();) { ep = *it; if (!ep.address ().is_unspecified ()) @@ -780,7 +779,7 @@ namespace client else { found = true; - ep = *it; // first available + ep = *endpoints.begin (); // first available } if (!found) { @@ -789,7 +788,7 @@ namespace client } auto addr = ep.address (); - LogPrint (eLogInfo, "I2PTunnel: Server tunnel ", (*it).host_name (), " has been resolved to ", addr); + LogPrint (eLogInfo, "I2PTunnel: Server tunnel ", (*endpoints.begin ()).host_name (), " has been resolved to ", addr); m_Endpoint.address (addr); Accept (); } @@ -806,7 +805,7 @@ namespace client void I2PServerTunnel::SetLocalAddress (const std::string& localAddress) { boost::system::error_code ec; - auto addr = boost::asio::ip::address::from_string(localAddress, ec); + auto addr = boost::asio::ip::make_address(localAddress, ec); if (!ec) m_LocalAddress.reset (new boost::asio::ip::address (addr)); else diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index b94eb9e4..0b01688d 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.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 * @@ -208,7 +208,7 @@ namespace client private: - void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, + void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::results_type endpoints, std::shared_ptr resolver); void Accept (); diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index e4cbae8a..c124be9b 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -371,7 +371,7 @@ namespace client // udp forward selected boost::system::error_code e; // TODO: support hostnames in udp forward - auto addr = boost::asio::ip::address::from_string(params[SAM_PARAM_HOST], e); + auto addr = boost::asio::ip::make_address(params[SAM_PARAM_HOST], e); if (e) { // not an ip address @@ -624,7 +624,7 @@ namespace client auto socket = session->acceptQueue.front ().first; session->acceptQueue.pop_front (); if (socket) - m_Owner.GetService ().post (std::bind(&SAMSocket::TerminateClose, socket)); + boost::asio::post (m_Owner.GetService (), std::bind(&SAMSocket::TerminateClose, socket)); } if (session->acceptQueue.size () < SAM_SESSION_MAX_ACCEPT_QUEUE_SIZE) { @@ -1046,13 +1046,13 @@ namespace client else { auto s = shared_from_this (); - m_Owner.GetService ().post ([s] { s->Terminate ("stream read error"); }); + boost::asio::post (m_Owner.GetService (), [s] { s->Terminate ("stream read error"); }); } } else { auto s = shared_from_this (); - m_Owner.GetService ().post ([s] { s->Terminate ("stream read error (op aborted)"); }); + boost::asio::post (m_Owner.GetService (), [s] { s->Terminate ("stream read error (op aborted)"); }); } } else @@ -1102,7 +1102,7 @@ namespace client auto socket = session->acceptQueue.front ().first; session->acceptQueue.pop_front (); if (socket) - m_Owner.GetService ().post (std::bind(&SAMSocket::TerminateClose, socket)); + boost::asio::post (m_Owner.GetService (), std::bind(&SAMSocket::TerminateClose, socket)); } if (!session->acceptQueue.empty ()) { @@ -1236,7 +1236,7 @@ namespace client void SAMSocket::HandleStreamSend(const boost::system::error_code & ec) { - m_Owner.GetService ().post (std::bind( !ec ? &SAMSocket::Receive : &SAMSocket::TerminateClose, shared_from_this())); + boost::asio::post (m_Owner.GetService (), std::bind( !ec ? &SAMSocket::Receive : &SAMSocket::TerminateClose, shared_from_this())); } SAMSession::SAMSession (SAMBridge & parent, const std::string & id, SAMSessionType type): @@ -1310,8 +1310,8 @@ namespace client SAMBridge::SAMBridge (const std::string& address, uint16_t portTCP, uint16_t portUDP, bool singleThread): RunnableService ("SAM"), m_IsSingleThread (singleThread), - m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), portTCP)), - m_DatagramEndpoint (boost::asio::ip::address::from_string(address), (!portUDP) ? portTCP-1 : portUDP), m_DatagramSocket (GetIOService (), m_DatagramEndpoint), + m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(address), portTCP)), + m_DatagramEndpoint (boost::asio::ip::make_address(address), (!portUDP) ? portTCP-1 : portUDP), m_DatagramSocket (GetIOService (), m_DatagramEndpoint), m_SignatureTypes { {"DSA_SHA1", i2p::data::SIGNING_KEY_TYPE_DSA_SHA1}, diff --git a/libi2pd_client/SOCKS.cpp b/libi2pd_client/SOCKS.cpp index 0961690b..27df33c8 100644 --- a/libi2pd_client/SOCKS.cpp +++ b/libi2pd_client/SOCKS.cpp @@ -126,9 +126,8 @@ namespace proxy void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered); void Terminate(); void AsyncSockRead(); - 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_buffer GenerateSOCKS4Response(errTypes error, uint32_t ip, uint16_t port); + boost::asio::const_buffer GenerateSOCKS5Response(errTypes error, addrTypes type, const address &addr, uint16_t port); bool Socks5ChooseAuth(); void Socks5UserPasswdResponse (); void SocksRequestFailed(errTypes error); @@ -145,9 +144,9 @@ namespace proxy template void SendUpstreamRequest(std::shared_ptr& upstreamSock); void HandleUpstreamConnected(const boost::system::error_code & ecode, - boost::asio::ip::tcp::resolver::iterator itr); + const boost::asio::ip::tcp::endpoint& ep); void HandleUpstreamResolved(const boost::system::error_code & ecode, - boost::asio::ip::tcp::resolver::iterator itr); + boost::asio::ip::tcp::resolver::results_type endpoints); boost::asio::ip::tcp::resolver m_proxy_resolver; uint8_t m_sock_buff[socks_buffer_size]; @@ -233,17 +232,17 @@ namespace proxy Done(shared_from_this()); } - boost::asio::const_buffers_1 SOCKSHandler::GenerateSOCKS4Response(SOCKSHandler::errTypes error, uint32_t ip, uint16_t port) + boost::asio::const_buffer SOCKSHandler::GenerateSOCKS4Response(SOCKSHandler::errTypes error, uint32_t ip, uint16_t port) { assert(error >= SOCKS4_OK); m_response[0] = '\x00'; // version m_response[1] = error; // response code htobe16buf(m_response + 2, port); // port htobe32buf(m_response + 4, ip); // IP - return boost::asio::const_buffers_1(m_response,8); + return boost::asio::const_buffer (m_response,8); } - boost::asio::const_buffers_1 SOCKSHandler::GenerateSOCKS5Response(SOCKSHandler::errTypes error, SOCKSHandler::addrTypes type, const SOCKSHandler::address &addr, uint16_t port) + boost::asio::const_buffer SOCKSHandler::GenerateSOCKS5Response(SOCKSHandler::errTypes error, SOCKSHandler::addrTypes type, const SOCKSHandler::address &addr, uint16_t port) { size_t size = 6; // header + port assert(error <= SOCKS5_ADDR_UNSUP); @@ -280,14 +279,14 @@ namespace proxy } break; } - return boost::asio::const_buffers_1(m_response, size); + return boost::asio::const_buffer (m_response, size); } bool SOCKSHandler::Socks5ChooseAuth() { m_response[0] = '\x05'; // Version m_response[1] = m_authchosen; // Response code - boost::asio::const_buffers_1 response(m_response, 2); + boost::asio::const_buffer response(m_response, 2); if (m_authchosen == AUTH_UNACCEPTABLE) { LogPrint(eLogWarning, "SOCKS: v5 authentication negotiation failed"); @@ -307,14 +306,14 @@ namespace proxy m_response[0] = 1; // Version of the subnegotiation m_response[1] = 0; // Response code LogPrint(eLogDebug, "SOCKS: v5 user/password response"); - boost::asio::async_write(*m_sock, boost::asio::const_buffers_1(m_response, 2), + boost::asio::async_write(*m_sock, boost::asio::const_buffer(m_response, 2), std::bind(&SOCKSHandler::SentSocksResponse, shared_from_this(), std::placeholders::_1)); } /* All hope is lost beyond this point */ void SOCKSHandler::SocksRequestFailed(SOCKSHandler::errTypes error) { - boost::asio::const_buffers_1 response(nullptr,0); + boost::asio::const_buffer response(nullptr,0); assert(error != SOCKS4_OK && error != SOCKS5_OK); switch (m_socksv) { @@ -334,7 +333,7 @@ namespace proxy void SOCKSHandler::SocksRequestSuccess() { - boost::asio::const_buffers_1 response(nullptr,0); + boost::asio::const_buffer response(nullptr,0); // TODO: this should depend on things like the command type and callbacks may change switch (m_socksv) { @@ -691,9 +690,8 @@ namespace proxy 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)); + m_proxy_resolver.async_resolve(m_UpstreamProxyAddress, std::to_string(m_UpstreamProxyPort), + std::bind(&SOCKSHandler::HandleUpstreamResolved, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } else if (!m_UpstreamProxyAddress.empty ())// local { @@ -729,7 +727,7 @@ namespace proxy void SOCKSHandler::SocksUpstreamSuccess(std::shared_ptr& upstreamSock) { LogPrint(eLogInfo, "SOCKS: Upstream success"); - boost::asio::const_buffers_1 response(nullptr, 0); + boost::asio::const_buffer response(nullptr, 0); switch (m_socksv) { case SOCKS4: @@ -775,7 +773,8 @@ namespace proxy 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) + void SOCKSHandler::HandleUpstreamConnected(const boost::system::error_code & ecode, + const boost::asio::ip::tcp::endpoint& ep) { if (ecode) { LogPrint(eLogWarning, "SOCKS: Could not connect to upstream proxy: ", ecode.message()); @@ -786,7 +785,8 @@ namespace proxy SendUpstreamRequest(m_upstreamSock); } - void SOCKSHandler::HandleUpstreamResolved(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr) + void SOCKSHandler::HandleUpstreamResolved(const boost::system::error_code & ecode, + boost::asio::ip::tcp::resolver::results_type endpoints) { if (ecode) { // error resolving @@ -798,7 +798,7 @@ namespace proxy EnterState(UPSTREAM_CONNECT); auto & service = GetOwner()->GetService(); m_upstreamSock = std::make_shared(service); - boost::asio::async_connect(*m_upstreamSock, itr, + boost::asio::async_connect(*m_upstreamSock, endpoints, std::bind(&SOCKSHandler::HandleUpstreamConnected, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } From cc768de8ea4845165075da50ae6251a72b978754 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 25 Nov 2024 19:16:42 -0500 Subject: [PATCH 271/527] iterator through resolver's results --- libi2pd/Reseed.cpp | 10 ++++------ libi2pd/Timestamp.cpp | 5 ++--- libi2pd_client/I2PTunnel.cpp | 5 ++--- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/libi2pd/Reseed.cpp b/libi2pd/Reseed.cpp index 6cf277bf..e58e898b 100644 --- a/libi2pd/Reseed.cpp +++ b/libi2pd/Reseed.cpp @@ -641,9 +641,9 @@ namespace data if (!ecode) { bool connected = false; - for (auto it = endpoints.begin (); it != endpoints.end ();) + for (const auto& it: endpoints) { - boost::asio::ip::tcp::endpoint ep = *it; + boost::asio::ip::tcp::endpoint ep = it; bool supported = false; if (!ep.address ().is_unspecified ()) { @@ -663,7 +663,6 @@ namespace data break; } } - it++; } if (!connected) { @@ -750,9 +749,9 @@ namespace data if (!ecode) { bool connected = false; - for (auto it = endpoints.begin (); it != endpoints.end ();) + for (const auto& it: endpoints) { - boost::asio::ip::tcp::endpoint ep = *it; + boost::asio::ip::tcp::endpoint ep = it; if ( i2p::util::net::IsYggdrasilAddress (ep.address ()) && i2p::context.SupportsMesh () @@ -766,7 +765,6 @@ namespace data break; } } - it++; } if (!connected) { diff --git a/libi2pd/Timestamp.cpp b/libi2pd/Timestamp.cpp index 210ef3b9..a22e9bde 100644 --- a/libi2pd/Timestamp.cpp +++ b/libi2pd/Timestamp.cpp @@ -67,9 +67,9 @@ namespace util { bool found = false; boost::asio::ip::udp::endpoint ep; - for (auto it = endpoints.begin (); it != endpoints.end ();) + for (const auto& it: endpoints) { - ep = *it; + ep = it; if (!ep.address ().is_unspecified ()) { if (ep.address ().is_v4 ()) @@ -86,7 +86,6 @@ namespace util } } if (found) break; - it++; } if (!found) { diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index ed0533a7..bbe09508 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -752,9 +752,9 @@ namespace client boost::asio::ip::tcp::endpoint ep; if (m_LocalAddress) { - for (auto it = endpoints.begin (); it != endpoints.end ();) + for (const auto& it: endpoints) { - ep = *it; + ep = it; if (!ep.address ().is_unspecified ()) { if (ep.address ().is_v4 ()) @@ -773,7 +773,6 @@ namespace client } } if (found) break; - it++; } } else From 8b9f427aa4882690662feea3e66f4a808bb36ac3 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 27 Nov 2024 18:31:58 -0500 Subject: [PATCH 272/527] handle session handshakes in separate thread --- libi2pd/NTCP2.cpp | 149 ++++++++++++++++++++++++++++------------------ libi2pd/NTCP2.h | 20 ++++++- 2 files changed, 109 insertions(+), 60 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 38efc825..ca5e9260 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -491,7 +491,6 @@ namespace transport void NTCP2Session::HandleSessionRequestReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - (void) bytes_transferred; if (ecode) { LogPrint (eLogWarning, "NTCP2: SessionRequest read error: ", ecode.message ()); @@ -499,38 +498,47 @@ namespace transport } else { - LogPrint (eLogDebug, "NTCP2: SessionRequest received ", bytes_transferred); - uint16_t paddingLen = 0; - bool clockSkew = false; - if (m_Establisher->ProcessSessionRequestMessage (paddingLen, clockSkew)) - { - if (clockSkew) + boost::asio::post (m_Server.GetEstablisherService (), + [s = shared_from_this (), bytes_transferred] () { - // we don't care about padding, send SessionCreated and close session - SendSessionCreated (); - boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); - } - else if (paddingLen > 0) - { - if (paddingLen <= NTCP2_SESSION_REQUEST_MAX_SIZE - 64) // session request is 287 bytes max - { - boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (), - std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); - } - else - { - LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long"); - Terminate (); - } - } - else - SendSessionCreated (); - } - else - Terminate (); + s->ProcessSessionRequest (bytes_transferred);; + }); } } + void NTCP2Session::ProcessSessionRequest (size_t len) + { + LogPrint (eLogDebug, "NTCP2: SessionRequest received ", len); + uint16_t paddingLen = 0; + bool clockSkew = false; + if (m_Establisher->ProcessSessionRequestMessage (paddingLen, clockSkew)) + { + if (clockSkew) + { + // we don't care about padding, send SessionCreated and close session + SendSessionCreated (); + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + } + else if (paddingLen > 0) + { + if (paddingLen <= NTCP2_SESSION_REQUEST_MAX_SIZE - 64) // session request is 287 bytes max + { + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long"); + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + } + } + else + SendSessionCreated (); + } + else + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + } + void NTCP2Session::HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (ecode) @@ -539,7 +547,13 @@ namespace transport Terminate (); } else - SendSessionCreated (); + { + boost::asio::post (m_Server.GetEstablisherService (), + [s = shared_from_this ()] () + { + s->SendSessionCreated (); + }); + } } void NTCP2Session::SendSessionCreated () @@ -561,35 +575,44 @@ namespace transport else { m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval; - LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred); - uint16_t paddingLen = 0; - if (m_Establisher->ProcessSessionCreatedMessage (paddingLen)) - { - if (paddingLen > 0) + boost::asio::post (m_Server.GetEstablisherService (), + [s = shared_from_this (), bytes_transferred] () { - if (paddingLen <= NTCP2_SESSION_CREATED_MAX_SIZE - 64) // session created is 287 bytes max - { - boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (), - std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); - } - else - { - LogPrint (eLogWarning, "NTCP2: SessionCreated padding length ", (int)paddingLen, " is too long"); - Terminate (); - } - } - else - SendSessionConfirmed (); - } - else - { - if (GetRemoteIdentity ()) - i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); // assume wrong s key - Terminate (); - } + s->ProcessSessionCreated (bytes_transferred); + }); } } + void NTCP2Session::ProcessSessionCreated (size_t len) + { + LogPrint (eLogDebug, "NTCP2: SessionCreated received ", len); + uint16_t paddingLen = 0; + if (m_Establisher->ProcessSessionCreatedMessage (paddingLen)) + { + if (paddingLen > 0) + { + if (paddingLen <= NTCP2_SESSION_CREATED_MAX_SIZE - 64) // session created is 287 bytes max + { + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionCreated padding length ", (int)paddingLen, " is too long"); + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + } + } + else + SendSessionConfirmed (); + } + else + { + if (GetRemoteIdentity ()) + i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); // assume wrong s key + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + } + } + void NTCP2Session::HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (ecode) @@ -600,7 +623,11 @@ namespace transport else { m_Establisher->m_SessionCreatedBufferLen += bytes_transferred; - SendSessionConfirmed (); + boost::asio::post (m_Server.GetEstablisherService (), + [s = shared_from_this ()] () + { + s->SendSessionConfirmed (); + }); } } @@ -679,7 +706,7 @@ namespace transport // part 2 std::vector buf(m_Establisher->m3p2Len - 16); // -MAC memset (nonce, 0, 12); // set nonce to 0 again - if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf.data ())) + if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf.data ())) // TODO:handle in establisher thread { KeyDerivationFunctionDataPhase (); // Bob data phase keys @@ -811,7 +838,11 @@ namespace transport void NTCP2Session::ClientLogin () { m_Establisher->CreateEphemeralKey (); - SendSessionRequest (); + boost::asio::post (m_Server.GetEstablisherService (), + [s = shared_from_this ()] () + { + s->SendSessionRequest (); + }); } void NTCP2Session::ServerLogin () @@ -1367,6 +1398,7 @@ namespace transport void NTCP2Server::Start () { + m_EstablisherService.Start (); if (!IsRunning ()) { StartIOService (); @@ -1476,6 +1508,7 @@ namespace transport m_TerminationTimer.cancel (); m_ProxyEndpoint = nullptr; } + m_EstablisherService.Stop (); StopIOService (); } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index e1718bb0..7f5c97aa 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -172,9 +172,11 @@ namespace transport void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionRequestReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void ProcessSessionRequest (size_t len); void HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void ProcessSessionCreated (size_t len); void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); @@ -239,6 +241,18 @@ namespace transport class NTCP2Server: private i2p::util::RunnableServiceWithWork { + private: + + class EstablisherService: public i2p::util::RunnableServiceWithWork + { + public: + + EstablisherService (): RunnableServiceWithWork ("NTCP2e") {}; + auto& GetService () { return GetIOService (); }; + void Start () { StartIOService (); }; + void Stop () { StopIOService (); }; + }; + public: enum ProxyType @@ -247,13 +261,14 @@ namespace transport eSocksProxy, eHTTPProxy }; - + NTCP2Server (); ~NTCP2Server (); void Start (); void Stop (); auto& GetService () { return GetIOService (); }; + auto& GetEstablisherService () { return m_EstablisherService.GetService (); }; std::mt19937& GetRng () { return m_Rng; }; bool AddNTCP2Session (std::shared_ptr session, bool incoming = false); @@ -294,7 +309,8 @@ namespace transport std::unique_ptr m_ProxyEndpoint; std::shared_ptr m_Address4, m_Address6, m_YggdrasilAddress; std::mt19937 m_Rng; - + EstablisherService m_EstablisherService; + public: // for HTTP/I2PControl From 56145d0f3c80270fe3c7a6cdf094f7b8dbbf5ae4 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 28 Nov 2024 21:56:26 -0500 Subject: [PATCH 273/527] bind tunnel gateway to transport session --- libi2pd/Transports.cpp | 40 ++++++++++++++++++++++----------------- libi2pd/Transports.h | 9 +++++---- libi2pd/TunnelGateway.cpp | 32 ++++++++++++++++++++++++++++++- libi2pd/TunnelGateway.h | 6 +++++- 4 files changed, 64 insertions(+), 23 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index e2f8c730..03416137 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -447,28 +447,29 @@ namespace transport return std::max (bwCongestionLevel, tbwCongestionLevel); } - void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg) + std::future > Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg) { if (m_IsOnline) - SendMessages (ident, { msg }); + return SendMessages (ident, { msg }); + return {}; // invalid future } - void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list >& msgs) + std::future > Transports::SendMessages (const i2p::data::IdentHash& ident, std::list >& msgs) { std::list > msgs1; msgs.swap (msgs1); - SendMessages (ident, std::move (msgs1)); + return SendMessages (ident, std::move (msgs1)); } - void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list >&& msgs) + std::future > Transports::SendMessages (const i2p::data::IdentHash& ident, std::list >&& msgs) { - boost::asio::post (*m_Service, [this, ident, msgs = std::move(msgs)] () mutable + return boost::asio::post (*m_Service, boost::asio::use_future ([this, ident, msgs = std::move(msgs)] () mutable { - PostMessages (ident, msgs); - }); + return PostMessages (ident, msgs); + })); } - void Transports::PostMessages (const i2p::data::IdentHash& ident, std::list >& msgs) + std::shared_ptr Transports::PostMessages (const i2p::data::IdentHash& ident, std::list >& msgs) { if (ident == i2p::context.GetRouterInfo ().GetIdentHash ()) { @@ -476,9 +477,9 @@ namespace transport for (auto& it: msgs) m_LoopbackHandler.PutNextMessage (std::move (it)); m_LoopbackHandler.Flush (); - return; + return nullptr; } - if(RoutesRestricted() && !IsRestrictedPeer(ident)) return; + if(RoutesRestricted() && !IsRestrictedPeer(ident)) return nullptr; std::shared_ptr peer; { std::lock_guard l(m_PeersMutex); @@ -489,13 +490,13 @@ namespace transport if (!peer) { // check if not banned - if (i2p::data::IsRouterBanned (ident)) return; // don't create peer to unreachable router + if (i2p::data::IsRouterBanned (ident)) return nullptr; // don't create peer to unreachable router // try to connect bool connected = false; try { auto r = netdb.FindRouter (ident); - if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return; // router found but non-reachable + if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return nullptr; // router found but non-reachable peer = std::make_shared(r, i2p::util::GetSecondsSinceEpoch ()); { @@ -509,12 +510,16 @@ namespace transport { LogPrint (eLogError, "Transports: PostMessages exception:", ex.what ()); } - if (!connected) return; + if (!connected) return nullptr; } - if (!peer) return; + if (!peer) return nullptr; if (peer->IsConnected ()) - peer->sessions.front ()->SendI2NPMessages (msgs); + { + auto session = peer->sessions.front (); + if (session) session->SendI2NPMessages (msgs); + return session; + } else { auto sz = peer->delayedMessages.size (); @@ -527,7 +532,7 @@ namespace transport LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped"); std::lock_guard l(m_PeersMutex); m_Peers.erase (ident); - return; + return nullptr; } } if (sz > MAX_NUM_DELAYED_MESSAGES/2) @@ -549,6 +554,7 @@ namespace transport m_Peers.erase (ident); } } + return nullptr; } bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr peer) diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 5829b9f3..b72d5b70 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -143,9 +144,9 @@ namespace transport std::shared_ptr GetNextX25519KeysPair (); void ReuseX25519KeysPair (std::shared_ptr pair); - void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg); - void SendMessages (const i2p::data::IdentHash& ident, std::list >& msgs); - void SendMessages (const i2p::data::IdentHash& ident, std::list >&& msgs); + std::future > SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg); + std::future > SendMessages (const i2p::data::IdentHash& ident, std::list >& msgs); + std::future > SendMessages (const i2p::data::IdentHash& ident, std::list >&& msgs); void PeerConnected (std::shared_ptr session); void PeerDisconnected (std::shared_ptr session); @@ -189,7 +190,7 @@ namespace transport void Run (); void RequestComplete (std::shared_ptr r, const i2p::data::IdentHash& ident); void HandleRequestComplete (std::shared_ptr r, i2p::data::IdentHash ident); - void PostMessages (const i2p::data::IdentHash& ident, std::list >& msgs); + std::shared_ptr PostMessages (const i2p::data::IdentHash& ident, std::list >& msgs); bool ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr peer); void SetPriority (std::shared_ptr peer) const; void HandlePeerCleanupTimer (const boost::system::error_code& ecode); diff --git a/libi2pd/TunnelGateway.cpp b/libi2pd/TunnelGateway.cpp index 78a63fc4..4b9e037a 100644 --- a/libi2pd/TunnelGateway.cpp +++ b/libi2pd/TunnelGateway.cpp @@ -220,6 +220,7 @@ namespace tunnel void TunnelGateway::SendBuffer () { + // create list or tunnel messages m_Buffer.CompleteCurrentTunnelDataMessage (); std::list > newTunnelMsgs; const auto& tunnelDataMsgs = m_Buffer.GetTunnelDataMsgs (); @@ -234,7 +235,36 @@ namespace tunnel m_NumSentBytes += TUNNEL_DATA_MSG_SIZE; } m_Buffer.ClearTunnelDataMsgs (); - i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), std::move (newTunnelMsgs)); + + // send + if (m_CurrentTransport && !m_CurrentTransport->IsEstablished ()) // check if session became invalid since last call + m_CurrentTransport = nullptr; + if (!m_CurrentTransport) + { + // try to obtain transport from peding reequest or send thought transport is not complete + if (m_PendingTransport.valid ()) // pending request? + { + if (m_PendingTransport.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + { + // pending request complete + m_CurrentTransport = m_PendingTransport.get (); // take tarnsports used in pending request + if (m_CurrentTransport && !m_CurrentTransport->IsEstablished ()) + m_CurrentTransport = nullptr; + } + else // still pending + { + // send through transports, but don't update pedning transport + i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), std::move (newTunnelMsgs)); + return; + } + } + } + if (m_CurrentTransport) // session is good + // send to session directly + m_CurrentTransport->SendI2NPMessages (newTunnelMsgs); + else // no session yet + // send through transports + m_PendingTransport = i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), std::move (newTunnelMsgs)); } } } diff --git a/libi2pd/TunnelGateway.h b/libi2pd/TunnelGateway.h index 741bbe84..ba36ac73 100644 --- a/libi2pd/TunnelGateway.h +++ b/libi2pd/TunnelGateway.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 * @@ -12,7 +12,9 @@ #include #include #include +#include #include "I2NPProtocol.h" +#include "TransportSession.h" #include "TunnelBase.h" namespace i2p @@ -57,6 +59,8 @@ namespace tunnel TunnelBase * m_Tunnel; TunnelGatewayBuffer m_Buffer; size_t m_NumSentBytes; + std::shared_ptr m_CurrentTransport; + std::future > m_PendingTransport; }; } } From fcc70025fda78e4ce15cc4985d5109bf489d3efa Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 29 Nov 2024 11:31:13 -0500 Subject: [PATCH 274/527] use reference instead naked pointer to tunnel in tunnel gateway --- libi2pd/TransitTunnel.h | 2 +- libi2pd/Tunnel.h | 2 +- libi2pd/TunnelGateway.cpp | 8 ++++---- libi2pd/TunnelGateway.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index c4a6e156..14f9b997 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.h @@ -73,7 +73,7 @@ namespace tunnel const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID, const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey): TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, - layerKey, ivKey), m_Gateway(this) {}; + layerKey, ivKey), m_Gateway(*this) {}; void SendTunnelDataMsg (std::shared_ptr msg) override; void FlushTunnelDataMsgs () override; diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 2d0641e3..e11a360d 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -139,7 +139,7 @@ namespace tunnel public: OutboundTunnel (std::shared_ptr config): - Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {}; + Tunnel (config), m_Gateway (*this), m_EndpointIdentHash (config->GetLastIdentHash ()) {}; void SendTunnelDataMsgTo (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr msg); virtual void SendTunnelDataMsgs (const std::vector& msgs); // multiple messages diff --git a/libi2pd/TunnelGateway.cpp b/libi2pd/TunnelGateway.cpp index 4b9e037a..73ca02b8 100644 --- a/libi2pd/TunnelGateway.cpp +++ b/libi2pd/TunnelGateway.cpp @@ -227,8 +227,8 @@ namespace tunnel for (auto& tunnelMsg : tunnelDataMsgs) { auto newMsg = CreateEmptyTunnelDataMsg (false); - m_Tunnel->EncryptTunnelMsg (tunnelMsg, newMsg); - htobe32buf (newMsg->GetPayload (), m_Tunnel->GetNextTunnelID ()); + m_Tunnel.EncryptTunnelMsg (tunnelMsg, newMsg); + htobe32buf (newMsg->GetPayload (), m_Tunnel.GetNextTunnelID ()); newMsg->FillI2NPMessageHeader (eI2NPTunnelData); if (tunnelMsg->onDrop) newMsg->onDrop = tunnelMsg->onDrop; newTunnelMsgs.push_back (newMsg); @@ -254,7 +254,7 @@ namespace tunnel else // still pending { // send through transports, but don't update pedning transport - i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), std::move (newTunnelMsgs)); + i2p::transport::transports.SendMessages (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs)); return; } } @@ -264,7 +264,7 @@ namespace tunnel m_CurrentTransport->SendI2NPMessages (newTunnelMsgs); else // no session yet // send through transports - m_PendingTransport = i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), std::move (newTunnelMsgs)); + m_PendingTransport = i2p::transport::transports.SendMessages (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs)); } } } diff --git a/libi2pd/TunnelGateway.h b/libi2pd/TunnelGateway.h index ba36ac73..cd70b4d8 100644 --- a/libi2pd/TunnelGateway.h +++ b/libi2pd/TunnelGateway.h @@ -47,7 +47,7 @@ namespace tunnel { public: - TunnelGateway (TunnelBase * tunnel): + TunnelGateway (TunnelBase& tunnel): m_Tunnel (tunnel), m_NumSentBytes (0) {}; void SendTunnelDataMsg (const TunnelMessageBlock& block); void PutTunnelDataMsg (const TunnelMessageBlock& block); @@ -56,7 +56,7 @@ namespace tunnel private: - TunnelBase * m_Tunnel; + TunnelBase& m_Tunnel; TunnelGatewayBuffer m_Buffer; size_t m_NumSentBytes; std::shared_ptr m_CurrentTransport; From 31ff0ff1cba2a40a4634d00bd49d96b810c8607c Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 29 Nov 2024 21:29:03 -0500 Subject: [PATCH 275/527] use weak_ptr for transport session --- libi2pd/TunnelGateway.cpp | 20 ++++++++++++-------- libi2pd/TunnelGateway.h | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libi2pd/TunnelGateway.cpp b/libi2pd/TunnelGateway.cpp index 73ca02b8..fabc71bb 100644 --- a/libi2pd/TunnelGateway.cpp +++ b/libi2pd/TunnelGateway.cpp @@ -237,9 +237,8 @@ namespace tunnel m_Buffer.ClearTunnelDataMsgs (); // send - if (m_CurrentTransport && !m_CurrentTransport->IsEstablished ()) // check if session became invalid since last call - m_CurrentTransport = nullptr; - if (!m_CurrentTransport) + auto currentTransport = m_CurrentTransport.lock (); + if (!currentTransport) { // try to obtain transport from peding reequest or send thought transport is not complete if (m_PendingTransport.valid ()) // pending request? @@ -247,9 +246,14 @@ namespace tunnel if (m_PendingTransport.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { // pending request complete - m_CurrentTransport = m_PendingTransport.get (); // take tarnsports used in pending request - if (m_CurrentTransport && !m_CurrentTransport->IsEstablished ()) - m_CurrentTransport = nullptr; + currentTransport = m_PendingTransport.get (); // take tarnsports used in pending request + if (currentTransport) + { + if (currentTransport->IsEstablished ()) + m_CurrentTransport = currentTransport; + else + currentTransport = nullptr; + } } else // still pending { @@ -259,9 +263,9 @@ namespace tunnel } } } - if (m_CurrentTransport) // session is good + if (currentTransport) // session is good // send to session directly - m_CurrentTransport->SendI2NPMessages (newTunnelMsgs); + currentTransport->SendI2NPMessages (newTunnelMsgs); else // no session yet // send through transports m_PendingTransport = i2p::transport::transports.SendMessages (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs)); diff --git a/libi2pd/TunnelGateway.h b/libi2pd/TunnelGateway.h index cd70b4d8..4cfd5308 100644 --- a/libi2pd/TunnelGateway.h +++ b/libi2pd/TunnelGateway.h @@ -59,7 +59,7 @@ namespace tunnel TunnelBase& m_Tunnel; TunnelGatewayBuffer m_Buffer; size_t m_NumSentBytes; - std::shared_ptr m_CurrentTransport; + std::weak_ptr m_CurrentTransport; std::future > m_PendingTransport; }; } From 7b0ff2850cf0b54953652cdb6b77ff9eb51bf18f Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 1 Dec 2024 16:53:08 -0500 Subject: [PATCH 276/527] close session if x25519 fails --- libi2pd/NTCP2.cpp | 92 +++++++++++++++++++++++++++++++---------------- libi2pd/NTCP2.h | 22 ++++++------ 2 files changed, 73 insertions(+), 41 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index ca5e9260..8b10a7d5 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -42,28 +42,29 @@ namespace transport delete[] m_SessionConfirmedBuffer; } - void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub) + bool NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub) { i2p::crypto::InitNoiseXKState (*this, rs); // h = SHA256(h || epub) MixHash (epub, 32); // x25519 between pub and priv uint8_t inputKeyMaterial[32]; - priv.Agree (pub, inputKeyMaterial); + if (!priv.Agree (pub, inputKeyMaterial)) return false; MixKey (inputKeyMaterial); + return true; } - void NTCP2Establisher::KDF1Alice () + bool NTCP2Establisher::KDF1Alice () { - KeyDerivationFunction1 (m_RemoteStaticKey, *m_EphemeralKeys, m_RemoteStaticKey, GetPub ()); + return KeyDerivationFunction1 (m_RemoteStaticKey, *m_EphemeralKeys, m_RemoteStaticKey, GetPub ()); } - void NTCP2Establisher::KDF1Bob () + bool NTCP2Establisher::KDF1Bob () { - KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ()); + return KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ()); } - void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub) + bool NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub) { MixHash (sessionRequest + 32, 32); // encrypted payload @@ -74,33 +75,35 @@ namespace transport // x25519 between remote pub and ephemaral priv uint8_t inputKeyMaterial[32]; - m_EphemeralKeys->Agree (GetRemotePub (), inputKeyMaterial); - + if (!m_EphemeralKeys->Agree (GetRemotePub (), inputKeyMaterial)) return false; MixKey (inputKeyMaterial); + return true; } - void NTCP2Establisher::KDF2Alice () + bool NTCP2Establisher::KDF2Alice () { - KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetRemotePub ()); + return KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetRemotePub ()); } - void NTCP2Establisher::KDF2Bob () + bool NTCP2Establisher::KDF2Bob () { - KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetPub ()); + return KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetPub ()); } - void NTCP2Establisher::KDF3Alice () + bool NTCP2Establisher::KDF3Alice () { uint8_t inputKeyMaterial[32]; - i2p::context.GetNTCP2StaticKeys ().Agree (GetRemotePub (), inputKeyMaterial); + if (!i2p::context.GetNTCP2StaticKeys ().Agree (GetRemotePub (), inputKeyMaterial)) return false; MixKey (inputKeyMaterial); + return true; } - void NTCP2Establisher::KDF3Bob () + bool NTCP2Establisher::KDF3Bob () { uint8_t inputKeyMaterial[32]; - m_EphemeralKeys->Agree (m_RemoteStaticKey, inputKeyMaterial); + if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, inputKeyMaterial)) return false; MixKey (inputKeyMaterial); + return true; } void NTCP2Establisher::CreateEphemeralKey () @@ -108,7 +111,7 @@ namespace transport m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); } - void NTCP2Establisher::CreateSessionRequestMessage (std::mt19937& rng) + bool NTCP2Establisher::CreateSessionRequestMessage (std::mt19937& rng) { // create buffer and fill padding auto paddingLength = rng () % (NTCP2_SESSION_REQUEST_MAX_SIZE - 64); // message length doesn't exceed 287 bytes @@ -121,7 +124,7 @@ namespace transport encryption.Encrypt (GetPub (), 32, m_SessionRequestBuffer); // X encryption.GetIV (m_IV); // save IV for SessionCreated // encryption key for next block - KDF1Alice (); + if (!KDF1Alice ()) return false; // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); @@ -147,9 +150,10 @@ namespace transport uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt + return true; } - void NTCP2Establisher::CreateSessionCreatedMessage (std::mt19937& rng) + bool NTCP2Establisher::CreateSessionCreatedMessage (std::mt19937& rng) { auto paddingLen = rng () % (NTCP2_SESSION_CREATED_MAX_SIZE - 64); m_SessionCreatedBufferLen = paddingLen + 64; @@ -160,7 +164,7 @@ namespace transport encryption.SetIV (m_IV); encryption.Encrypt (GetPub (), 32, m_SessionCreatedBuffer); // Y // encryption key for next block (m_K) - KDF2Bob (); + if (!KDF2Bob ()) return false; uint8_t options[16]; memset (options, 0, 16); htobe16buf (options + 2, paddingLen); // padLen @@ -169,7 +173,7 @@ namespace transport uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt - + return true; } void NTCP2Establisher::CreateSessionConfirmedMessagePart1 (const uint8_t * nonce) @@ -184,17 +188,18 @@ namespace transport i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, GetH (), 32, GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt } - void NTCP2Establisher::CreateSessionConfirmedMessagePart2 (const uint8_t * nonce) + bool NTCP2Establisher::CreateSessionConfirmedMessagePart2 (const uint8_t * nonce) { // part 2 // update AD again MixHash (m_SessionConfirmedBuffer, 48); // encrypt m3p2, it must be filled in SessionRequest - KDF3Alice (); + if (!KDF3Alice ()) return false; uint8_t * m3p2 = m_SessionConfirmedBuffer + 48; i2p::crypto::AEADChaCha20Poly1305 (m3p2, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2, m3p2Len, true); // encrypt // update h again MixHash (m3p2, m3p2Len); //h = SHA256(h || ciphertext) + return true; } bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew) @@ -207,7 +212,11 @@ namespace transport decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ()); decryption.GetIV (m_IV); // save IV for SessionCreated // decryption key for next block - KDF1Bob (); + if (!KDF1Bob ()) + { + LogPrint (eLogWarning, "NTCP2: SessionRequest KDF failed"); + return false; + } // verify MAC and decrypt options block (32 bytes), use m_H as AD uint8_t nonce[12], options[16]; memset (nonce, 0, 12); // set nonce to zero @@ -262,7 +271,11 @@ namespace transport decryption.SetIV (m_IV); decryption.Decrypt (m_SessionCreatedBuffer, 32, GetRemotePub ()); // decryption key for next block (m_K) - KDF2Alice (); + if (!KDF2Alice ()) + { + LogPrint (eLogWarning, "NTCP2: SessionCreated KDF failed"); + return false; + } // decrypt and verify MAC uint8_t payload[16]; uint8_t nonce[12]; @@ -309,7 +322,11 @@ namespace transport // update AD again MixHash (m_SessionConfirmedBuffer, 48); - KDF3Bob (); + if (!KDF3Bob ()) + { + LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 KDF failed"); + return false; + } if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt // calculate new h again for KDF data MixHash (m_SessionConfirmedBuffer + 48, m3p2Len); // h = SHA256(h || ciphertext) @@ -466,7 +483,12 @@ namespace transport void NTCP2Session::SendSessionRequest () { - m_Establisher->CreateSessionRequestMessage (m_Server.GetRng ()); + if (!m_Establisher->CreateSessionRequestMessage (m_Server.GetRng ())) + { + LogPrint (eLogWarning, "NTCP2: Send SessionRequest KDF failed"); + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + return; + } // send message m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch (); boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (), @@ -558,7 +580,12 @@ namespace transport void NTCP2Session::SendSessionCreated () { - m_Establisher->CreateSessionCreatedMessage (m_Server.GetRng ()); + if (!m_Establisher->CreateSessionCreatedMessage (m_Server.GetRng ())) + { + LogPrint (eLogWarning, "NTCP2: Send SessionCreated KDF failed"); + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + return; + } // send message m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch (); boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (), @@ -637,7 +664,12 @@ namespace transport CreateNonce (1, nonce); // set nonce to 1 m_Establisher->CreateSessionConfirmedMessagePart1 (nonce); memset (nonce, 0, 12); // set nonce back to 0 - m_Establisher->CreateSessionConfirmedMessagePart2 (nonce); + if (!m_Establisher->CreateSessionConfirmedMessagePart2 (nonce)) + { + LogPrint (eLogWarning, "NTCP2: Send SessionConfirmed Part2 KDF failed"); + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + return; + } // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 7f5c97aa..f0cee06a 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -95,21 +95,21 @@ namespace transport const uint8_t * GetCK () const { return m_CK; }; const uint8_t * GetH () const { return m_H; }; - void KDF1Alice (); - void KDF1Bob (); - void KDF2Alice (); - void KDF2Bob (); - void KDF3Alice (); // for SessionConfirmed part 2 - void KDF3Bob (); + bool KDF1Alice (); + bool KDF1Bob (); + bool KDF2Alice (); + bool KDF2Bob (); + bool KDF3Alice (); // for SessionConfirmed part 2 + bool KDF3Bob (); - void KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH - void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate + bool KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH + bool KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate void CreateEphemeralKey (); - void CreateSessionRequestMessage (std::mt19937& rng); - void CreateSessionCreatedMessage (std::mt19937& rng); + bool CreateSessionRequestMessage (std::mt19937& rng); + bool CreateSessionCreatedMessage (std::mt19937& rng); void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce); - void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce); + bool CreateSessionConfirmedMessagePart2 (const uint8_t * nonce); bool ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew); bool ProcessSessionCreatedMessage (uint16_t& paddingLen); From b17bbd754a6662c2ba0fa7b4dc4744d7a1bd16ae Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 3 Dec 2024 00:40:30 +0300 Subject: [PATCH 277/527] [gha] winxp: forced overwrite files from boost package --- .github/workflows/build-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index d587ba05..38449bf7 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -231,7 +231,7 @@ jobs: cd MINGW-packages/mingw-w64-boost MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck - name: Install boost package - run: pacman --noconfirm -U MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst + run: pacman --noconfirm --overwrite -U MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst # Building i2pd - name: Build application From 1a32ed908889364d1d5ad39893e588358cc6df12 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 3 Dec 2024 00:44:14 +0300 Subject: [PATCH 278/527] [gha] winxp: fix option order --- .github/workflows/build-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 38449bf7..ed7147ff 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -231,7 +231,7 @@ jobs: cd MINGW-packages/mingw-w64-boost MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck - name: Install boost package - run: pacman --noconfirm --overwrite -U MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst + run: pacman --noconfirm -U --overwrite MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst # Building i2pd - name: Build application From e518b92a891743179417e92e057eb5a779045e08 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 2 Dec 2024 19:05:12 -0500 Subject: [PATCH 279/527] calculate X_I2P_DEST* headers once for series of HTTP requests --- libi2pd_client/I2PTunnel.cpp | 31 ++++++++++++++++++------------- libi2pd_client/I2PTunnel.h | 14 +++++++------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index bbe09508..3a3c491e 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -375,10 +375,10 @@ namespace client } I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr stream, - const boost::asio::ip::tcp::endpoint& target, const std::string& host, + const boost::asio::ip::tcp::endpoint& target, const std::string& host, const std::string& XI2P, std::shared_ptr sslCtx): - I2PTunnelConnection (owner, stream, target, true, sslCtx), m_Host (host), - m_HeaderSent (false), m_ResponseHeaderSent (false), m_From (stream->GetRemoteIdentity ()) + I2PTunnelConnection (owner, stream, target, true, sslCtx), m_Host (host), m_XI2P (XI2P), + m_HeaderSent (false), m_ResponseHeaderSent (false) { if (sslCtx) SSL_set_tlsext_host_name(GetSSL ()->native_handle(), host.c_str ()); @@ -448,17 +448,12 @@ namespace client if (!connection) m_OutHeader << "Connection: close\r\n"; // add X-I2P fields - if (m_From) - { - m_OutHeader << X_I2P_DEST_B32 << ": " << context.GetAddressBook ().ToAddress(m_From->GetIdentHash ()) << "\r\n"; - m_OutHeader << X_I2P_DEST_HASH << ": " << m_From->GetIdentHash ().ToBase64 () << "\r\n"; - m_OutHeader << X_I2P_DEST_B64 << ": " << m_From->ToBase64 () << "\r\n"; - } - - m_OutHeader << "\r\n"; // end of header + m_OutHeader << m_XI2P; + // end of header + m_OutHeader << "\r\n"; + m_OutHeader << m_InHeader.str ().substr (m_InHeader.tellg ()); // data right after header m_InHeader.str (""); - m_From = nullptr; m_HeaderSent = true; I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ()); } @@ -876,7 +871,17 @@ namespace client std::shared_ptr I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr stream) { - return std::make_shared (this, stream, GetEndpoint (), m_Host, GetSSLCtx ()); + if (m_XI2P.empty () || stream->GetRemoteIdentity () != m_From.lock ()) + { + auto from = stream->GetRemoteIdentity (); + m_From = from; + std::stringstream ss; + ss << X_I2P_DEST_B32 << ": " << context.GetAddressBook ().ToAddress(from->GetIdentHash ()) << "\r\n"; + ss << X_I2P_DEST_HASH << ": " << from->GetIdentHash ().ToBase64 () << "\r\n"; + ss << X_I2P_DEST_B64 << ": " << from->ToBase64 () << "\r\n"; + m_XI2P = ss.str (); + } + return std::make_shared (this, stream, GetEndpoint (), m_Host, m_XI2P, GetSSLCtx ()); } I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address, diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index 0b01688d..aa53f0b6 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -31,9 +31,9 @@ namespace client const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds // for HTTP tunnels - const char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64 - const char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64 - const char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // .b32.i2p address + constexpr char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64 + constexpr char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64 + constexpr char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // .b32.i2p address const int I2P_TUNNEL_HTTP_MAX_HEADER_SIZE = 8192; class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this @@ -107,7 +107,7 @@ namespace client public: I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr stream, - const boost::asio::ip::tcp::endpoint& target, const std::string& host, + const boost::asio::ip::tcp::endpoint& target, const std::string& host, const std::string& XI2P, std::shared_ptr sslCtx = nullptr); protected: @@ -117,10 +117,9 @@ namespace client private: - std::string m_Host; + std::string m_Host, m_XI2P; std::stringstream m_InHeader, m_OutHeader; bool m_HeaderSent, m_ResponseHeaderSent; - std::shared_ptr m_From; }; class I2PTunnelConnectionIRC: public I2PTunnelConnection @@ -242,7 +241,8 @@ namespace client private: - std::string m_Host; + std::string m_Host, m_XI2P; + std::weak_ptr m_From; }; class I2PServerTunnelIRC: public I2PServerTunnel From f79a2e81ffede33d7c7fc70e85634568dbf31d94 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Dec 2024 18:36:57 -0500 Subject: [PATCH 280/527] calculate data phase keys after verification --- libi2pd/NTCP2.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 8b10a7d5..cfc24e08 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -740,15 +740,8 @@ namespace transport memset (nonce, 0, 12); // set nonce to 0 again if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf.data ())) // TODO:handle in establisher thread { - KeyDerivationFunctionDataPhase (); - // Bob data phase keys - m_SendKey = m_Kba; - m_ReceiveKey = m_Kab; - SetSipKeys (m_Sipkeysba, m_Sipkeysab); - memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8); - memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8); - // payload - // process RI + // payload + // RI block must be first if (buf[0] != eNTCP2BlkRouterInfo) { LogPrint (eLogWarning, "NTCP2: Unexpected block ", (int)buf[0], " in SessionConfirmed"); @@ -825,12 +818,20 @@ namespace transport SendTerminationAndTerminate (eNTCP2Banned); return; } - // TODO: process options + // TODO: process options block // ready to communicate SetRemoteIdentity (ri1->GetRouterIdentity ()); if (m_Server.AddNTCP2Session (shared_from_this (), true)) { + KeyDerivationFunctionDataPhase (); + // Bob data phase keys + m_SendKey = m_Kba; + m_ReceiveKey = m_Kab; + SetSipKeys (m_Sipkeysba, m_Sipkeysab); + memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8); + memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8); + Established (); ReceiveLength (); } From e996db03c05eb83ff3814964a659a7775dd3cf82 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Dec 2024 20:57:40 -0500 Subject: [PATCH 281/527] process SessionConfirmed in establisher's thread --- libi2pd/NTCP2.cpp | 248 +++++++++++++++++++++++++--------------------- libi2pd/NTCP2.h | 4 +- 2 files changed, 138 insertions(+), 114 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index cfc24e08..cbfbc84e 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -344,6 +344,7 @@ namespace transport m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), m_Establisher (new NTCP2Establisher), + m_SendKey (nullptr), m_ReceiveKey (nullptr), #if OPENSSL_SIPHASH m_SendMDCtx(nullptr), m_ReceiveMDCtx (nullptr), #else @@ -721,6 +722,7 @@ namespace transport void NTCP2Session::HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { + (void) bytes_transferred; if (ecode) { LogPrint (eLogWarning, "NTCP2: SessionConfirmed read error: ", ecode.message ()); @@ -729,123 +731,143 @@ namespace transport else { m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval; - LogPrint (eLogDebug, "NTCP2: SessionConfirmed received"); - // part 1 - uint8_t nonce[12]; - CreateNonce (1, nonce); - if (m_Establisher->ProcessSessionConfirmedMessagePart1 (nonce)) - { - // part 2 - std::vector buf(m_Establisher->m3p2Len - 16); // -MAC - memset (nonce, 0, 12); // set nonce to 0 again - if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf.data ())) // TODO:handle in establisher thread + boost::asio::post (m_Server.GetEstablisherService (), + [s = shared_from_this ()] () { - // payload - // RI block must be first - if (buf[0] != eNTCP2BlkRouterInfo) - { - LogPrint (eLogWarning, "NTCP2: Unexpected block ", (int)buf[0], " in SessionConfirmed"); - Terminate (); - return; - } - auto size = bufbe16toh (buf.data () + 1); - if (size > buf.size () - 3 || size > i2p::data::MAX_RI_BUFFER_SIZE + 1) - { - LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); - Terminate (); - return; - } - // TODO: check flag - i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag - if (ri.IsUnreachable ()) - { - LogPrint (eLogError, "NTCP2: RouterInfo verification failed in SessionConfirmed from ", GetRemoteEndpoint ()); - SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail); - return; - } - LogPrint(eLogDebug, "NTCP2: SessionConfirmed from ", GetRemoteEndpoint (), - " (", i2p::data::GetIdentHashAbbreviation (ri.GetIdentHash ()), ")"); - auto ts = i2p::util::GetMillisecondsSinceEpoch (); - if (ts > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes - { - LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed for ", (ts - ri.GetTimestamp ())/1000LL, " seconds"); - SendTerminationAndTerminate (eNTCP2Message3Error); - return; - } - if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri.GetTimestamp ()) // 2 minutes - { - LogPrint (eLogError, "NTCP2: RouterInfo is from future for ", (ri.GetTimestamp () - ts)/1000LL, " seconds"); - SendTerminationAndTerminate (eNTCP2Message3Error); - return; - } - // update RouterInfo in netdb - auto ri1 = i2p::data::netdb.AddRouterInfo (ri.GetBuffer (), ri.GetBufferLen ()); // ri1 points to one from netdb now - if (!ri1) - { - LogPrint (eLogError, "NTCP2: Couldn't update RouterInfo from SessionConfirmed in netdb"); - Terminate (); - return; - } - std::shared_ptr profile; // not null if older - if (ri.GetTimestamp () + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri1->GetTimestamp ()) - { - // received RouterInfo is older than one in netdb - profile = i2p::data::GetRouterProfile (ri1->GetIdentHash ()); // retrieve profile - if (profile && profile->IsDuplicated ()) - { - SendTerminationAndTerminate (eNTCP2Banned); - return; - } - } - - auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri1->GetNTCP2V4Address () : - (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri1->GetYggdrasilAddress () : ri1->GetNTCP2V6Address ()); - if (!addr || memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32)) - { - LogPrint (eLogError, "NTCP2: Wrong static key in SessionConfirmed"); - Terminate (); - return; - } - if (addr->IsPublishedNTCP2 () && m_RemoteEndpoint.address () != addr->host && - (!m_RemoteEndpoint.address ().is_v6 () || (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? - memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data () + 1, addr->host.to_v6 ().to_bytes ().data () + 1, 7) : // from the same yggdrasil subnet - memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), addr->host.to_v6 ().to_bytes ().data (), 8)))) // temporary address - { - if (profile) // older router? - profile->Duplicated (); // mark router as duplicated in profile - else - LogPrint (eLogInfo, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ()); - SendTerminationAndTerminate (eNTCP2Banned); - return; - } - // TODO: process options block - - // ready to communicate - SetRemoteIdentity (ri1->GetRouterIdentity ()); - if (m_Server.AddNTCP2Session (shared_from_this (), true)) - { - KeyDerivationFunctionDataPhase (); - // Bob data phase keys - m_SendKey = m_Kba; - m_ReceiveKey = m_Kab; - SetSipKeys (m_Sipkeysba, m_Sipkeysab); - memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8); - memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8); - - Established (); - ReceiveLength (); - } - else - Terminate (); - } - else - Terminate (); - } - else - Terminate (); + s->ProcessSessionConfirmed ();; + }); } } + void NTCP2Session::ProcessSessionConfirmed () + { + // run on establisher thread + LogPrint (eLogDebug, "NTCP2: SessionConfirmed received"); + // part 1 + uint8_t nonce[12]; + CreateNonce (1, nonce); + if (m_Establisher->ProcessSessionConfirmedMessagePart1 (nonce)) + { + // part 2 + auto buf = std::make_shared > (m_Establisher->m3p2Len - 16); // -MAC + memset (nonce, 0, 12); // set nonce to 0 again + if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf->data ())) // TODO:handle in establisher thread + { + // payload + // RI block must be first + if ((*buf)[0] != eNTCP2BlkRouterInfo) + { + LogPrint (eLogWarning, "NTCP2: Unexpected block ", (int)(*buf)[0], " in SessionConfirmed"); + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + return; + } + auto size = bufbe16toh (buf->data () + 1); + if (size > buf->size () - 3 || size > i2p::data::MAX_RI_BUFFER_SIZE + 1) + { + LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + return; + } + boost::asio::post (m_Server.GetService (), + [s = shared_from_this (), buf, size] () + { + s->EstablishSessionAfterSessionConfirmed (buf, size); + }); + } + else + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + } + else + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + } + + void NTCP2Session::EstablishSessionAfterSessionConfirmed (std::shared_ptr > buf, size_t size) + { + // run on main NTCP2 thread + KeyDerivationFunctionDataPhase (); + // Bob data phase keys + m_SendKey = m_Kba; + m_ReceiveKey = m_Kab; + SetSipKeys (m_Sipkeysba, m_Sipkeysab); + memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8); + memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8); + // we need to set keys for SendTerminationAndTerminate + // TODO: check flag + i2p::data::RouterInfo ri (buf->data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag + if (ri.IsUnreachable ()) + { + LogPrint (eLogError, "NTCP2: RouterInfo verification failed in SessionConfirmed from ", GetRemoteEndpoint ()); + SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail); + return; + } + LogPrint(eLogDebug, "NTCP2: SessionConfirmed from ", GetRemoteEndpoint (), + " (", i2p::data::GetIdentHashAbbreviation (ri.GetIdentHash ()), ")"); + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + if (ts > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes + { + LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed for ", (ts - ri.GetTimestamp ())/1000LL, " seconds"); + SendTerminationAndTerminate (eNTCP2Message3Error); + return; + } + if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri.GetTimestamp ()) // 2 minutes + { + LogPrint (eLogError, "NTCP2: RouterInfo is from future for ", (ri.GetTimestamp () - ts)/1000LL, " seconds"); + SendTerminationAndTerminate (eNTCP2Message3Error); + return; + } + // update RouterInfo in netdb + auto ri1 = i2p::data::netdb.AddRouterInfo (ri.GetBuffer (), ri.GetBufferLen ()); // ri1 points to one from netdb now + if (!ri1) + { + LogPrint (eLogError, "NTCP2: Couldn't update RouterInfo from SessionConfirmed in netdb"); + Terminate (); + return; + } + std::shared_ptr profile; // not null if older + if (ri.GetTimestamp () + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri1->GetTimestamp ()) + { + // received RouterInfo is older than one in netdb + profile = i2p::data::GetRouterProfile (ri1->GetIdentHash ()); // retrieve profile + if (profile && profile->IsDuplicated ()) + { + SendTerminationAndTerminate (eNTCP2Banned); + return; + } + } + + auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri1->GetNTCP2V4Address () : + (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri1->GetYggdrasilAddress () : ri1->GetNTCP2V6Address ()); + if (!addr || memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32)) + { + LogPrint (eLogError, "NTCP2: Wrong static key in SessionConfirmed"); + Terminate (); + return; + } + if (addr->IsPublishedNTCP2 () && m_RemoteEndpoint.address () != addr->host && + (!m_RemoteEndpoint.address ().is_v6 () || (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? + memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data () + 1, addr->host.to_v6 ().to_bytes ().data () + 1, 7) : // from the same yggdrasil subnet + memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), addr->host.to_v6 ().to_bytes ().data (), 8)))) // temporary address + { + if (profile) // older router? + profile->Duplicated (); // mark router as duplicated in profile + else + LogPrint (eLogInfo, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ()); + SendTerminationAndTerminate (eNTCP2Banned); + return; + } + // TODO: process options block + + // ready to communicate + SetRemoteIdentity (ri1->GetRouterIdentity ()); + if (m_Server.AddNTCP2Session (shared_from_this (), true)) + { + Established (); + ReceiveLength (); + } + else + Terminate (); + } + void NTCP2Session::SetSipKeys (const uint8_t * sendSipKey, const uint8_t * receiveSipKey) { #if OPENSSL_SIPHASH diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index f0cee06a..108c58f6 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -180,7 +180,9 @@ namespace transport void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); - + void ProcessSessionConfirmed (); + void EstablishSessionAfterSessionConfirmed (std::shared_ptr > buf, size_t size); + // data void ReceiveLength (); void HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred); From 13604ccbb60bb3ef38125db3df5d1d6bad7b0985 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Dec 2024 22:15:11 -0500 Subject: [PATCH 282/527] Changing the window calculation algorithm, increasing the minimum window size --- libi2pd/Streaming.cpp | 28 ++++++++++++++++++++-------- libi2pd/Streaming.h | 4 +++- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index efa190cf..7a0a39a4 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -73,7 +73,7 @@ namespace stream m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsIncoming (false), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), - m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_LocalDestination (local), + m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_DoubleWinIncCounter (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), @@ -101,7 +101,7 @@ namespace stream m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsIncoming (true), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), - m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_LocalDestination (local), + m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_DoubleWinIncCounter (false), m_LocalDestination (local), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), @@ -495,6 +495,7 @@ namespace stream return; } int rttSample = INT_MAX; + int incCounter = 0; m_IsNAcked = false; m_IsResendNeeded = false; int nackCount = packet->GetNACKCount (); @@ -537,8 +538,7 @@ namespace stream m_LocalDestination.DeletePacket (sentPacket); acknowledged = true; if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK) - if (m_RTT < m_LocalDestination.GetRandom () % INITIAL_RTO) // dirty - m_WindowIncCounter++; + incCounter++; } else break; @@ -552,7 +552,7 @@ namespace stream m_SlowRTT2 = rttSample; m_PrevRTTSample = rttSample; m_Jitter = rttSample / 10; // 10% - m_Jitter += 5; // for low-latency connections + m_Jitter += 15; // for low-latency connections m_IsFirstRttSample = false; } else @@ -569,9 +569,23 @@ namespace stream jitter = m_PrevRTTSample - rttSample; else jitter = rttSample / 10; // 10% - jitter += 5; // for low-latency connections + jitter += 15; // for low-latency connections m_Jitter = (0.05 * jitter) + (1.0 - 0.05) * m_Jitter; } + if (rttSample > m_SlowRTT) + { + incCounter = 0; + m_DoubleWinIncCounter = 1; + } + else if (rttSample < m_SlowRTT) + { + if (m_DoubleWinIncCounter) + { + incCounter = incCounter * 2; + m_DoubleWinIncCounter = 0; + } + } + m_WindowIncCounter = m_WindowIncCounter + incCounter; // // delay-based CC if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection @@ -1297,8 +1311,6 @@ namespace stream else if (m_IsResendNeeded) // resend packets ResendPacket (); // delay-based CC - else if (!m_IsWinDropped && int(m_SentPackets.size ()) == m_WindowSize) // we sending packets too fast, early detection - ProcessWindowDrop (); else if (m_WindowSize > int(m_SentPackets.size ())) // send packets SendBuffer (); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index e5dba39f..36c13eff 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -19,6 +19,7 @@ #include #include #include "Base.h" +#include "Gzip.h" #include "I2PEndian.h" #include "Identity.h" #include "LeaseSet.h" @@ -54,7 +55,7 @@ namespace stream const size_t COMPRESSION_THRESHOLD_SIZE = 66; const int MAX_NUM_RESEND_ATTEMPTS = 10; const int INITIAL_WINDOW_SIZE = 10; - const int MIN_WINDOW_SIZE = 2; + const int MIN_WINDOW_SIZE = 3; const int MAX_WINDOW_SIZE = 512; const double RTT_EWMA_ALPHA = 0.25; const double SLOWRTT_EWMA_ALPHA = 0.05; @@ -274,6 +275,7 @@ namespace stream bool m_IsTimeOutResend; bool m_IsImmediateAckRequested; bool m_IsRemoteLeaseChangeInProgress; + bool m_DoubleWinIncCounter; StreamingDestination& m_LocalDestination; std::shared_ptr m_RemoteIdentity; std::shared_ptr m_TransientVerifier; // in case of offline key From 226257aa71f8a13e5b0e74e531dfc03e8ede448a Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Fri, 6 Dec 2024 17:11:31 +0200 Subject: [PATCH 283/527] Fix typos --- libi2pd/Config.cpp | 2 +- libi2pd/Garlic.cpp | 2 +- libi2pd/Garlic.h | 2 +- libi2pd/NetDb.cpp | 2 +- libi2pd/SSU2.cpp | 2 +- libi2pd/SSU2OutOfSession.cpp | 4 ++-- libi2pd/Streaming.cpp | 2 +- libi2pd/Streaming.h | 2 +- libi2pd/TunnelGateway.cpp | 6 +++--- libi2pd_client/I2CP.cpp | 2 +- libi2pd_client/UDPTunnel.cpp | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 5add5f1e..dfddeb7b 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -117,7 +117,7 @@ namespace config { ("httpproxy.latency.max", value()->default_value("0"), "HTTP proxy max latency for tunnels") ("httpproxy.outproxy", value()->default_value(""), "HTTP proxy upstream out proxy url") ("httpproxy.addresshelper", value()->default_value(true), "Enable or disable addresshelper") - ("httpproxy.senduseragent", value()->default_value(false), "Pass through user's User-Agent if enabled. Disabled by deafult") + ("httpproxy.senduseragent", value()->default_value(false), "Pass through user's User-Agent if enabled. Disabled by default") ("httpproxy.i2cp.leaseSetType", value()->default_value("3"), "Local destination's LeaseSet type") ("httpproxy.i2cp.leaseSetEncType", value()->default_value("0,4"), "Local destination's LeaseSet encryption type") ("httpproxy.i2cp.leaseSetPrivKey", value()->default_value(""), "LeaseSet private key") diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index b6f6d131..c93579e0 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -550,7 +550,7 @@ namespace garlic LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); } else - LogPrint (eLogWarning, "Garlic: Incoming sessions come too ofter"); + LogPrint (eLogWarning, "Garlic: Incoming sessions come too often"); } else LogPrint (eLogError, "Garlic: Failed to decrypt message"); diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 57c3fddc..8401f052 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -286,7 +286,7 @@ namespace garlic std::unordered_map m_Sessions; std::unordered_map, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session uint8_t * m_PayloadBuffer; // for ECIESX25519AEADRatchet - uint64_t m_LastIncomingSessionTimestamp; // in millseconds + uint64_t m_LastIncomingSessionTimestamp; // in milliseconds // incoming int m_NumRatchetInboundTags; std::unordered_map, std::hash > > m_Tags; diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 18d6308b..c712af8b 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -637,7 +637,7 @@ namespace data if (checkForExpiration && uptime > i2p::transport::SSU2_TO_INTRODUCER_SESSION_DURATION) // 1 hour expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL : NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total; - bool isOffline = checkForExpiration && i2p::transport::transports.GetNumPeers () < NETDB_MIN_TRANSPORTS; // enough routers and uptime, but no tranports + bool isOffline = checkForExpiration && i2p::transport::transports.GetNumPeers () < NETDB_MIN_TRANSPORTS; // enough routers and uptime, but no transports std::list > > saveToDisk; std::list removeFromDisk; diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 982940c5..f53f9dd0 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1389,7 +1389,7 @@ namespace transport excluded.insert (ident); } - // sesssion about to expire are not counted + // session about to expire are not counted for (auto i = introducers.size (); i < SSU2_MAX_NUM_INTRODUCERS + numOldSessions; i++) { auto introducer = i2p::data::netdb.GetRandomSSU2Introducer (v4, excluded); diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index 651ed76c..333c1c92 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -68,7 +68,7 @@ namespace transport void SSU2PeerTestSession::HandleAddress (const uint8_t * buf, size_t len) { if (!ExtractEndpoint (buf, len, m_OurEndpoint)) - LogPrint (eLogWarning, "SSU2: Can't hanlde address block from peer test message"); + LogPrint (eLogWarning, "SSU2: Can't handle address block from peer test message"); } void SSU2PeerTestSession::HandlePeerTest (const uint8_t * buf, size_t len) @@ -89,7 +89,7 @@ namespace transport { if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ()) { - m_PeerTestResendTimer.cancel (); // calcel delayed msg 6 if any + m_PeerTestResendTimer.cancel (); // cancel delayed msg 6 if any m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ()); if (GetAddress ()) { diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 7a0a39a4..2495e15f 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -958,7 +958,7 @@ namespace stream if (choking || requestImmediateAck) { htobe16buf (packet + size, 2); // 2 bytes delay interval - htobe16buf (packet + size + 2, choking ? DELAY_CHOKING : 0); // set choking or immediated ack interval + htobe16buf (packet + size + 2, choking ? DELAY_CHOKING : 0); // set choking or immediate ack interval size += 2; if (requestImmediateAck) // ack request sent { diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 36c13eff..71450b2b 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -298,7 +298,7 @@ namespace stream int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; double m_Jitter; uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, // microseconds - m_LastSendTime, m_RemoteLeaseChangeTime; // miliseconds + m_LastSendTime, m_RemoteLeaseChangeTime; // milliseconds uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed int m_NumResendAttempts, m_NumPacketsToSend; size_t m_MTU; diff --git a/libi2pd/TunnelGateway.cpp b/libi2pd/TunnelGateway.cpp index fabc71bb..e2797f8c 100644 --- a/libi2pd/TunnelGateway.cpp +++ b/libi2pd/TunnelGateway.cpp @@ -240,13 +240,13 @@ namespace tunnel auto currentTransport = m_CurrentTransport.lock (); if (!currentTransport) { - // try to obtain transport from peding reequest or send thought transport is not complete + // try to obtain transport from pending request or send thought transport is not complete if (m_PendingTransport.valid ()) // pending request? { if (m_PendingTransport.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { // pending request complete - currentTransport = m_PendingTransport.get (); // take tarnsports used in pending request + currentTransport = m_PendingTransport.get (); // take transports used in pending request if (currentTransport) { if (currentTransport->IsEstablished ()) @@ -257,7 +257,7 @@ namespace tunnel } else // still pending { - // send through transports, but don't update pedning transport + // send through transports, but don't update pending transport i2p::transport::transports.SendMessages (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs)); return; } diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 1949746a..f6bc3268 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -879,7 +879,7 @@ namespace client if (!remoteSession || !m_Destination->SendMsg (buf + offset, payloadLen, remoteSession, nonce)) { i2p::data::IdentHash identHash; - SHA256(ident, identSize, identHash); // caclulate ident hash, because we don't need full identity + SHA256(ident, identSize, identHash); // calculate ident hash, because we don't need full identity m_Destination->SendMsgTo (buf + offset, payloadLen, identHash, nonce); } } diff --git a/libi2pd_client/UDPTunnel.cpp b/libi2pd_client/UDPTunnel.cpp index 9f7fe864..b173fc0f 100644 --- a/libi2pd_client/UDPTunnel.cpp +++ b/libi2pd_client/UDPTunnel.cpp @@ -86,7 +86,7 @@ namespace client } else { - LogPrint(eLogWarning, "UDPServer: Session with from ", remotePort, " and to ", localPort, " ports already exists. But from differend address. Removed"); + LogPrint(eLogWarning, "UDPServer: Session with from ", remotePort, " and to ", localPort, " ports already exists. But from different address. Removed"); m_Sessions.erase (it); } } From 786da057f2ce74a1ebffcf4fb2951944e8fac618 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 6 Dec 2024 20:25:22 -0500 Subject: [PATCH 284/527] always use openssl for AES --- libi2pd/CPU.cpp | 68 ------- libi2pd/CPU.h | 18 +- libi2pd/Crypto.cpp | 470 +++++++-------------------------------------- libi2pd/Crypto.h | 137 ++++--------- libi2pd/NTCP2.cpp | 4 +- 5 files changed, 111 insertions(+), 586 deletions(-) delete mode 100644 libi2pd/CPU.cpp diff --git a/libi2pd/CPU.cpp b/libi2pd/CPU.cpp deleted file mode 100644 index 77820c88..00000000 --- a/libi2pd/CPU.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* -* Copyright (c) 2013-2023, 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 "CPU.h" -#include "Log.h" - -#ifndef bit_AES - #define bit_AES (1 << 25) -#endif - -#if defined(__GNUC__) && __GNUC__ < 6 && IS_X86 - #include -#endif - -#ifdef _MSC_VER - #include -#endif - -namespace i2p -{ -namespace cpu -{ - bool aesni = false; - - inline bool cpu_support_aes() - { -#if IS_X86 -#if defined(__clang__) -# if (__clang_major__ >= 6) - __builtin_cpu_init(); -# endif - return __builtin_cpu_supports("aes"); -#elif (defined(__GNUC__) && __GNUC__ >= 6) - __builtin_cpu_init(); - return __builtin_cpu_supports("aes"); -#elif (defined(__GNUC__) && __GNUC__ < 6) - int cpu_info[4]; - bool flag = false; - __cpuid(0, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]); - if (cpu_info[0] >= 0x00000001) { - __cpuid(0x00000001, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]); - flag = ((cpu_info[2] & bit_AES) != 0); - } - return flag; -#elif defined(_MSC_VER) - int cpu_info[4]; - __cpuid(cpu_info, 1); - return ((cpu_info[2] & bit_AES) != 0); -#endif -#endif - return false; - } - - void Detect(bool AesSwitch, bool force) - { - if ((cpu_support_aes() && AesSwitch) || (AesSwitch && force)) { - aesni = true; - } - - LogPrint(eLogInfo, "AESNI ", (aesni ? "enabled" : "disabled")); - } -} -} diff --git a/libi2pd/CPU.h b/libi2pd/CPU.h index 1c30db48..3fc38d47 100644 --- a/libi2pd/CPU.h +++ b/libi2pd/CPU.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 * @@ -21,20 +21,4 @@ # define IS_X86_64 0 #endif -#if defined(__AES__) && !defined(_MSC_VER) && IS_X86 -# define SUPPORTS_AES 1 -#else -# define SUPPORTS_AES 0 -#endif - -namespace i2p -{ -namespace cpu -{ - extern bool aesni; - - void Detect(bool AesSwitch, bool force); -} -} - #endif diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 2371b529..604c6287 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -19,6 +19,7 @@ #if OPENSSL_HKDF #include #endif +#include "CPU.h" #include "Crypto.h" #include "Ed25519.h" #include "I2PEndian.h" @@ -515,429 +516,105 @@ namespace crypto } // AES -#if SUPPORTS_AES - #define KeyExpansion256(round0,round1) \ - "pshufd $0xff, %%xmm2, %%xmm2 \n" \ - "movaps %%xmm1, %%xmm4 \n" \ - "pslldq $4, %%xmm4 \n" \ - "pxor %%xmm4, %%xmm1 \n" \ - "pslldq $4, %%xmm4 \n" \ - "pxor %%xmm4, %%xmm1 \n" \ - "pslldq $4, %%xmm4 \n" \ - "pxor %%xmm4, %%xmm1 \n" \ - "pxor %%xmm2, %%xmm1 \n" \ - "movaps %%xmm1, "#round0"(%[sched]) \n" \ - "aeskeygenassist $0, %%xmm1, %%xmm4 \n" \ - "pshufd $0xaa, %%xmm4, %%xmm2 \n" \ - "movaps %%xmm3, %%xmm4 \n" \ - "pslldq $4, %%xmm4 \n" \ - "pxor %%xmm4, %%xmm3 \n" \ - "pslldq $4, %%xmm4 \n" \ - "pxor %%xmm4, %%xmm3 \n" \ - "pslldq $4, %%xmm4 \n" \ - "pxor %%xmm4, %%xmm3 \n" \ - "pxor %%xmm2, %%xmm3 \n" \ - "movaps %%xmm3, "#round1"(%[sched]) \n" -#endif - -#if SUPPORTS_AES - void ECBCryptoAESNI::ExpandKey (const AESKey& key) + ECBEncryption::ECBEncryption () { - __asm__ - ( - "movups (%[key]), %%xmm1 \n" - "movups 16(%[key]), %%xmm3 \n" - "movaps %%xmm1, (%[sched]) \n" - "movaps %%xmm3, 16(%[sched]) \n" - "aeskeygenassist $1, %%xmm3, %%xmm2 \n" - KeyExpansion256(32,48) - "aeskeygenassist $2, %%xmm3, %%xmm2 \n" - KeyExpansion256(64,80) - "aeskeygenassist $4, %%xmm3, %%xmm2 \n" - KeyExpansion256(96,112) - "aeskeygenassist $8, %%xmm3, %%xmm2 \n" - KeyExpansion256(128,144) - "aeskeygenassist $16, %%xmm3, %%xmm2 \n" - KeyExpansion256(160,176) - "aeskeygenassist $32, %%xmm3, %%xmm2 \n" - KeyExpansion256(192,208) - "aeskeygenassist $64, %%xmm3, %%xmm2 \n" - // key expansion final - "pshufd $0xff, %%xmm2, %%xmm2 \n" - "movaps %%xmm1, %%xmm4 \n" - "pslldq $4, %%xmm4 \n" - "pxor %%xmm4, %%xmm1 \n" - "pslldq $4, %%xmm4 \n" - "pxor %%xmm4, %%xmm1 \n" - "pslldq $4, %%xmm4 \n" - "pxor %%xmm4, %%xmm1 \n" - "pxor %%xmm2, %%xmm1 \n" - "movups %%xmm1, 224(%[sched]) \n" - : // output - : [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input - : "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged - ); + m_Ctx = EVP_CIPHER_CTX_new (); } -#endif - - -#if SUPPORTS_AES - #define EncryptAES256(sched) \ - "pxor (%["#sched"]), %%xmm0 \n" \ - "aesenc 16(%["#sched"]), %%xmm0 \n" \ - "aesenc 32(%["#sched"]), %%xmm0 \n" \ - "aesenc 48(%["#sched"]), %%xmm0 \n" \ - "aesenc 64(%["#sched"]), %%xmm0 \n" \ - "aesenc 80(%["#sched"]), %%xmm0 \n" \ - "aesenc 96(%["#sched"]), %%xmm0 \n" \ - "aesenc 112(%["#sched"]), %%xmm0 \n" \ - "aesenc 128(%["#sched"]), %%xmm0 \n" \ - "aesenc 144(%["#sched"]), %%xmm0 \n" \ - "aesenc 160(%["#sched"]), %%xmm0 \n" \ - "aesenc 176(%["#sched"]), %%xmm0 \n" \ - "aesenc 192(%["#sched"]), %%xmm0 \n" \ - "aesenc 208(%["#sched"]), %%xmm0 \n" \ - "aesenclast 224(%["#sched"]), %%xmm0 \n" -#endif - - void ECBEncryption::Encrypt (const ChipherBlock * in, ChipherBlock * out) + + ECBEncryption::~ECBEncryption () { -#if SUPPORTS_AES - if(i2p::cpu::aesni) - { - __asm__ - ( - "movups (%[in]), %%xmm0 \n" - EncryptAES256(sched) - "movups %%xmm0, (%[out]) \n" - : - : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) - : "%xmm0", "memory" - ); - } - else -#endif - { - AES_encrypt (in->buf, out->buf, &m_Key); - } + if (m_Ctx) + EVP_CIPHER_CTX_free (m_Ctx); + } + + void ECBEncryption::Encrypt (const uint8_t * in, uint8_t * out) + { + EVP_EncryptInit_ex (m_Ctx, EVP_aes_256_ecb(), NULL, m_Key, NULL); + EVP_CIPHER_CTX_set_padding (m_Ctx, 0); + int len; + EVP_EncryptUpdate (m_Ctx, out, &len, in, 16); + EVP_EncryptFinal_ex (m_Ctx, out + len, &len); } -#if SUPPORTS_AES - #define DecryptAES256(sched) \ - "pxor 224(%["#sched"]), %%xmm0 \n" \ - "aesdec 208(%["#sched"]), %%xmm0 \n" \ - "aesdec 192(%["#sched"]), %%xmm0 \n" \ - "aesdec 176(%["#sched"]), %%xmm0 \n" \ - "aesdec 160(%["#sched"]), %%xmm0 \n" \ - "aesdec 144(%["#sched"]), %%xmm0 \n" \ - "aesdec 128(%["#sched"]), %%xmm0 \n" \ - "aesdec 112(%["#sched"]), %%xmm0 \n" \ - "aesdec 96(%["#sched"]), %%xmm0 \n" \ - "aesdec 80(%["#sched"]), %%xmm0 \n" \ - "aesdec 64(%["#sched"]), %%xmm0 \n" \ - "aesdec 48(%["#sched"]), %%xmm0 \n" \ - "aesdec 32(%["#sched"]), %%xmm0 \n" \ - "aesdec 16(%["#sched"]), %%xmm0 \n" \ - "aesdeclast (%["#sched"]), %%xmm0 \n" -#endif - - void ECBDecryption::Decrypt (const ChipherBlock * in, ChipherBlock * out) + ECBDecryption::ECBDecryption () { -#if SUPPORTS_AES - if(i2p::cpu::aesni) - { - __asm__ - ( - "movups (%[in]), %%xmm0 \n" - DecryptAES256(sched) - "movups %%xmm0, (%[out]) \n" - : - : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) - : "%xmm0", "memory" - ); - } - else -#endif - { - AES_decrypt (in->buf, out->buf, &m_Key); - } + m_Ctx = EVP_CIPHER_CTX_new (); + } + + ECBDecryption::~ECBDecryption () + { + if (m_Ctx) + EVP_CIPHER_CTX_free (m_Ctx); + } + + void ECBDecryption::Decrypt (const uint8_t * in, uint8_t * out) + { + EVP_DecryptInit_ex (m_Ctx, EVP_aes_256_ecb(), NULL, m_Key, NULL); + EVP_CIPHER_CTX_set_padding (m_Ctx, 0); + int len; + EVP_DecryptUpdate (m_Ctx, out, &len, in, 16); + EVP_DecryptFinal_ex (m_Ctx, out + len, &len); } -#if SUPPORTS_AES - #define CallAESIMC(offset) \ - "movaps "#offset"(%[shed]), %%xmm0 \n" \ - "aesimc %%xmm0, %%xmm0 \n" \ - "movaps %%xmm0, "#offset"(%[shed]) \n" -#endif - void ECBEncryption::SetKey (const AESKey& key) - { -#if SUPPORTS_AES - if(i2p::cpu::aesni) - { - ExpandKey (key); - } - else -#endif - { - AES_set_encrypt_key (key, 256, &m_Key); - } + CBCEncryption::CBCEncryption () + { + m_Ctx = EVP_CIPHER_CTX_new (); + //memset ((uint8_t *)m_LastBlock, 0, 16); } - - void ECBDecryption::SetKey (const AESKey& key) + + CBCEncryption::~CBCEncryption () { -#if SUPPORTS_AES - if(i2p::cpu::aesni) - { - ExpandKey (key); // expand encryption key first - // then invert it using aesimc - __asm__ - ( - CallAESIMC(16) - CallAESIMC(32) - CallAESIMC(48) - CallAESIMC(64) - CallAESIMC(80) - CallAESIMC(96) - CallAESIMC(112) - CallAESIMC(128) - CallAESIMC(144) - CallAESIMC(160) - CallAESIMC(176) - CallAESIMC(192) - CallAESIMC(208) - : - : [shed]"r"(GetKeySchedule ()) - : "%xmm0", "memory" - ); - } - else -#endif - { - AES_set_decrypt_key (key, 256, &m_Key); - } - } - - void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) - { -#if SUPPORTS_AES - if(i2p::cpu::aesni) - { - __asm__ - ( - "movups (%[iv]), %%xmm1 \n" - "1: \n" - "movups (%[in]), %%xmm0 \n" - "pxor %%xmm1, %%xmm0 \n" - EncryptAES256(sched) - "movaps %%xmm0, %%xmm1 \n" - "movups %%xmm0, (%[out]) \n" - "add $16, %[in] \n" - "add $16, %[out] \n" - "dec %[num] \n" - "jnz 1b \n" - "movups %%xmm1, (%[iv]) \n" - : - : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), - [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) - : "%xmm0", "%xmm1", "cc", "memory" - ); - } - else -#endif - { - for (int i = 0; i < numBlocks; i++) - { - *m_LastBlock.GetChipherBlock () ^= in[i]; - m_ECBEncryption.Encrypt (m_LastBlock.GetChipherBlock (), m_LastBlock.GetChipherBlock ()); - out[i] = *m_LastBlock.GetChipherBlock (); - } - } - } - + if (m_Ctx) + EVP_CIPHER_CTX_free (m_Ctx); + } + void CBCEncryption::Encrypt (const uint8_t * in, std::size_t len, uint8_t * out) { // len/16 - int numBlocks = len >> 4; - if (numBlocks > 0) - Encrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out); + EVP_EncryptInit_ex (m_Ctx, EVP_aes_256_cbc(), NULL, m_Key, m_IV); + EVP_CIPHER_CTX_set_padding (m_Ctx, 0); + int l; + EVP_EncryptUpdate (m_Ctx, out, &l, in, len); + EVP_EncryptFinal_ex (m_Ctx, out + l, &l); } - void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out) + CBCDecryption::CBCDecryption () + { + m_Ctx = EVP_CIPHER_CTX_new (); + //memset ((uint8_t *)m_IV, 0, 16); + } + + CBCDecryption::~CBCDecryption () { -#if SUPPORTS_AES - if(i2p::cpu::aesni) - { - __asm__ - ( - "movups (%[iv]), %%xmm1 \n" - "movups (%[in]), %%xmm0 \n" - "pxor %%xmm1, %%xmm0 \n" - EncryptAES256(sched) - "movups %%xmm0, (%[out]) \n" - "movups %%xmm0, (%[iv]) \n" - : - : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), - [in]"r"(in), [out]"r"(out) - : "%xmm0", "%xmm1", "memory" - ); - } - else -#endif - Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); - } - - void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) - { -#if SUPPORTS_AES - if(i2p::cpu::aesni) - { - __asm__ - ( - "movups (%[iv]), %%xmm1 \n" - "1: \n" - "movups (%[in]), %%xmm0 \n" - "movaps %%xmm0, %%xmm2 \n" - DecryptAES256(sched) - "pxor %%xmm1, %%xmm0 \n" - "movups %%xmm0, (%[out]) \n" - "movaps %%xmm2, %%xmm1 \n" - "add $16, %[in] \n" - "add $16, %[out] \n" - "dec %[num] \n" - "jnz 1b \n" - "movups %%xmm1, (%[iv]) \n" - : - : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), - [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) - : "%xmm0", "%xmm1", "%xmm2", "cc", "memory" - ); - } - else -#endif - { - for (int i = 0; i < numBlocks; i++) - { - ChipherBlock tmp = in[i]; - m_ECBDecryption.Decrypt (in + i, out + i); - out[i] ^= *m_IV.GetChipherBlock (); - *m_IV.GetChipherBlock () = tmp; - } - } - } - + if (m_Ctx) + EVP_CIPHER_CTX_free (m_Ctx); + } + void CBCDecryption::Decrypt (const uint8_t * in, std::size_t len, uint8_t * out) { - int numBlocks = len >> 4; - if (numBlocks > 0) - Decrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out); - } - - void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out) - { -#if SUPPORTS_AES - if(i2p::cpu::aesni) - { - __asm__ - ( - "movups (%[iv]), %%xmm1 \n" - "movups (%[in]), %%xmm0 \n" - "movups %%xmm0, (%[iv]) \n" - DecryptAES256(sched) - "pxor %%xmm1, %%xmm0 \n" - "movups %%xmm0, (%[out]) \n" - : - : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), - [in]"r"(in), [out]"r"(out) - : "%xmm0", "%xmm1", "memory" - ); - } - else -#endif - Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); + // len/16 + EVP_DecryptInit_ex (m_Ctx, EVP_aes_256_cbc(), NULL, m_Key, m_IV); + EVP_CIPHER_CTX_set_padding (m_Ctx, 0); + int l; + EVP_DecryptUpdate (m_Ctx, out, &l, in, len); + EVP_DecryptFinal_ex (m_Ctx, out + l, &l); } void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out) { -#if SUPPORTS_AES - if(i2p::cpu::aesni) - { - __asm__ - ( - // encrypt IV - "movups (%[in]), %%xmm0 \n" - EncryptAES256(sched_iv) - "movaps %%xmm0, %%xmm1 \n" - // double IV encryption - EncryptAES256(sched_iv) - "movups %%xmm0, (%[out]) \n" - // encrypt data, IV is xmm1 - "1: \n" - "add $16, %[in] \n" - "add $16, %[out] \n" - "movups (%[in]), %%xmm0 \n" - "pxor %%xmm1, %%xmm0 \n" - EncryptAES256(sched_l) - "movaps %%xmm0, %%xmm1 \n" - "movups %%xmm0, (%[out]) \n" - "dec %[num] \n" - "jnz 1b \n" - : - : [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.ECB().GetKeySchedule ()), - [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes - : "%xmm0", "%xmm1", "cc", "memory" - ); - } - else -#endif - { - m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv - m_LayerEncryption.SetIV (out); - m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data - m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv - } + m_IVEncryption.Encrypt (in, out); // iv + m_LayerEncryption.SetIV (out); + m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data + m_IVEncryption.Encrypt (out, out); // double iv } void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out) { -#if SUPPORTS_AES - if(i2p::cpu::aesni) - { - __asm__ - ( - // decrypt IV - "movups (%[in]), %%xmm0 \n" - DecryptAES256(sched_iv) - "movaps %%xmm0, %%xmm1 \n" - // double IV encryption - DecryptAES256(sched_iv) - "movups %%xmm0, (%[out]) \n" - // decrypt data, IV is xmm1 - "1: \n" - "add $16, %[in] \n" - "add $16, %[out] \n" - "movups (%[in]), %%xmm0 \n" - "movaps %%xmm0, %%xmm2 \n" - DecryptAES256(sched_l) - "pxor %%xmm1, %%xmm0 \n" - "movups %%xmm0, (%[out]) \n" - "movaps %%xmm2, %%xmm1 \n" - "dec %[num] \n" - "jnz 1b \n" - : - : [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.ECB().GetKeySchedule ()), - [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes - : "%xmm0", "%xmm1", "%xmm2", "cc", "memory" - ); - } - else -#endif - { - m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv - m_LayerDecryption.SetIV (out); - m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data - m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv - } + m_IVDecryption.Decrypt (in, out); // iv + m_LayerDecryption.SetIV (out); + m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data + m_IVDecryption.Decrypt (out, out); // double iv } // AEAD/ChaCha20/Poly1305 @@ -1159,7 +836,6 @@ namespace crypto void InitCrypto (bool precomputation, bool aesni, bool force) { - i2p::cpu::Detect (aesni, force); /* auto numLocks = CRYPTO_num_locks(); for (int i = 0; i < numLocks; i++) m_OpenSSLMutexes.emplace_back (new std::mutex); diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 75bd7bb2..a996728e 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -25,7 +25,6 @@ #include "Base.h" #include "Tag.h" -#include "CPU.h" // recognize openssl version and features #if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1 @@ -85,142 +84,76 @@ namespace crypto void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub); // AES - struct ChipherBlock - { - uint8_t buf[16]; - - void operator^=(const ChipherBlock& other) // XOR - { - if (!(((size_t)buf | (size_t)other.buf) & 0x03)) // multiple of 4 ? - { - for (int i = 0; i < 4; i++) - reinterpret_cast(buf)[i] ^= reinterpret_cast(other.buf)[i]; - } - else - { - for (int i = 0; i < 16; i++) - buf[i] ^= other.buf[i]; - } - } - }; - typedef i2p::data::Tag<32> AESKey; - - template - class AESAlignedBuffer // 16 bytes alignment - { - public: - - AESAlignedBuffer () - { - m_Buf = m_UnalignedBuffer; - uint8_t rem = ((size_t)m_Buf) & 0x0f; - if (rem) - m_Buf += (16 - rem); - } - - operator uint8_t * () { return m_Buf; }; - operator const uint8_t * () const { return m_Buf; }; - ChipherBlock * GetChipherBlock () { return (ChipherBlock *)m_Buf; }; - const ChipherBlock * GetChipherBlock () const { return (const ChipherBlock *)m_Buf; }; - - private: - - uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment - uint8_t * m_Buf; - }; - - -#if SUPPORTS_AES - class ECBCryptoAESNI - { - public: - - uint8_t * GetKeySchedule () { return m_KeySchedule; }; - - protected: - - void ExpandKey (const AESKey& key); - - private: - - AESAlignedBuffer<240> m_KeySchedule; // 14 rounds for AES-256, 240 bytes - }; -#endif - -#if SUPPORTS_AES - class ECBEncryption: public ECBCryptoAESNI -#else + class ECBEncryption -#endif { public: - void SetKey (const AESKey& key); + ECBEncryption (); + ~ECBEncryption (); + + void SetKey (const AESKey& key) { m_Key = key; }; + void Encrypt(const uint8_t * in, uint8_t * out); - void Encrypt(const ChipherBlock * in, ChipherBlock * out); + private: - private: - AES_KEY m_Key; + AESKey m_Key; + EVP_CIPHER_CTX * m_Ctx; }; -#if SUPPORTS_AES - class ECBDecryption: public ECBCryptoAESNI -#else class ECBDecryption -#endif { public: - void SetKey (const AESKey& key); - void Decrypt (const ChipherBlock * in, ChipherBlock * out); + ECBDecryption (); + ~ECBDecryption (); + + void SetKey (const AESKey& key) { m_Key = key; }; + void Decrypt (const uint8_t * in, uint8_t * out); + private: - AES_KEY m_Key; + + AESKey m_Key; + EVP_CIPHER_CTX * m_Ctx; }; class CBCEncryption { public: - CBCEncryption () { memset ((uint8_t *)m_LastBlock, 0, 16); }; + CBCEncryption (); + ~CBCEncryption (); - void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes - void SetIV (const uint8_t * iv) { memcpy ((uint8_t *)m_LastBlock, iv, 16); }; // 16 bytes - void GetIV (uint8_t * iv) const { memcpy (iv, (const uint8_t *)m_LastBlock, 16); }; - - void Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out); + void SetKey (const AESKey& key) { m_Key = key; }; // 32 bytes + void SetIV (const uint8_t * iv) { m_IV = iv; }; // 16 bytes + void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out); - void Encrypt (const uint8_t * in, uint8_t * out); // one block - - ECBEncryption & ECB() { return m_ECBEncryption; } - + private: - AESAlignedBuffer<16> m_LastBlock; - - ECBEncryption m_ECBEncryption; + AESKey m_Key; + i2p::data::Tag<16> m_IV; + EVP_CIPHER_CTX * m_Ctx; }; class CBCDecryption { public: - CBCDecryption () { memset ((uint8_t *)m_IV, 0, 16); }; + CBCDecryption (); + ~CBCDecryption (); + + void SetKey (const AESKey& key) { m_Key = key; }; // 32 bytes + void SetIV (const uint8_t * iv) { m_IV = iv; }; // 16 bytes - void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes - void SetIV (const uint8_t * iv) { memcpy ((uint8_t *)m_IV, iv, 16); }; // 16 bytes - void GetIV (uint8_t * iv) const { memcpy (iv, (const uint8_t *)m_IV, 16); }; - - void Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out); void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out); - void Decrypt (const uint8_t * in, uint8_t * out); // one block - - ECBDecryption & ECB() { return m_ECBDecryption; } private: - AESAlignedBuffer<16> m_IV; - ECBDecryption m_ECBDecryption; + AESKey m_Key; + i2p::data::Tag<16> m_IV; + EVP_CIPHER_CTX * m_Ctx; }; class TunnelEncryption // with double IV encryption diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index cbfbc84e..6630a351 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -122,7 +122,7 @@ namespace transport encryption.SetKey (m_RemoteIdentHash); encryption.SetIV (m_IV); encryption.Encrypt (GetPub (), 32, m_SessionRequestBuffer); // X - encryption.GetIV (m_IV); // save IV for SessionCreated + memcpy (m_IV, m_SessionRequestBuffer + 16, 16); // save last block as IV for SessionCreated // encryption key for next block if (!KDF1Alice ()) return false; // fill options @@ -210,7 +210,7 @@ namespace transport decryption.SetKey (i2p::context.GetIdentHash ()); decryption.SetIV (i2p::context.GetNTCP2IV ()); decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ()); - decryption.GetIV (m_IV); // save IV for SessionCreated + memcpy (m_IV, m_SessionRequestBuffer + 16, 16); // save last block as IV for SessionCreated // decryption key for next block if (!KDF1Bob ()) { From 65da550d19a31c325dbd68346c970d56a2de517d Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 7 Dec 2024 15:03:18 -0500 Subject: [PATCH 285/527] fix bug with unexpected stream closing --- libi2pd/Streaming.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 2495e15f..70c59067 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1147,7 +1147,6 @@ namespace stream m_CurrentOutboundTunnel = routingPath->outboundTunnel; m_CurrentRemoteLease = routingPath->remoteLease; m_RTT = routingPath->rtt; - m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter)); // TODO: implement it better } } From 48b62340ccfc6742d09b3d20a4aa16325391af3c Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 7 Dec 2024 15:27:23 -0500 Subject: [PATCH 286/527] exclude AESNI option --- Makefile | 1 - Makefile.homebrew | 7 ------- Makefile.linux | 7 ------- Makefile.mingw | 6 ------ Makefile.osx | 6 +----- build/CMakeLists.txt | 12 ------------ daemon/Daemon.cpp | 4 +--- libi2pd/Config.cpp | 6 +++--- libi2pd/Crypto.cpp | 2 +- libi2pd/Crypto.h | 2 +- libi2pd/api.cpp | 4 +--- 11 files changed, 8 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index 3998beb0..016dec97 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,6 @@ DAEMON_SRC_DIR := daemon # import source files lists include filelist.mk -USE_AESNI := $(or $(USE_AESNI),yes) USE_STATIC := $(or $(USE_STATIC),no) USE_UPNP := $(or $(USE_UPNP),no) DEBUG := $(or $(DEBUG),yes) diff --git a/Makefile.homebrew b/Makefile.homebrew index e14ea955..ced8c117 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -30,13 +30,6 @@ ifeq ($(USE_UPNP),yes) INCFLAGS += -I${UPNPROOT}/include endif -ifeq ($(USE_AESNI),yes) -ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that - NEEDED_CXXFLAGS += -maes - DEFINES += -D__AES__ -endif -endif - install: all install -d ${PREFIX}/bin install -m 755 ${I2PD} ${PREFIX}/bin diff --git a/Makefile.linux b/Makefile.linux index 9c3e6895..5dfed6a8 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -51,13 +51,6 @@ ifeq ($(USE_UPNP),yes) DEFINES += -DUSE_UPNP endif -ifeq ($(USE_AESNI),yes) -ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that - NEEDED_CXXFLAGS += -maes - DEFINES += -D__AES__ -endif -endif - install: all install -d ${PREFIX}/bin install -m 755 ${I2PD} ${PREFIX}/bin diff --git a/Makefile.mingw b/Makefile.mingw index fc92e9b0..32d60764 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -42,12 +42,6 @@ ifeq ($(USE_WIN32_APP), yes) DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) endif -ifeq ($(USE_AESNI),yes) - NEEDED_CXXFLAGS += -maes - LDFLAGS += -maes - DEFINES += -D__AES__ -endif - ifeq ($(USE_ASLR),yes) LDFLAGS += -Wl,--nxcompat -Wl,--high-entropy-va -Wl,--dynamicbase,--export-all-symbols endif diff --git a/Makefile.osx b/Makefile.osx index 48eb1a51..c509ea7c 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -25,9 +25,5 @@ endif OSARCH = $(shell uname -p) ifneq ($(OSARCH),powerpc) - ifeq ($(USE_AESNI),yes) - CXXFLAGS += -D__AES__ -maes - else - CXXFLAGS += -msse - endif + CXXFLAGS += -msse endif diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 954f5de9..bc936e18 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -29,7 +29,6 @@ project( ) # configurable options -option(WITH_AESNI "Use AES-NI instructions set" ON) option(WITH_HARDENING "Use hardening compiler flags" OFF) option(WITH_LIBRARY "Build library" ON) option(WITH_BINARY "Build binary" ON) @@ -185,16 +184,6 @@ if(UNIX) endif() endif() -# Note: AES-NI and AVX is available on x86-based CPU's. -# Here also ARM64 implementation, but currently we don't support it. -# MSVC is not supported due to different ASM processing, so we hope OpenSSL has its own checks to run optimized code. -if(WITH_AESNI AND (ARCHITECTURE MATCHES "x86_64" OR ARCHITECTURE MATCHES "i386")) - if(NOT MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes") - endif() - add_definitions(-D__AES__) -endif() - if(WITH_ADDRSANITIZER) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") @@ -335,7 +324,6 @@ message(STATUS "Architecture : ${ARCHITECTURE}") message(STATUS "Compiler flags : ${CMAKE_CXX_FLAGS}") message(STATUS "Install prefix: : ${CMAKE_INSTALL_PREFIX}") message(STATUS "Options:") -message(STATUS " AESNI : ${WITH_AESNI}") message(STATUS " HARDENING : ${WITH_HARDENING}") message(STATUS " LIBRARY : ${WITH_LIBRARY}") message(STATUS " BINARY : ${WITH_BINARY}") diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index b572944f..e2fdf2d4 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -149,12 +149,10 @@ namespace util LogPrint(eLogDebug, "FS: Certificates directory: ", certsdir); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); - bool aesni; i2p::config::GetOption("cpuext.aesni", aesni); - bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt); bool ssu; i2p::config::GetOption("ssu", ssu); if (!ssu && i2p::config::IsDefault ("precomputation.elgamal")) precomputation = false; // we don't elgamal table if no ssu, unless it's specified explicitly - i2p::crypto::InitCrypto (precomputation, aesni, forceCpuExt); + i2p::crypto::InitCrypto (precomputation); i2p::transport::InitAddressFromIface (); // get address4/6 from interfaces diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index dfddeb7b..fc1b2272 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -315,11 +315,11 @@ namespace config { ("persist.addressbook", value()->default_value(true), "Persist full addresses (default: true)") ; - options_description cpuext("CPU encryption extensions options"); + options_description cpuext("CPU encryption extensions options. Deprecated"); cpuext.add_options() - ("cpuext.aesni", bool_switch()->default_value(true), "Use auto detection for AESNI CPU extensions. If false, AESNI will be not used") + ("cpuext.aesni", bool_switch()->default_value(true), "Deprecated option") ("cpuext.avx", bool_switch()->default_value(false), "Deprecated option") - ("cpuext.force", bool_switch()->default_value(false), "Force usage of CPU extensions. Useful when cpuinfo is not available on virtual machines") + ("cpuext.force", bool_switch()->default_value(false), "Deprecated option") ; options_description meshnets("Meshnet transports options"); diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 604c6287..76963a18 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -834,7 +834,7 @@ namespace crypto } }*/ - void InitCrypto (bool precomputation, bool aesni, bool force) + void InitCrypto (bool precomputation) { /* auto numLocks = CRYPTO_num_locks(); for (int i = 0; i < numLocks; i++) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index a996728e..d153ee89 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -221,7 +221,7 @@ namespace crypto void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets) // init and terminate - void InitCrypto (bool precomputation, bool aesni, bool force); + void InitCrypto (bool precomputation); void TerminateCrypto (); } } diff --git a/libi2pd/api.cpp b/libi2pd/api.cpp index 05f962f3..7dc11157 100644 --- a/libi2pd/api.cpp +++ b/libi2pd/api.cpp @@ -37,9 +37,7 @@ namespace api i2p::fs::Init(); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); - bool aesni; i2p::config::GetOption("cpuext.aesni", aesni); - bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt); - i2p::crypto::InitCrypto (precomputation, aesni, forceCpuExt); + i2p::crypto::InitCrypto (precomputation); int netID; i2p::config::GetOption("netid", netID); i2p::context.SetNetID (netID); From f23a7f569beea6003aac8d6c583d7f8be549dc39 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 8 Dec 2024 11:08:17 -0500 Subject: [PATCH 287/527] pass iv to AES Encrypt/Decrypt directly. aes-test added --- libi2pd/Crypto.cpp | 32 ++++++++---------- libi2pd/Crypto.h | 18 ++++------ libi2pd/Garlic.cpp | 12 +++---- libi2pd/Garlic.h | 1 + libi2pd/NTCP2.cpp | 12 +++---- libi2pd/TransitTunnel.cpp | 3 +- libi2pd/TunnelConfig.cpp | 3 +- tests/CMakeLists.txt | 7 ++++ tests/Makefile | 5 ++- tests/test-aes.cpp | 69 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 112 insertions(+), 50 deletions(-) create mode 100644 tests/test-aes.cpp diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 76963a18..794ea324 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -442,9 +442,8 @@ namespace crypto // encrypt CBCEncryption encryption; encryption.SetKey (shared); - encryption.SetIV (iv); encrypted[257] = 0; - encryption.Encrypt (m, 256, encrypted + 258); + encryption.Encrypt (m, 256, iv, encrypted + 258); EC_POINT_free (p); BN_CTX_end (ctx); BN_CTX_free (ctx); @@ -477,8 +476,7 @@ namespace crypto uint8_t m[256]; CBCDecryption decryption; decryption.SetKey (shared); - decryption.SetIV (iv); - decryption.Decrypt (encrypted + 258, 256, m); + decryption.Decrypt (encrypted + 258, 256, iv, m); // verify and copy uint8_t hash[32]; SHA256 (m + 33, 222, hash); @@ -560,7 +558,6 @@ namespace crypto CBCEncryption::CBCEncryption () { m_Ctx = EVP_CIPHER_CTX_new (); - //memset ((uint8_t *)m_LastBlock, 0, 16); } CBCEncryption::~CBCEncryption () @@ -569,10 +566,10 @@ namespace crypto EVP_CIPHER_CTX_free (m_Ctx); } - void CBCEncryption::Encrypt (const uint8_t * in, std::size_t len, uint8_t * out) + void CBCEncryption::Encrypt (const uint8_t * in, size_t len, const uint8_t * iv, uint8_t * out) { // len/16 - EVP_EncryptInit_ex (m_Ctx, EVP_aes_256_cbc(), NULL, m_Key, m_IV); + EVP_EncryptInit_ex (m_Ctx, EVP_aes_256_cbc(), NULL, m_Key, iv); EVP_CIPHER_CTX_set_padding (m_Ctx, 0); int l; EVP_EncryptUpdate (m_Ctx, out, &l, in, len); @@ -582,7 +579,6 @@ namespace crypto CBCDecryption::CBCDecryption () { m_Ctx = EVP_CIPHER_CTX_new (); - //memset ((uint8_t *)m_IV, 0, 16); } CBCDecryption::~CBCDecryption () @@ -591,10 +587,10 @@ namespace crypto EVP_CIPHER_CTX_free (m_Ctx); } - void CBCDecryption::Decrypt (const uint8_t * in, std::size_t len, uint8_t * out) + void CBCDecryption::Decrypt (const uint8_t * in, size_t len, const uint8_t * iv, uint8_t * out) { // len/16 - EVP_DecryptInit_ex (m_Ctx, EVP_aes_256_cbc(), NULL, m_Key, m_IV); + EVP_DecryptInit_ex (m_Ctx, EVP_aes_256_cbc(), NULL, m_Key, iv); EVP_CIPHER_CTX_set_padding (m_Ctx, 0); int l; EVP_DecryptUpdate (m_Ctx, out, &l, in, len); @@ -603,18 +599,18 @@ namespace crypto void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out) { - m_IVEncryption.Encrypt (in, out); // iv - m_LayerEncryption.SetIV (out); - m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data - m_IVEncryption.Encrypt (out, out); // double iv + uint8_t iv[16]; + m_IVEncryption.Encrypt (in, iv); // iv + m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, iv, out + 16); // data + m_IVEncryption.Encrypt (iv, out); // double iv } void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out) { - m_IVDecryption.Decrypt (in, out); // iv - m_LayerDecryption.SetIV (out); - m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data - m_IVDecryption.Decrypt (out, out); // double iv + uint8_t iv[16]; + m_IVDecryption.Decrypt (in, iv); // iv + m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, iv, out + 16); // data + m_IVDecryption.Decrypt (iv, out); // double iv } // AEAD/ChaCha20/Poly1305 diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index d153ee89..1666bfeb 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -93,7 +93,7 @@ namespace crypto ECBEncryption (); ~ECBEncryption (); - void SetKey (const AESKey& key) { m_Key = key; }; + void SetKey (const uint8_t * key) { m_Key = key; }; void Encrypt(const uint8_t * in, uint8_t * out); private: @@ -109,7 +109,7 @@ namespace crypto ECBDecryption (); ~ECBDecryption (); - void SetKey (const AESKey& key) { m_Key = key; }; + void SetKey (const uint8_t * key) { m_Key = key; }; void Decrypt (const uint8_t * in, uint8_t * out); private: @@ -125,15 +125,12 @@ namespace crypto CBCEncryption (); ~CBCEncryption (); - void SetKey (const AESKey& key) { m_Key = key; }; // 32 bytes - void SetIV (const uint8_t * iv) { m_IV = iv; }; // 16 bytes - - void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out); + void SetKey (const uint8_t * key) { m_Key = key; }; // 32 bytes + void Encrypt (const uint8_t * in, size_t len, const uint8_t * iv, uint8_t * out); private: AESKey m_Key; - i2p::data::Tag<16> m_IV; EVP_CIPHER_CTX * m_Ctx; }; @@ -144,15 +141,12 @@ namespace crypto CBCDecryption (); ~CBCDecryption (); - void SetKey (const AESKey& key) { m_Key = key; }; // 32 bytes - void SetIV (const uint8_t * iv) { m_IV = iv; }; // 16 bytes - - void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out); + void SetKey (const uint8_t * key) { m_Key = key; }; // 32 bytes + void Decrypt (const uint8_t * in, size_t len, const uint8_t * iv, uint8_t * out); private: AESKey m_Key; - i2p::data::Tag<16> m_IV; EVP_CIPHER_CTX * m_Ctx; }; diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index c93579e0..83511c26 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -160,7 +160,7 @@ namespace garlic uint8_t iv[32]; // IV is first 16 bytes SHA256(elGamal.preIV, 32, iv); m_Destination->Encrypt ((uint8_t *)&elGamal, buf); - m_Encryption.SetIV (iv); + m_IV = iv; buf += 514; len += 514; } @@ -170,7 +170,7 @@ namespace garlic memcpy (buf, tag, 32); uint8_t iv[32]; // IV is first 16 bytes SHA256(tag, 32, iv); - m_Encryption.SetIV (iv); + m_IV = iv; buf += 32; len += 32; } @@ -210,7 +210,7 @@ namespace garlic size_t rem = blockSize % 16; if (rem) blockSize += (16-rem); //padding - m_Encryption.Encrypt(buf, blockSize, buf); + m_Encryption.Encrypt(buf, blockSize, m_IV, buf); return blockSize; } @@ -514,8 +514,7 @@ namespace garlic { uint8_t iv[32]; // IV is first 16 bytes SHA256(buf, 32, iv); - decryption->SetIV (iv); - decryption->Decrypt (buf + 32, length - 32, buf + 32); + decryption->Decrypt (buf + 32, length - 32, iv, buf + 32); HandleAESBlock (buf + 32, length - 32, decryption, msg->from); found = true; } @@ -533,8 +532,7 @@ namespace garlic auto decryption = std::make_shared(elGamal.sessionKey); uint8_t iv[32]; // IV is first 16 bytes SHA256(elGamal.preIV, 32, iv); - decryption->SetIV (iv); - decryption->Decrypt(buf + 514, length - 514, buf + 514); + 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)) diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 8401f052..b39d5fde 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -205,6 +205,7 @@ namespace garlic std::map > m_UnconfirmedTagsMsgs; // msgID->tags i2p::crypto::CBCEncryption m_Encryption; + i2p::data::Tag<16> m_IV; public: diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 6630a351..d0c6b002 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -120,8 +120,7 @@ namespace transport // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (m_RemoteIdentHash); - encryption.SetIV (m_IV); - encryption.Encrypt (GetPub (), 32, m_SessionRequestBuffer); // X + encryption.Encrypt (GetPub (), 32, m_IV, m_SessionRequestBuffer); // X memcpy (m_IV, m_SessionRequestBuffer + 16, 16); // save last block as IV for SessionCreated // encryption key for next block if (!KDF1Alice ()) return false; @@ -161,8 +160,7 @@ namespace transport // encrypt Y i2p::crypto::CBCEncryption encryption; encryption.SetKey (i2p::context.GetIdentHash ()); - encryption.SetIV (m_IV); - encryption.Encrypt (GetPub (), 32, m_SessionCreatedBuffer); // Y + encryption.Encrypt (GetPub (), 32, m_IV, m_SessionCreatedBuffer); // Y // encryption key for next block (m_K) if (!KDF2Bob ()) return false; uint8_t options[16]; @@ -208,8 +206,7 @@ namespace transport // decrypt X i2p::crypto::CBCDecryption decryption; decryption.SetKey (i2p::context.GetIdentHash ()); - decryption.SetIV (i2p::context.GetNTCP2IV ()); - decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ()); + decryption.Decrypt (m_SessionRequestBuffer, 32, i2p::context.GetNTCP2IV (), GetRemotePub ()); memcpy (m_IV, m_SessionRequestBuffer + 16, 16); // save last block as IV for SessionCreated // decryption key for next block if (!KDF1Bob ()) @@ -268,8 +265,7 @@ namespace transport // decrypt Y i2p::crypto::CBCDecryption decryption; decryption.SetKey (m_RemoteIdentHash); - decryption.SetIV (m_IV); - decryption.Decrypt (m_SessionCreatedBuffer, 32, GetRemotePub ()); + decryption.Decrypt (m_SessionCreatedBuffer, 32, m_IV, GetRemotePub ()); // decryption key for next block (m_K) if (!KDF2Alice ()) { diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index 8284dc14..883034fe 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -434,8 +434,7 @@ namespace tunnel else { encryption.SetKey (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET); - encryption.SetIV (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET); - encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply); + encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET, reply); } } return true; diff --git a/libi2pd/TunnelConfig.cpp b/libi2pd/TunnelConfig.cpp index e19b515d..fe0e8573 100644 --- a/libi2pd/TunnelConfig.cpp +++ b/libi2pd/TunnelConfig.cpp @@ -79,8 +79,7 @@ namespace tunnel uint8_t * record = records + index*TUNNEL_BUILD_RECORD_SIZE; i2p::crypto::CBCDecryption decryption; decryption.SetKey (replyKey); - decryption.SetIV (replyIV); - decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record); + decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, replyIV, record); } void ECIESTunnelHopConfig::EncryptECIES (const uint8_t * plainText, size_t len, uint8_t * encrypted) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6353a683..fb03d434 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -65,6 +65,10 @@ set(test-eddsa_SRCS test-eddsa.cpp ) +set(test-aes_SRCS + test-aes.cpp +) + add_executable(test-http-merge_chunked ${test-http-merge_chunked_SRCS}) add_executable(test-http-req ${test-http-req_SRCS}) add_executable(test-http-res ${test-http-res_SRCS}) @@ -77,6 +81,7 @@ add_executable(test-aeadchacha20poly1305 ${test-aeadchacha20poly1305_SRCS}) add_executable(test-blinding ${test-blinding_SRCS}) add_executable(test-elligator ${test-elligator_SRCS}) add_executable(test-eddsa ${test-eddsa_SRCS}) +add_executable(test-aes ${test-aes_SRCS}) set(LIBS libi2pd @@ -101,6 +106,7 @@ target_link_libraries(test-aeadchacha20poly1305 ${LIBS}) target_link_libraries(test-blinding ${LIBS}) target_link_libraries(test-elligator ${LIBS}) target_link_libraries(test-eddsa ${LIBS}) +target_link_libraries(test-aes ${LIBS}) add_test(test-http-merge_chunked ${TEST_PATH}/test-http-merge_chunked) add_test(test-http-req ${TEST_PATH}/test-http-req) @@ -114,3 +120,4 @@ add_test(test-aeadchacha20poly1305 ${TEST_PATH}/test-aeadchacha20poly1305) add_test(test-blinding ${TEST_PATH}/test-blinding) add_test(test-elligator ${TEST_PATH}/test-elligator) add_test(test-eddsa ${TEST_PATH}/test-eddsa) +add_test(test-aes ${TEST_PATH}/test-aes) diff --git a/tests/Makefile b/tests/Makefile index 51a11dfe..b020427d 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -8,7 +8,7 @@ LIBI2PD = ../libi2pd.a TESTS = \ test-http-merge_chunked test-http-req test-http-res test-http-url test-http-url_decode \ test-gost test-gost-sig test-base-64 test-aeadchacha20poly1305 test-blinding \ - test-elligator test-eddsa + test-elligator test-eddsa test-aes ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS))) CXXFLAGS += -DWIN32_LEAN_AND_MEAN @@ -56,6 +56,9 @@ test-elligator: test-elligator.cpp $(LIBI2PD) test-eddsa: test-eddsa.cpp $(LIBI2PD) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) +test-aes: test-aes.cpp $(LIBI2PD) + $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) + run: $(TESTS) @for TEST in $(TESTS); do echo Running $$TEST; ./$$TEST ; done diff --git a/tests/test-aes.cpp b/tests/test-aes.cpp new file mode 100644 index 00000000..15f4de1e --- /dev/null +++ b/tests/test-aes.cpp @@ -0,0 +1,69 @@ +#include +#include +#include + +#include "Crypto.h" + +uint8_t ecb_key1[32] = +{ + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 +}; + +uint8_t ecb_plain1[16] = +{ + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a +}; + +uint8_t ecb_cipher1[16] = +{ + 0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8 +}; + +uint8_t cbc_key1[32] = +{ + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 +}; + +uint8_t cbc_iv1[16] = +{ + 0xF5, 0x8C, 0x4C, 0x04, 0xD6, 0xE5, 0xF1, 0xBA, 0x77, 0x9E, 0xAB, 0xFB, 0x5F, 0x7B, 0xFB, 0xD6 +}; + +uint8_t cbc_plain1[16] = +{ + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 +}; + +uint8_t cbc_cipher1[16] = +{ + 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d +}; + +int main () +{ + // ECB encrypt test1 + i2p::crypto::ECBEncryption ecbencryption; + ecbencryption.SetKey (ecb_key1); + uint8_t out[16]; + ecbencryption.Encrypt (ecb_plain1, out); + assert (memcmp (ecb_cipher1, out, 16) == 0); + + // ECB decrypt test1 + i2p::crypto::ECBDecryption ecbdecryption; + ecbdecryption.SetKey (ecb_key1); + ecbdecryption.Decrypt (ecb_cipher1, out); + assert (memcmp (ecb_plain1, out, 16) == 0); + // CBC encrypt test + i2p::crypto::CBCEncryption cbcencryption; + cbcencryption.SetKey (cbc_key1); + cbcencryption.Encrypt (cbc_plain1, 16, cbc_iv1, out); + assert (memcmp (cbc_cipher1, out, 16) == 0); + // CBC decrypt test + i2p::crypto::CBCDecryption cbcdecryption; + cbcdecryption.SetKey (cbc_key1); + cbcdecryption.Decrypt (cbc_cipher1, 16, cbc_iv1, out); + assert (memcmp (cbc_plain1, out, 16) == 0); +} + From 1a748aebf12b30ff961adf6adb0143a95fbf560d Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 8 Dec 2024 11:33:30 -0500 Subject: [PATCH 288/527] removed depereated section from config --- contrib/i2pd.conf | 6 ------ 1 file changed, 6 deletions(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index be4a6719..1d71b180 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -277,9 +277,3 @@ verify = true ## Save full addresses on disk (default: true) # addressbook = true -[cpuext] -## Use CPU AES-NI instructions set when work with cryptography when available (default: true) -# aesni = true -## Force usage of CPU instructions set, even if they not found (default: false) -## DO NOT TOUCH that option if you really don't know what are you doing! -# force = false From cdd528c51f1c33c0c6772fc360f4c42a460cd12d Mon Sep 17 00:00:00 2001 From: r4sas Date: Sun, 8 Dec 2024 23:50:16 +0300 Subject: [PATCH 289/527] [gha] disable winxp build Signed-off-by: r4sas --- .github/workflows/build-windows.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index ed7147ff..e49a86d1 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -110,6 +110,7 @@ jobs: build-xp: name: XP runs-on: windows-latest + if: false strategy: fail-fast: false From 946e5235545ca7d51439c2cbb767403e691945f1 Mon Sep 17 00:00:00 2001 From: Vort Date: Mon, 9 Dec 2024 02:48:07 +0200 Subject: [PATCH 290/527] fix Windows XP build --- .github/workflows/build-windows.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index e49a86d1..e32fdccb 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -110,7 +110,6 @@ jobs: build-xp: name: XP runs-on: windows-latest - if: false strategy: fail-fast: false @@ -231,8 +230,10 @@ jobs: run: | cd MINGW-packages/mingw-w64-boost MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck + - name: Remove boost packages + run: pacman --noconfirm -R mingw-w64-i686-boost mingw-w64-i686-boost-libs - name: Install boost package - run: pacman --noconfirm -U --overwrite MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst + run: pacman --noconfirm -U MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst # Building i2pd - name: Build application From 3534b9c499f3d0e3ae699232f6a21de5285a49cb Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 9 Dec 2024 20:59:59 -0500 Subject: [PATCH 291/527] don't create EVP_CIPHER_CTX for each AEAD/Chacha20/Poly1305 message --- libi2pd/Crypto.cpp | 64 +++++++++++++++++++++++++++++++++-------- libi2pd/Crypto.h | 36 +++++++++++++++++++++-- libi2pd/NTCP2.cpp | 18 ++++++++++-- libi2pd/NTCP2.h | 8 ++++++ libi2pd/SSU2.cpp | 12 ++++++++ libi2pd/SSU2.h | 6 ++++ libi2pd/SSU2Session.cpp | 14 ++++----- 7 files changed, 134 insertions(+), 24 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 794ea324..1b663e41 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -615,13 +615,13 @@ namespace crypto // AEAD/ChaCha20/Poly1305 - bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt) + static bool AEADChaCha20Poly1305 (EVP_CIPHER_CTX * ctx, const uint8_t * msg, size_t msgLen, + const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt) { - if (len < msgLen) return false; + if (!ctx || len < msgLen) return false; if (encrypt && len < msgLen + 16) return false; bool ret = true; int outlen = 0; - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); if (encrypt) { EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); @@ -651,26 +651,66 @@ namespace crypto EVP_DecryptUpdate(ctx, buf, &outlen, msg, msgLen); ret = EVP_DecryptFinal_ex(ctx, buf + outlen, &outlen) > 0; } + return ret; + } + bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt) + { + EVP_CIPHER_CTX * ctx = EVP_CIPHER_CTX_new (); + auto ret = AEADChaCha20Poly1305 (ctx, msg, msgLen, ad, adLen, key, nonce, buf, len, encrypt); EVP_CIPHER_CTX_free (ctx); return ret; } - void AEADChaCha20Poly1305Encrypt (const std::vector >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac) + AEADChaCha20Poly1305Encryptor::AEADChaCha20Poly1305Encryptor () + { + m_Ctx = EVP_CIPHER_CTX_new (); + } + + AEADChaCha20Poly1305Encryptor::~AEADChaCha20Poly1305Encryptor () + { + if (m_Ctx) + EVP_CIPHER_CTX_free (m_Ctx); + } + + bool AEADChaCha20Poly1305Encryptor::Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len) + { + return AEADChaCha20Poly1305 (m_Ctx, msg, msgLen, ad, adLen, key, nonce, buf, len, true); + } + + void AEADChaCha20Poly1305Encryptor::Encrypt (const std::vector >& bufs, + const uint8_t * key, const uint8_t * nonce, uint8_t * mac) { if (bufs.empty ()) return; int outlen = 0; - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); - EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); - EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0); - EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce); + EVP_EncryptInit_ex(m_Ctx, EVP_chacha20_poly1305(), 0, 0, 0); + EVP_CIPHER_CTX_ctrl(m_Ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0); + EVP_EncryptInit_ex(m_Ctx, NULL, NULL, key, nonce); for (const auto& it: bufs) - EVP_EncryptUpdate(ctx, it.first, &outlen, it.first, it.second); - EVP_EncryptFinal_ex(ctx, NULL, &outlen); - EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac); - EVP_CIPHER_CTX_free (ctx); + EVP_EncryptUpdate(m_Ctx, it.first, &outlen, it.first, it.second); + EVP_EncryptFinal_ex(m_Ctx, NULL, &outlen); + EVP_CIPHER_CTX_ctrl(m_Ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac); + } + + AEADChaCha20Poly1305Decryptor::AEADChaCha20Poly1305Decryptor () + { + m_Ctx = EVP_CIPHER_CTX_new (); } + + AEADChaCha20Poly1305Decryptor::~AEADChaCha20Poly1305Decryptor () + { + if (m_Ctx) + EVP_CIPHER_CTX_free (m_Ctx); + } + bool AEADChaCha20Poly1305Decryptor::Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len) + { + return AEADChaCha20Poly1305 (m_Ctx, msg, msgLen, ad, adLen, key, nonce, buf, len, false); + } + void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 1666bfeb..75b259a5 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -187,10 +187,42 @@ namespace crypto }; // AEAD/ChaCha20/Poly1305 - bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag - void AEADChaCha20Poly1305Encrypt (const std::vector >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad + class AEADChaCha20Poly1305Encryptor + { + public: + AEADChaCha20Poly1305Encryptor (); + ~AEADChaCha20Poly1305Encryptor (); + + bool Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); // msgLen is len without tag + + void Encrypt (const std::vector >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad + + private: + + EVP_CIPHER_CTX * m_Ctx; + }; + + class AEADChaCha20Poly1305Decryptor + { + public: + + AEADChaCha20Poly1305Decryptor (); + ~AEADChaCha20Poly1305Decryptor (); + + bool Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); // msgLen is len without tag + + private: + + EVP_CIPHER_CTX * m_Ctx; + }; + + bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag + // ChaCha20 void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index d0c6b002..76b056cf 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -991,7 +991,7 @@ namespace transport i2p::transport::transports.UpdateReceivedBytes (bytes_transferred + 2); uint8_t nonce[12]; CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++; - if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false)) + if (m_Server.AEADChaCha20Poly1305Decrypt (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen)) { LogPrint (eLogDebug, "NTCP2: Received message decrypted"); ProcessNextFrame (m_NextReceivedBuffer, m_NextReceivedLen-16); @@ -1180,7 +1180,7 @@ namespace transport } uint8_t nonce[12]; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; - i2p::crypto::AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers + m_Server.AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers SetNextSentFrameLength (totalLen + 16, first->GetNTCP2Header () - 5); // frame length right before first block // send buffers @@ -1211,7 +1211,7 @@ namespace transport // encrypt uint8_t nonce[12]; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; - i2p::crypto::AEADChaCha20Poly1305Encrypt ({ {m_NextSendBuffer + 2, payloadLen} }, m_SendKey, nonce, m_NextSendBuffer + payloadLen + 2); + m_Server.AEADChaCha20Poly1305Encrypt ({ {m_NextSendBuffer + 2, payloadLen} }, m_SendKey, nonce, m_NextSendBuffer + payloadLen + 2); SetNextSentFrameLength (payloadLen + 16, m_NextSendBuffer); // send m_IsSending = true; @@ -1980,5 +1980,17 @@ namespace transport else m_Address4 = addr; } + + void NTCP2Server::AEADChaCha20Poly1305Encrypt (const std::vector >& bufs, + const uint8_t * key, const uint8_t * nonce, uint8_t * mac) + { + return m_Encryptor.Encrypt (bufs, key, nonce, mac); + } + + bool NTCP2Server::AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen, + const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len) + { + return m_Decryptor.Decrypt (msg, msgLen, ad, adLen, key, nonce, buf, len); + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 108c58f6..5df4de6e 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -272,6 +272,11 @@ namespace transport auto& GetService () { return GetIOService (); }; auto& GetEstablisherService () { return m_EstablisherService.GetService (); }; std::mt19937& GetRng () { return m_Rng; }; + void AEADChaCha20Poly1305Encrypt (const std::vector >& bufs, + const uint8_t * key, const uint8_t * nonce, uint8_t * mac); + bool AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); + bool AddNTCP2Session (std::shared_ptr session, bool incoming = false); void RemoveNTCP2Session (std::shared_ptr session); @@ -309,9 +314,12 @@ namespace transport uint16_t m_ProxyPort; boost::asio::ip::tcp::resolver m_Resolver; std::unique_ptr m_ProxyEndpoint; + std::shared_ptr m_Address4, m_Address6, m_YggdrasilAddress; std::mt19937 m_Rng; EstablisherService m_EstablisherService; + i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor; + i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor; public: diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index f53f9dd0..cbd6d38e 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1516,6 +1516,18 @@ namespace transport } } + bool SSU2Server::AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, + const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len) + { + return m_Encryptor.Encrypt (msg, msgLen, ad, adLen, key, nonce, buf, len); + } + + bool SSU2Server::AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen, + const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len) + { + return m_Decryptor.Decrypt (msg, msgLen, ad, adLen, key, nonce, buf, len); + } + void SSU2Server::SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to) { diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 715e72ab..d6ff415b 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -82,6 +82,10 @@ namespace transport bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max = true); void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts); std::mt19937& GetRng () { return m_Rng; } + bool AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); + bool AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; } bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; void AdjustTimeOffset (int64_t offset, std::shared_ptr from); @@ -200,6 +204,8 @@ namespace transport std::unordered_map, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp) std::list m_ReceivedPacketsQueue; mutable std::mutex m_ReceivedPacketsQueueMutex; + i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor; + i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor; // proxy bool m_IsThroughProxy; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 96f38217..4196e785 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -349,7 +349,7 @@ namespace transport void SSU2Session::Done () { - m_Server.GetService ().post (std::bind (&SSU2Session::Terminate, shared_from_this ())); + boost::asio::post (m_Server.GetService (), std::bind (&SSU2Session::Terminate, shared_from_this ())); } void SSU2Session::SendLocalRouterInfo (bool update) @@ -357,7 +357,7 @@ namespace transport if (update || !IsOutgoing ()) { auto s = shared_from_this (); - m_Server.GetService ().post ([s]() + boost::asio::post (m_Server.GetService (), [s]() { if (!s->IsEstablished ()) return; uint8_t payload[SSU2_MAX_PACKET_SIZE]; @@ -389,7 +389,7 @@ namespace transport m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs); } if (empty) - m_Server.GetService ().post (std::bind (&SSU2Session::PostI2NPMessages, shared_from_this ())); + boost::asio::post (m_Server.GetService (), std::bind (&SSU2Session::PostI2NPMessages, shared_from_this ())); } void SSU2Session::PostI2NPMessages () @@ -1455,7 +1455,7 @@ namespace transport uint8_t nonce[12]; CreateNonce (m_SendPacketNum, nonce); uint8_t payload[SSU2_MAX_PACKET_SIZE]; - i2p::crypto::AEADChaCha20Poly1305 (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MAX_PACKET_SIZE, true); + m_Server.AEADChaCha20Poly1305Encrypt (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MAX_PACKET_SIZE); header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (len - 8)); header.ll[1] ^= CreateHeaderMask (m_KeyDataSend + 32, payload + (len + 4)); m_Server.Send (header.buf, 16, payload, len + 16, m_RemoteEndpoint); @@ -1495,8 +1495,8 @@ namespace transport uint32_t packetNum = be32toh (header.h.packetNum); uint8_t nonce[12]; CreateNonce (packetNum, nonce); - if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 16, payloadSize, header.buf, 16, - m_KeyDataReceive, nonce, payload, payloadSize, false)) + if (!m_Server.AEADChaCha20Poly1305Decrypt (buf + 16, payloadSize, header.buf, 16, + m_KeyDataReceive, nonce, payload, payloadSize)) { LogPrint (eLogWarning, "SSU2: Data AEAD verification failed "); return; @@ -2052,7 +2052,7 @@ namespace transport auto vec = std::make_shared >(len); memcpy (vec->data (), buf, len); auto s = shared_from_this (); - m_Server.GetService ().post ([s, vec, attempts]() + boost::asio::post (m_Server.GetService (), [s, vec, attempts]() { LogPrint (eLogDebug, "SSU2: RelayIntro attempt ", attempts + 1); s->HandleRelayIntro (vec->data (), vec->size (), attempts + 1); From dcbe6cfaf24d0aaa5d9c4b808f3dbe1f915b9298 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 10 Dec 2024 17:49:11 -0500 Subject: [PATCH 292/527] Update RTO calculation and windows reseting algorithm --- libi2pd/Streaming.cpp | 75 ++++++++++++++++++++++++++++--------------- libi2pd/Streaming.h | 4 +-- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 70c59067..3d71e8d5 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -78,9 +78,9 @@ namespace stream m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), - m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), + m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_WindowSizeTail (0), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_RemoteLeaseChangeTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { @@ -106,8 +106,8 @@ namespace stream m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), - m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_RemoteLeaseChangeTime (0), + m_PrevRTTSample (INITIAL_RTT), m_WindowSizeTail (0), m_Jitter (0), m_MinPacingTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { @@ -366,6 +366,7 @@ namespace stream { if (!m_IsWinDropped) { + LogPrint (eLogDebug, "Streaming: Client choked, set min. window size"); m_WindowDropTargetSize = MIN_WINDOW_SIZE; m_LastWindowDropSize = 0; m_WindowIncCounter = 0; @@ -537,12 +538,21 @@ namespace stream m_SentPackets.erase (it++); m_LocalDestination.DeletePacket (sentPacket); acknowledged = true; - if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK) + if (m_WindowIncCounter < MAX_WINDOW_SIZE && !m_IsFirstACK && !m_IsWinDropped) incCounter++; } else break; } + if (m_LastACKRecieveTime) + { + uint64_t interval = ts - m_LastACKRecieveTime; + if (m_ACKRecieveInterval) + m_ACKRecieveInterval = (m_ACKRecieveInterval + interval) / 2; + else + m_ACKRecieveInterval = interval; + } + m_LastACKRecieveTime = ts; if (rttSample != INT_MAX) { if (m_IsFirstRttSample && !m_IsFirstACK) @@ -589,12 +599,15 @@ namespace stream // // delay-based CC if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection + { + LogPrint (eLogDebug, "Streaming: Congestion detected, reduce window size"); ProcessWindowDrop (); + } UpdatePacingTime (); m_PrevRTTSample = rttSample; bool wasInitial = m_RTO == INITIAL_RTO; - m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter)); // TODO: implement it better + m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter + m_ACKRecieveInterval)); // TODO: implement it better if (wasInitial) ScheduleResend (); @@ -604,20 +617,10 @@ namespace stream m_IsFirstRttSample = true; m_IsWinDropped = false; } - if (m_WindowDropTargetSize && m_WindowSize <= m_WindowDropTargetSize) + if (m_WindowDropTargetSize && int(m_SentPackets.size ()) <= m_WindowDropTargetSize) { + m_WindowSize = m_WindowDropTargetSize; m_WindowDropTargetSize = 0; - m_DropWindowDelaySequenceNumber = m_SequenceNumber; - } - if (acknowledged && m_WindowDropTargetSize && m_WindowSize > m_WindowDropTargetSize) - { - m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter)); // we assume that the next rtt sample may be much larger than the current - m_IsResendNeeded = true; - m_WindowSize = m_SentPackets.size () + 1; // if there are no packets to resend, just send one regular packet - if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; - if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; - m_WindowIncCounter = 0; - UpdatePacingTime (); } if (acknowledged || m_IsNAcked) { @@ -626,12 +629,14 @@ namespace stream if (m_SendBuffer.IsEmpty () && m_SentPackets.size () > 0) // tail loss { m_IsResendNeeded = true; - m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter)); // to prevent spurious retransmit + m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter + m_ACKRecieveInterval)); // to prevent spurious retransmit } if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ()) { m_ResendTimer.cancel (); m_SendTimer.cancel (); + m_LastACKRecieveTime = 0; + m_ACKRecieveInterval = m_AckDelay; } if (acknowledged && m_IsFirstACK) { @@ -1158,6 +1163,7 @@ namespace stream } if (m_RemoteLeaseChangeTime && m_IsRemoteLeaseChangeInProgress && ts > m_RemoteLeaseChangeTime + INITIAL_RTO) { + LogPrint (eLogDebug, "Streaming: RemoteLease changed, set initial window size"); CancelRemoteLeaseChange (); m_CurrentRemoteLease = m_NextRemoteLease; HalveWindowSize (); @@ -1305,6 +1311,11 @@ namespace stream } UpdatePacingTime (); } + else if (m_WindowIncCounter && m_WindowSize == MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) + { + m_WindowSizeTail = m_WindowSizeTail + m_WindowIncCounter; + if (m_WindowSizeTail > MAX_WINDOW_SIZE) m_WindowSizeTail = MAX_WINDOW_SIZE; + } if (m_IsNAcked) ResendPacket (); else if (m_IsResendNeeded) // resend packets @@ -1409,7 +1420,10 @@ namespace stream { // loss-based CC if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED) + { + LogPrint (eLogDebug, "Streaming: Packet loss, reduce window size"); ProcessWindowDrop (); + } } else if (m_IsTimeOutResend) { @@ -1422,6 +1436,8 @@ namespace stream m_IsFirstRttSample = true; m_DropWindowDelaySequenceNumber = 0; m_IsFirstACK = true; + m_LastACKRecieveTime = 0; + m_ACKRecieveInterval = m_AckDelay; UpdatePacingTime (); if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); if (m_NumResendAttempts & 1) @@ -1585,6 +1601,7 @@ namespace stream } if (isLeaseChanged && !m_IsRemoteLeaseChangeInProgress) { + LogPrint (eLogDebug, "Streaming: RemoteLease changed, set initial window size"); HalveWindowSize (); } } @@ -1601,7 +1618,10 @@ namespace stream void Stream::UpdatePacingTime () { - m_PacingTime = std::round (m_RTT*1000/m_WindowSize); + if (m_WindowDropTargetSize) + m_PacingTime = std::round (m_RTT*1000/m_WindowDropTargetSize); + else + m_PacingTime = std::round (m_RTT*1000/m_WindowSize); if (m_MinPacingTime && m_PacingTime < m_MinPacingTime) m_PacingTime = m_MinPacingTime; } @@ -1609,18 +1629,20 @@ namespace stream void Stream::ProcessWindowDrop () { if (m_WindowSize > m_LastWindowDropSize) - m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2; + { + m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize + m_WindowSizeTail) / 2; + if (m_LastWindowDropSize > MAX_WINDOW_SIZE) m_LastWindowDropSize = MAX_WINDOW_SIZE; + } else m_LastWindowDropSize = m_WindowSize; m_WindowDropTargetSize = m_LastWindowDropSize - (m_LastWindowDropSize / 4); // -25%; - if (m_WindowDropTargetSize < MIN_WINDOW_SIZE + 1) - m_WindowDropTargetSize = MIN_WINDOW_SIZE + 1; - m_WindowSize = m_SentPackets.size (); // stop sending now - if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; + if (m_WindowDropTargetSize < MIN_WINDOW_SIZE) + m_WindowDropTargetSize = MIN_WINDOW_SIZE; m_WindowIncCounter = 0; // disable window growth - m_DropWindowDelaySequenceNumber = m_SequenceNumber; + m_DropWindowDelaySequenceNumber = m_SequenceNumber + int(m_WindowDropTargetSize); m_IsFirstACK = true; // ignore first RTT sample m_IsWinDropped = true; // don't drop window twice + m_WindowSizeTail = 0; UpdatePacingTime (); } @@ -1638,6 +1660,7 @@ namespace stream m_WindowIncCounter = 0; m_IsFirstRttSample = true; m_IsFirstACK = true; + m_WindowSizeTail = 0; UpdatePacingTime (); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 71450b2b..a9e8a404 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -295,10 +295,10 @@ namespace stream SendBufferQueue m_SendBuffer; double m_RTT, m_SlowRTT, m_SlowRTT2; float m_WindowSize, m_LastWindowDropSize, m_WindowDropTargetSize; - int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; + int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample, m_WindowSizeTail; double m_Jitter; uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, // microseconds - m_LastSendTime, m_RemoteLeaseChangeTime; // milliseconds + m_LastSendTime, m_LastACKRecieveTime, m_ACKRecieveInterval, m_RemoteLeaseChangeTime; // milliseconds uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed int m_NumResendAttempts, m_NumPacketsToSend; size_t m_MTU; From 73ba1afc20ad76eb7c5454ae592d7b59127c1426 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 11 Dec 2024 18:55:30 -0500 Subject: [PATCH 293/527] don't create EVP_CIPHER_CTX for each AEAD/Chacha20/Poly1305 message --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 50 ++++++++++++----------- libi2pd/Garlic.cpp | 12 ++++++ libi2pd/Garlic.h | 10 ++++- 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index ffd47a31..0fb85378 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -725,6 +725,8 @@ namespace garlic bool ECIESX25519AEADRatchetSession::NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { + auto owner = GetOwner (); + if (!owner) return false; uint8_t nonce[12]; auto index = m_SendTagset->GetNextIndex (); CreateNonce (index, nonce); // tag's index @@ -732,8 +734,7 @@ namespace garlic if (!tag) { LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for send tagset"); - if (GetOwner ()) - GetOwner ()->RemoveECIESx25519Session (m_RemoteStaticKey); + owner->RemoveECIESx25519Session (m_RemoteStaticKey); return false; } memcpy (out, &tag, 8); @@ -741,7 +742,7 @@ namespace garlic // ciphertext = ENCRYPT(k, n, payload, ad) uint8_t key[32]; m_SendTagset->GetSymmKey (index, key); - if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, out, 8, key, nonce, out + 8, outLen - 8, true)) // encrypt + if (!owner->AEADChaCha20Poly1305Encrypt (payload, len, out, 8, key, nonce, out + 8, outLen - 8)) { LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); return false; @@ -760,34 +761,35 @@ namespace garlic uint8_t * payload = buf + 8; uint8_t key[32]; receiveTagset->GetSymmKey (index, key); - if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 16, buf, 8, key, nonce, payload, len - 16, false)) // decrypt + auto owner = GetOwner (); + if (!owner) return true; // drop message + + if (!owner->AEADChaCha20Poly1305Decrypt (payload, len - 16, buf, 8, key, nonce, payload, len - 16)) { LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed"); return false; } HandlePayload (payload, len - 16, receiveTagset, index); - if (GetOwner ()) + + int moreTags = 0; + if (owner->GetNumRatchetInboundTags () > 0) // override in settings? { - int moreTags = 0; - if (GetOwner ()->GetNumRatchetInboundTags () > 0) // override in settings? - { - if (receiveTagset->GetNextIndex () - index < GetOwner ()->GetNumRatchetInboundTags ()/2) - moreTags = GetOwner ()->GetNumRatchetInboundTags (); - index -= GetOwner ()->GetNumRatchetInboundTags (); // trim behind - } - else - { - moreTags = (receiveTagset->GetTagSetID () > 0) ? ECIESX25519_MAX_NUM_GENERATED_TAGS : // for non first tagset - (ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 1)); // N/2 - if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS; - moreTags -= (receiveTagset->GetNextIndex () - index); - index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind - } - if (moreTags > 0) - GenerateMoreReceiveTags (receiveTagset, moreTags); - if (index > 0) - receiveTagset->SetTrimBehind (index); + if (receiveTagset->GetNextIndex () - index < owner->GetNumRatchetInboundTags ()/2) + moreTags = owner->GetNumRatchetInboundTags (); + index -= owner->GetNumRatchetInboundTags (); // trim behind } + else + { + moreTags = (receiveTagset->GetTagSetID () > 0) ? ECIESX25519_MAX_NUM_GENERATED_TAGS : // for non first tagset + (ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 1)); // N/2 + if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS; + moreTags -= (receiveTagset->GetNextIndex () - index); + index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind + } + if (moreTags > 0) + GenerateMoreReceiveTags (receiveTagset, moreTags); + if (index > 0) + receiveTagset->SetTrimBehind (index); return true; } diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 83511c26..89737db0 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -1103,5 +1103,17 @@ namespace garlic m_PayloadBuffer = new uint8_t[I2NP_MAX_MESSAGE_SIZE]; return m_PayloadBuffer; } + + bool GarlicDestination::AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len) + { + return m_Encryptor.Encrypt (msg, msgLen, ad, adLen, key, nonce, buf, len); + } + + bool GarlicDestination::AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len) + { + return m_Decryptor.Decrypt (msg, msgLen, ad, adLen, key, nonce, buf, len); + } } } diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index b39d5fde..5baeeb99 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -242,6 +242,11 @@ namespace garlic void RemoveDeliveryStatusSession (uint32_t msgID); std::shared_ptr WrapMessageForRouter (std::shared_ptr router, std::shared_ptr msg); + + bool AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); + bool AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, + const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag void AddECIESx25519Key (const uint8_t * key, uint64_t tag); // one tag @@ -295,7 +300,10 @@ namespace garlic // DeliveryStatus std::mutex m_DeliveryStatusSessionsMutex; std::unordered_map m_DeliveryStatusSessions; // msgID -> session - + // encryption + i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor; + i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor; + public: // for HTTP only From cec68a24474e77e984ce4dbc3aaa3a6550bffb09 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 11 Dec 2024 21:33:16 -0500 Subject: [PATCH 294/527] rollback --- libi2pd/Streaming.cpp | 75 +++++++++++++++---------------------------- libi2pd/Streaming.h | 4 +-- 2 files changed, 28 insertions(+), 51 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 3d71e8d5..70c59067 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -78,9 +78,9 @@ namespace stream m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), - m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_WindowSizeTail (0), + m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_RemoteLeaseChangeTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { @@ -106,8 +106,8 @@ namespace stream m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), - m_PrevRTTSample (INITIAL_RTT), m_WindowSizeTail (0), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0), + m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_RemoteLeaseChangeTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { @@ -366,7 +366,6 @@ namespace stream { if (!m_IsWinDropped) { - LogPrint (eLogDebug, "Streaming: Client choked, set min. window size"); m_WindowDropTargetSize = MIN_WINDOW_SIZE; m_LastWindowDropSize = 0; m_WindowIncCounter = 0; @@ -538,21 +537,12 @@ namespace stream m_SentPackets.erase (it++); m_LocalDestination.DeletePacket (sentPacket); acknowledged = true; - if (m_WindowIncCounter < MAX_WINDOW_SIZE && !m_IsFirstACK && !m_IsWinDropped) + if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK) incCounter++; } else break; } - if (m_LastACKRecieveTime) - { - uint64_t interval = ts - m_LastACKRecieveTime; - if (m_ACKRecieveInterval) - m_ACKRecieveInterval = (m_ACKRecieveInterval + interval) / 2; - else - m_ACKRecieveInterval = interval; - } - m_LastACKRecieveTime = ts; if (rttSample != INT_MAX) { if (m_IsFirstRttSample && !m_IsFirstACK) @@ -599,15 +589,12 @@ namespace stream // // delay-based CC if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection - { - LogPrint (eLogDebug, "Streaming: Congestion detected, reduce window size"); ProcessWindowDrop (); - } UpdatePacingTime (); m_PrevRTTSample = rttSample; bool wasInitial = m_RTO == INITIAL_RTO; - m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter + m_ACKRecieveInterval)); // TODO: implement it better + m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter)); // TODO: implement it better if (wasInitial) ScheduleResend (); @@ -617,10 +604,20 @@ namespace stream m_IsFirstRttSample = true; m_IsWinDropped = false; } - if (m_WindowDropTargetSize && int(m_SentPackets.size ()) <= m_WindowDropTargetSize) + if (m_WindowDropTargetSize && m_WindowSize <= m_WindowDropTargetSize) { - m_WindowSize = m_WindowDropTargetSize; m_WindowDropTargetSize = 0; + m_DropWindowDelaySequenceNumber = m_SequenceNumber; + } + if (acknowledged && m_WindowDropTargetSize && m_WindowSize > m_WindowDropTargetSize) + { + m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter)); // we assume that the next rtt sample may be much larger than the current + m_IsResendNeeded = true; + m_WindowSize = m_SentPackets.size () + 1; // if there are no packets to resend, just send one regular packet + if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; + if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; + m_WindowIncCounter = 0; + UpdatePacingTime (); } if (acknowledged || m_IsNAcked) { @@ -629,14 +626,12 @@ namespace stream if (m_SendBuffer.IsEmpty () && m_SentPackets.size () > 0) // tail loss { m_IsResendNeeded = true; - m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter + m_ACKRecieveInterval)); // to prevent spurious retransmit + m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter)); // to prevent spurious retransmit } if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ()) { m_ResendTimer.cancel (); m_SendTimer.cancel (); - m_LastACKRecieveTime = 0; - m_ACKRecieveInterval = m_AckDelay; } if (acknowledged && m_IsFirstACK) { @@ -1163,7 +1158,6 @@ namespace stream } if (m_RemoteLeaseChangeTime && m_IsRemoteLeaseChangeInProgress && ts > m_RemoteLeaseChangeTime + INITIAL_RTO) { - LogPrint (eLogDebug, "Streaming: RemoteLease changed, set initial window size"); CancelRemoteLeaseChange (); m_CurrentRemoteLease = m_NextRemoteLease; HalveWindowSize (); @@ -1311,11 +1305,6 @@ namespace stream } UpdatePacingTime (); } - else if (m_WindowIncCounter && m_WindowSize == MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) - { - m_WindowSizeTail = m_WindowSizeTail + m_WindowIncCounter; - if (m_WindowSizeTail > MAX_WINDOW_SIZE) m_WindowSizeTail = MAX_WINDOW_SIZE; - } if (m_IsNAcked) ResendPacket (); else if (m_IsResendNeeded) // resend packets @@ -1420,10 +1409,7 @@ namespace stream { // loss-based CC if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED) - { - LogPrint (eLogDebug, "Streaming: Packet loss, reduce window size"); ProcessWindowDrop (); - } } else if (m_IsTimeOutResend) { @@ -1436,8 +1422,6 @@ namespace stream m_IsFirstRttSample = true; m_DropWindowDelaySequenceNumber = 0; m_IsFirstACK = true; - m_LastACKRecieveTime = 0; - m_ACKRecieveInterval = m_AckDelay; UpdatePacingTime (); if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); if (m_NumResendAttempts & 1) @@ -1601,7 +1585,6 @@ namespace stream } if (isLeaseChanged && !m_IsRemoteLeaseChangeInProgress) { - LogPrint (eLogDebug, "Streaming: RemoteLease changed, set initial window size"); HalveWindowSize (); } } @@ -1618,10 +1601,7 @@ namespace stream void Stream::UpdatePacingTime () { - if (m_WindowDropTargetSize) - m_PacingTime = std::round (m_RTT*1000/m_WindowDropTargetSize); - else - m_PacingTime = std::round (m_RTT*1000/m_WindowSize); + m_PacingTime = std::round (m_RTT*1000/m_WindowSize); if (m_MinPacingTime && m_PacingTime < m_MinPacingTime) m_PacingTime = m_MinPacingTime; } @@ -1629,20 +1609,18 @@ namespace stream void Stream::ProcessWindowDrop () { if (m_WindowSize > m_LastWindowDropSize) - { - m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize + m_WindowSizeTail) / 2; - if (m_LastWindowDropSize > MAX_WINDOW_SIZE) m_LastWindowDropSize = MAX_WINDOW_SIZE; - } + m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2; else m_LastWindowDropSize = m_WindowSize; m_WindowDropTargetSize = m_LastWindowDropSize - (m_LastWindowDropSize / 4); // -25%; - if (m_WindowDropTargetSize < MIN_WINDOW_SIZE) - m_WindowDropTargetSize = MIN_WINDOW_SIZE; + if (m_WindowDropTargetSize < MIN_WINDOW_SIZE + 1) + m_WindowDropTargetSize = MIN_WINDOW_SIZE + 1; + m_WindowSize = m_SentPackets.size (); // stop sending now + if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; m_WindowIncCounter = 0; // disable window growth - m_DropWindowDelaySequenceNumber = m_SequenceNumber + int(m_WindowDropTargetSize); + m_DropWindowDelaySequenceNumber = m_SequenceNumber; m_IsFirstACK = true; // ignore first RTT sample m_IsWinDropped = true; // don't drop window twice - m_WindowSizeTail = 0; UpdatePacingTime (); } @@ -1660,7 +1638,6 @@ namespace stream m_WindowIncCounter = 0; m_IsFirstRttSample = true; m_IsFirstACK = true; - m_WindowSizeTail = 0; UpdatePacingTime (); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index a9e8a404..71450b2b 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -295,10 +295,10 @@ namespace stream SendBufferQueue m_SendBuffer; double m_RTT, m_SlowRTT, m_SlowRTT2; float m_WindowSize, m_LastWindowDropSize, m_WindowDropTargetSize; - int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample, m_WindowSizeTail; + int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; double m_Jitter; uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, // microseconds - m_LastSendTime, m_LastACKRecieveTime, m_ACKRecieveInterval, m_RemoteLeaseChangeTime; // milliseconds + m_LastSendTime, m_RemoteLeaseChangeTime; // milliseconds uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed int m_NumResendAttempts, m_NumPacketsToSend; size_t m_MTU; From 3264704a234409297da9b5ca4bdad9edc214f419 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 14 Dec 2024 17:59:51 -0500 Subject: [PATCH 295/527] Handle choked, new RTO and window size calculation --- libi2pd/Streaming.cpp | 156 +++++++++++++++++++++++++++--------------- libi2pd/Streaming.h | 7 +- 2 files changed, 104 insertions(+), 59 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 70c59067..b5e520b9 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -72,15 +72,15 @@ namespace stream m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsIncoming (false), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), - m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), + m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsClientChoked (false), m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_DoubleWinIncCounter (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), - m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), + m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_WindowSizeTail (0), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_RemoteLeaseChangeTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { @@ -99,15 +99,15 @@ namespace stream m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed - m_Status (eStreamStatusNew), m_IsIncoming (true), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), - m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), + m_Status (eStreamStatusNew), m_IsIncoming (true), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), + m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsClientChoked (false), m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_DoubleWinIncCounter (false), m_LocalDestination (local), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), - m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_RemoteLeaseChangeTime (0), + m_PrevRTTSample (INITIAL_RTT), m_WindowSizeTail (0), m_Jitter (0), m_MinPacingTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { @@ -364,12 +364,14 @@ namespace stream } if (delayRequested >= DELAY_CHOKING) { - if (!m_IsWinDropped) + if (!m_IsClientChoked) { + LogPrint (eLogDebug, "Streaming: Client choked, set min. window size"); m_WindowDropTargetSize = MIN_WINDOW_SIZE; m_LastWindowDropSize = 0; m_WindowIncCounter = 0; - m_IsWinDropped = true; // don't drop window twice + m_IsClientChoked = true; + m_IsWinDropped = false; m_DropWindowDelaySequenceNumber = m_SequenceNumber; UpdatePacingTime (); } @@ -537,12 +539,21 @@ namespace stream m_SentPackets.erase (it++); m_LocalDestination.DeletePacket (sentPacket); acknowledged = true; - if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK) + if (m_WindowIncCounter < MAX_WINDOW_SIZE && !m_IsFirstACK && !m_IsWinDropped) incCounter++; } else break; } + if (m_LastACKRecieveTime) + { + uint64_t interval = ts - m_LastACKRecieveTime; + if (m_ACKRecieveInterval) + m_ACKRecieveInterval = (m_ACKRecieveInterval + interval) / 2; + else + m_ACKRecieveInterval = interval; + } + m_LastACKRecieveTime = ts; if (rttSample != INT_MAX) { if (m_IsFirstRttSample && !m_IsFirstACK) @@ -588,36 +599,33 @@ namespace stream m_WindowIncCounter = m_WindowIncCounter + incCounter; // // delay-based CC - if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection + if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped && !m_IsClientChoked) // Drop window if RTT grows too fast, late detection + { + LogPrint (eLogDebug, "Streaming: Congestion detected, reduce window size"); ProcessWindowDrop (); + } UpdatePacingTime (); m_PrevRTTSample = rttSample; bool wasInitial = m_RTO == INITIAL_RTO; - m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter)); // TODO: implement it better + m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter + m_ACKRecieveInterval)); // TODO: implement it better if (wasInitial) ScheduleResend (); } + if (m_IsClientChoked && ackThrough > m_DropWindowDelaySequenceNumber) + { + m_IsClientChoked = false; + } if (m_IsWinDropped && ackThrough > m_DropWindowDelaySequenceNumber) { m_IsFirstRttSample = true; m_IsWinDropped = false; } - if (m_WindowDropTargetSize && m_WindowSize <= m_WindowDropTargetSize) + if (m_WindowDropTargetSize && int(m_SentPackets.size ()) <= m_WindowDropTargetSize) { + m_WindowSize = m_WindowDropTargetSize; m_WindowDropTargetSize = 0; - m_DropWindowDelaySequenceNumber = m_SequenceNumber; - } - if (acknowledged && m_WindowDropTargetSize && m_WindowSize > m_WindowDropTargetSize) - { - m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter)); // we assume that the next rtt sample may be much larger than the current - m_IsResendNeeded = true; - m_WindowSize = m_SentPackets.size () + 1; // if there are no packets to resend, just send one regular packet - if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; - if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; - m_WindowIncCounter = 0; - UpdatePacingTime (); } if (acknowledged || m_IsNAcked) { @@ -626,12 +634,14 @@ namespace stream if (m_SendBuffer.IsEmpty () && m_SentPackets.size () > 0) // tail loss { m_IsResendNeeded = true; - m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter)); // to prevent spurious retransmit + m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter + m_ACKRecieveInterval)); // to prevent spurious retransmit } if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ()) { m_ResendTimer.cancel (); m_SendTimer.cancel (); + m_LastACKRecieveTime = 0; + m_ACKRecieveInterval = m_AckDelay; } if (acknowledged && m_IsFirstACK) { @@ -1158,9 +1168,10 @@ namespace stream } if (m_RemoteLeaseChangeTime && m_IsRemoteLeaseChangeInProgress && ts > m_RemoteLeaseChangeTime + INITIAL_RTO) { + LogPrint (eLogDebug, "Streaming: RemoteLease changed, set initial window size"); CancelRemoteLeaseChange (); m_CurrentRemoteLease = m_NextRemoteLease; - HalveWindowSize (); + ResetWindowSize (); } auto currentRemoteLease = m_CurrentRemoteLease; if (!m_IsRemoteLeaseChangeInProgress && m_RemoteLeaseSet && m_CurrentRemoteLease && ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD) @@ -1195,7 +1206,8 @@ namespace stream } if (freshTunnel) { - m_RTO = INITIAL_RTO; + LogPrint (eLogDebug, "Streaming: OutboundTunnel changed, set initial window size"); + ResetWindowSize (); // m_TunnelsChangeSequenceNumber = m_SequenceNumber; // should be determined more precisely } @@ -1285,31 +1297,47 @@ namespace stream m_NumPacketsToSend = 1; m_PacingTimeRem = 0; } m_IsSendTime = true; - if (m_WindowIncCounter && m_WindowSize < MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) + if (m_WindowIncCounter && (m_WindowSize < MAX_WINDOW_SIZE || m_WindowDropTargetSize) && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) { for (int i = 0; i < m_NumPacketsToSend; i++) { if (m_WindowIncCounter) { - if (m_LastWindowDropSize && (m_LastWindowDropSize >= m_WindowSize)) - m_WindowSize += 1 - (1 / ((m_LastWindowDropSize + PREV_SPEED_KEEP_TIME_COEFF) / m_WindowSize)); // some magic here - else if (m_LastWindowDropSize && (m_LastWindowDropSize < m_WindowSize)) - m_WindowSize += (m_WindowSize - (m_LastWindowDropSize - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize; // some magic here + if (m_WindowDropTargetSize) + { + if (m_LastWindowDropSize && (m_LastWindowDropSize >= m_WindowDropTargetSize)) + m_WindowDropTargetSize += 1 - (1 / ((m_LastWindowDropSize + PREV_SPEED_KEEP_TIME_COEFF) / m_WindowDropTargetSize)); // some magic here + else if (m_LastWindowDropSize && (m_LastWindowDropSize < m_WindowSize)) + m_WindowDropTargetSize += (m_WindowDropTargetSize - (m_LastWindowDropSize - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowDropTargetSize; // some magic here + else + m_WindowDropTargetSize += (m_WindowDropTargetSize - (1 - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowDropTargetSize; + if (m_WindowDropTargetSize > MAX_WINDOW_SIZE) m_WindowDropTargetSize = MAX_WINDOW_SIZE; + m_WindowIncCounter--; + } else - m_WindowSize += (m_WindowSize - (1 - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize; - if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; - m_WindowIncCounter--; + { + if (m_LastWindowDropSize && (m_LastWindowDropSize >= m_WindowSize)) + m_WindowSize += 1 - (1 / ((m_LastWindowDropSize + PREV_SPEED_KEEP_TIME_COEFF) / m_WindowSize)); // some magic here + else if (m_LastWindowDropSize && (m_LastWindowDropSize < m_WindowSize)) + m_WindowSize += (m_WindowSize - (m_LastWindowDropSize - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize; // some magic here + else + m_WindowSize += (m_WindowSize - (1 - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize; + if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; + m_WindowIncCounter--; + } } else break; } UpdatePacingTime (); } - if (m_IsNAcked) + else if (m_WindowIncCounter && m_WindowSize == MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) + { + m_WindowSizeTail = m_WindowSizeTail + m_WindowIncCounter; + if (m_WindowSizeTail > MAX_WINDOW_SIZE) m_WindowSizeTail = MAX_WINDOW_SIZE; + } + if (m_IsNAcked || m_IsResendNeeded || m_IsClientChoked) // resend packets ResendPacket (); - else if (m_IsResendNeeded) // resend packets - ResendPacket (); - // delay-based CC else if (m_WindowSize > int(m_SentPackets.size ())) // send packets SendBuffer (); } @@ -1408,8 +1436,11 @@ namespace stream if (m_NumResendAttempts == 1 && m_RTO != INITIAL_RTO) { // loss-based CC - if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED) + if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED && !m_IsClientChoked) + { + LogPrint (eLogDebug, "Streaming: Packet loss, reduce window size"); ProcessWindowDrop (); + } } else if (m_IsTimeOutResend) { @@ -1422,6 +1453,8 @@ namespace stream m_IsFirstRttSample = true; m_DropWindowDelaySequenceNumber = 0; m_IsFirstACK = true; + m_LastACKRecieveTime = 0; + m_ACKRecieveInterval = m_AckDelay; UpdatePacingTime (); if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); if (m_NumResendAttempts & 1) @@ -1442,11 +1475,12 @@ namespace stream SendPackets (packets); m_LastSendTime = ts; m_IsSendTime = false; - if (m_IsNAcked || m_IsResendNeeded) ScheduleSend (); + if (m_IsNAcked || m_IsResendNeeded || m_IsClientChoked) ScheduleSend (); } - else + else if (!m_IsClientChoked) SendBuffer (); if (!m_IsNAcked && !m_IsResendNeeded) ScheduleResend (); + if (m_IsClientChoked) ScheduleSend (); } void Stream::ScheduleAck (int timeout) @@ -1585,7 +1619,8 @@ namespace stream } if (isLeaseChanged && !m_IsRemoteLeaseChangeInProgress) { - HalveWindowSize (); + LogPrint (eLogDebug, "Streaming: RemoteLease changed, set initial window size"); + ResetWindowSize (); } } @@ -1601,7 +1636,10 @@ namespace stream void Stream::UpdatePacingTime () { - m_PacingTime = std::round (m_RTT*1000/m_WindowSize); + if (m_WindowDropTargetSize) + m_PacingTime = std::round (m_RTT*1000/m_WindowDropTargetSize); + else + m_PacingTime = std::round (m_RTT*1000/m_WindowSize); if (m_MinPacingTime && m_PacingTime < m_MinPacingTime) m_PacingTime = m_MinPacingTime; } @@ -1609,35 +1647,41 @@ namespace stream void Stream::ProcessWindowDrop () { if (m_WindowSize > m_LastWindowDropSize) - m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2; + { + m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize + m_WindowSizeTail) / 2; + if (m_LastWindowDropSize > MAX_WINDOW_SIZE) m_LastWindowDropSize = MAX_WINDOW_SIZE; + } else m_LastWindowDropSize = m_WindowSize; m_WindowDropTargetSize = m_LastWindowDropSize - (m_LastWindowDropSize / 4); // -25%; - if (m_WindowDropTargetSize < MIN_WINDOW_SIZE + 1) - m_WindowDropTargetSize = MIN_WINDOW_SIZE + 1; - m_WindowSize = m_SentPackets.size (); // stop sending now - if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; + if (m_WindowDropTargetSize < MIN_WINDOW_SIZE) + m_WindowDropTargetSize = MIN_WINDOW_SIZE; m_WindowIncCounter = 0; // disable window growth - m_DropWindowDelaySequenceNumber = m_SequenceNumber; + m_DropWindowDelaySequenceNumber = m_SequenceNumber + int(m_WindowDropTargetSize); m_IsFirstACK = true; // ignore first RTT sample m_IsWinDropped = true; // don't drop window twice + m_WindowSizeTail = 0; UpdatePacingTime (); } - void Stream::HalveWindowSize () + void Stream::ResetWindowSize () { m_RTO = INITIAL_RTO; - if (m_WindowSize > INITIAL_WINDOW_SIZE) + if (!m_IsClientChoked) { - m_WindowDropTargetSize = std::max (m_WindowSize/2, (float)INITIAL_WINDOW_SIZE); - m_IsWinDropped = true; + if (m_WindowSize > INITIAL_WINDOW_SIZE) + { + m_WindowDropTargetSize = (float)INITIAL_WINDOW_SIZE; + m_IsWinDropped = true; + } + else + m_WindowSize = INITIAL_WINDOW_SIZE; } - else - m_WindowSize = INITIAL_WINDOW_SIZE; m_LastWindowDropSize = 0; m_WindowIncCounter = 0; m_IsFirstRttSample = true; m_IsFirstACK = true; + m_WindowSizeTail = 0; UpdatePacingTime (); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 71450b2b..a91604c3 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -251,7 +251,7 @@ namespace stream void UpdatePacingTime (); void ProcessWindowDrop (); - void HalveWindowSize (); + void ResetWindowSize (); void CancelRemoteLeaseChange (); private: @@ -272,6 +272,7 @@ namespace stream bool m_IsFirstRttSample; bool m_IsSendTime; bool m_IsWinDropped; + bool m_IsClientChoked; bool m_IsTimeOutResend; bool m_IsImmediateAckRequested; bool m_IsRemoteLeaseChangeInProgress; @@ -295,10 +296,10 @@ namespace stream SendBufferQueue m_SendBuffer; double m_RTT, m_SlowRTT, m_SlowRTT2; float m_WindowSize, m_LastWindowDropSize, m_WindowDropTargetSize; - int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; + int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample, m_WindowSizeTail; double m_Jitter; uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, // microseconds - m_LastSendTime, m_RemoteLeaseChangeTime; // milliseconds + m_LastSendTime, m_LastACKRecieveTime, m_ACKRecieveInterval, m_RemoteLeaseChangeTime; // milliseconds uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed int m_NumResendAttempts, m_NumPacketsToSend; size_t m_MTU; From e76d09e1a157e54fbb5d082bdf48d04b4218fd55 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 15 Dec 2024 18:03:31 -0500 Subject: [PATCH 296/527] send tunnel participant data to transport session directly. Implemented TunnelTransportSender --- libi2pd/NetDb.cpp | 2 +- libi2pd/TransitTunnel.cpp | 3 +- libi2pd/TransitTunnel.h | 1 + libi2pd/Transports.cpp | 7 ----- libi2pd/Transports.h | 1 - libi2pd/TunnelBase.cpp | 64 +++++++++++++++++++++++++++++++++++++++ libi2pd/TunnelBase.h | 25 ++++++++++++++- libi2pd/TunnelGateway.cpp | 35 ++------------------- libi2pd/TunnelGateway.h | 5 +-- 9 files changed, 95 insertions(+), 48 deletions(-) create mode 100644 libi2pd/TunnelBase.cpp diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index c712af8b..09182948 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -502,7 +502,7 @@ namespace data } // send them off - i2p::transport::transports.SendMessages(ih, requests); + i2p::transport::transports.SendMessages(ih, std::move (requests)); } bool NetDb::LoadRouterInfo (const std::string& path, uint64_t ts) diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index 883034fe..7dbed003 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -62,7 +62,8 @@ namespace tunnel auto num = m_TunnelDataMsgs.size (); if (num > 1) LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num); - i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs); // send and clear + if (!m_Sender) m_Sender = std::make_unique(); + m_Sender->SendMessagesTo (GetNextIdentHash (), m_TunnelDataMsgs); // send and clear } } diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index 14f9b997..89653931 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.h @@ -63,6 +63,7 @@ namespace tunnel size_t m_NumTransmittedBytes; std::list > m_TunnelDataMsgs; + std::unique_ptr m_Sender; }; class TransitTunnelGateway: public TransitTunnel diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 03416137..06bd724d 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -454,13 +454,6 @@ namespace transport return {}; // invalid future } - std::future > Transports::SendMessages (const i2p::data::IdentHash& ident, std::list >& msgs) - { - std::list > msgs1; - msgs.swap (msgs1); - return SendMessages (ident, std::move (msgs1)); - } - std::future > Transports::SendMessages (const i2p::data::IdentHash& ident, std::list >&& msgs) { return boost::asio::post (*m_Service, boost::asio::use_future ([this, ident, msgs = std::move(msgs)] () mutable diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index b72d5b70..85330162 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -145,7 +145,6 @@ namespace transport void ReuseX25519KeysPair (std::shared_ptr pair); std::future > SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg); - std::future > SendMessages (const i2p::data::IdentHash& ident, std::list >& msgs); std::future > SendMessages (const i2p::data::IdentHash& ident, std::list >&& msgs); void PeerConnected (std::shared_ptr session); diff --git a/libi2pd/TunnelBase.cpp b/libi2pd/TunnelBase.cpp new file mode 100644 index 00000000..031988a6 --- /dev/null +++ b/libi2pd/TunnelBase.cpp @@ -0,0 +1,64 @@ +/* +* 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 +* +*/ + +#include "Transports.h" +#include "TunnelBase.h" + +namespace i2p +{ +namespace tunnel +{ + void TunnelTransportSender::SendMessagesTo (const i2p::data::IdentHash& to, + std::list >&& msgs) + { + if (msgs.empty ()) return; + auto currentTransport = m_CurrentTransport.lock (); + if (!currentTransport) + { + // try to obtain transport from pending request or send thought transport is not complete + if (m_PendingTransport.valid ()) // pending request? + { + if (m_PendingTransport.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + { + // pending request complete + currentTransport = m_PendingTransport.get (); // take transports used in pending request + if (currentTransport) + { + if (currentTransport->IsEstablished ()) + m_CurrentTransport = currentTransport; + else + currentTransport = nullptr; + } + } + else // still pending + { + // send through transports, but don't update pending transport + i2p::transport::transports.SendMessages (to, std::move (msgs)); + return; + } + } + } + if (currentTransport) // session is good + // send to session directly + currentTransport->SendI2NPMessages (msgs); + else // no session yet + // send through transports + m_PendingTransport = i2p::transport::transports.SendMessages (to, std::move (msgs)); + + } + + void TunnelTransportSender::SendMessagesTo (const i2p::data::IdentHash& to, + std::list >& msgs) + { + std::list > msgs1; + msgs.swap (msgs1); + SendMessagesTo (to, std::move (msgs1)); + } +} +} diff --git a/libi2pd/TunnelBase.h b/libi2pd/TunnelBase.h index d58ec2d7..91d0fafc 100644 --- a/libi2pd/TunnelBase.h +++ b/libi2pd/TunnelBase.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 * @@ -11,12 +11,19 @@ #include #include +#include +#include #include "Timestamp.h" #include "I2NPProtocol.h" #include "Identity.h" namespace i2p { +namespace transport +{ + class TransportSession; +} + namespace tunnel { const size_t TUNNEL_DATA_MSG_SIZE = 1028; @@ -76,6 +83,22 @@ namespace tunnel return t1 < t2; } }; + + class TunnelTransportSender final + { + public: + + TunnelTransportSender () = default; + ~TunnelTransportSender () = default; + + void SendMessagesTo (const i2p::data::IdentHash& to, std::list >&& msgs); + void SendMessagesTo (const i2p::data::IdentHash& to, std::list >& msgs); // send and clear + + private: + + std::weak_ptr m_CurrentTransport; + std::future > m_PendingTransport; + }; } } diff --git a/libi2pd/TunnelGateway.cpp b/libi2pd/TunnelGateway.cpp index e2797f8c..9e27d207 100644 --- a/libi2pd/TunnelGateway.cpp +++ b/libi2pd/TunnelGateway.cpp @@ -235,40 +235,9 @@ namespace tunnel m_NumSentBytes += TUNNEL_DATA_MSG_SIZE; } m_Buffer.ClearTunnelDataMsgs (); - // send - auto currentTransport = m_CurrentTransport.lock (); - if (!currentTransport) - { - // try to obtain transport from pending request or send thought transport is not complete - if (m_PendingTransport.valid ()) // pending request? - { - if (m_PendingTransport.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - { - // pending request complete - currentTransport = m_PendingTransport.get (); // take transports used in pending request - if (currentTransport) - { - if (currentTransport->IsEstablished ()) - m_CurrentTransport = currentTransport; - else - currentTransport = nullptr; - } - } - else // still pending - { - // send through transports, but don't update pending transport - i2p::transport::transports.SendMessages (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs)); - return; - } - } - } - if (currentTransport) // session is good - // send to session directly - currentTransport->SendI2NPMessages (newTunnelMsgs); - else // no session yet - // send through transports - m_PendingTransport = i2p::transport::transports.SendMessages (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs)); + if (!m_Sender) m_Sender = std::make_unique(); + m_Sender->SendMessagesTo (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs)); } } } diff --git a/libi2pd/TunnelGateway.h b/libi2pd/TunnelGateway.h index 4cfd5308..292392ae 100644 --- a/libi2pd/TunnelGateway.h +++ b/libi2pd/TunnelGateway.h @@ -12,9 +12,7 @@ #include #include #include -#include #include "I2NPProtocol.h" -#include "TransportSession.h" #include "TunnelBase.h" namespace i2p @@ -59,8 +57,7 @@ namespace tunnel TunnelBase& m_Tunnel; TunnelGatewayBuffer m_Buffer; size_t m_NumSentBytes; - std::weak_ptr m_CurrentTransport; - std::future > m_PendingTransport; + std::unique_ptr m_Sender; }; } } From bdc5eaa824ea8258434d058df76a16dfc2b66a5e Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 15 Dec 2024 18:15:21 -0500 Subject: [PATCH 297/527] fixed build with boost 1.87 --- daemon/UPnP.cpp | 2 +- libi2pd/util.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/daemon/UPnP.cpp b/daemon/UPnP.cpp index 7885578e..21ed0faf 100644 --- a/daemon/UPnP.cpp +++ b/daemon/UPnP.cpp @@ -150,7 +150,7 @@ namespace transport // UPnP discovered LogPrint (eLogDebug, "UPnP: ExternalIPAddress is ", m_externalIPAddress); - i2p::context.UpdateAddress (boost::asio::ip::address::from_string (m_externalIPAddress)); + i2p::context.UpdateAddress (boost::asio::ip::make_address (m_externalIPAddress)); // port mapping PortMapping (); } diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index aff3d0e0..76bfe103 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -454,9 +454,9 @@ namespace net #ifdef _WIN32 LogPrint(eLogError, "NetIface: Cannot get address by interface name, not implemented on WIN32"); if (ipv6) - return boost::asio::ip::address::from_string("::1"); + return boost::asio::ip::make_address("::1"); else - return boost::asio::ip::address::from_string("127.0.0.1"); + return boost::asio::ip::make_address("127.0.0.1"); #else int af = (ipv6 ? AF_INET6 : AF_INET); ifaddrs *addrs; From 833e0a936eb8cba2937a4421d554aecb555f5a02 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 15 Dec 2024 18:27:24 -0500 Subject: [PATCH 298/527] fixed build with boost 1.87 --- daemon/UPnP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/UPnP.cpp b/daemon/UPnP.cpp index 21ed0faf..8e6dbcf6 100644 --- a/daemon/UPnP.cpp +++ b/daemon/UPnP.cpp @@ -52,7 +52,7 @@ namespace transport { m_IsRunning = true; LogPrint(eLogInfo, "UPnP: Starting"); - m_Service.post (std::bind (&UPnP::Discover, this)); + boost::asio::post (m_Service, std::bind (&UPnP::Discover, this)); std::unique_lock l(m_StartedMutex); m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this))); m_Started.wait_for (l, std::chrono::seconds (5)); // 5 seconds maximum From b4bcd9914aabfe6de231490228035bce3d726828 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 16 Dec 2024 19:49:14 -0500 Subject: [PATCH 299/527] show next peer and connectivity on transit tunnels page --- daemon/HTTPServer.cpp | 4 +-- libi2pd/NTCP2.cpp | 6 +++++ libi2pd/NTCP2.h | 1 + libi2pd/RouterInfo.cpp | 13 ++++++++++ libi2pd/RouterInfo.h | 4 +++ libi2pd/SSU2Session.cpp | 5 ++++ libi2pd/SSU2Session.h | 1 + libi2pd/TransitTunnel.cpp | 50 +++++++++++++++++++++++++++++++------- libi2pd/TransitTunnel.h | 11 ++++++--- libi2pd/TransportSession.h | 1 + libi2pd/TunnelBase.cpp | 6 +++++ libi2pd/TunnelBase.h | 3 +++ libi2pd/TunnelGateway.h | 1 + 13 files changed, 92 insertions(+), 14 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index e32bd459..2ac636ce 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -826,7 +826,7 @@ namespace http { if (i2p::tunnel::tunnels.CountTransitTunnels()) { s << "" << tr("Transit Tunnels") << ":
\r\n"; - s << ""; + s << "
ID" << tr("Amount") << "
"; for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ()) { if (std::dynamic_pointer_cast(it)) @@ -836,7 +836,7 @@ namespace http { else s << "\r\n"; + s << "\r\n"; } s << "
ID" << tr("Amount") << "" << tr("Next") << "
" << it->GetTunnelID () << ""; ShowTraffic(s, it->GetNumTransmittedBytes ()); - s << "
" << it->GetNextPeerName () << "
\r\n"; } diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 76b056cf..5ab577c0 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1435,6 +1435,12 @@ namespace transport boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ())); } + i2p::data::RouterInfo::SupportedTransports NTCP2Session::GetTransportType () const + { + if (m_RemoteEndpoint.address ().is_v4 ()) return i2p::data::RouterInfo::eNTCP2V4; + return i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? i2p::data::RouterInfo::eNTCP2V6Mesh : i2p::data::RouterInfo::eNTCP2V6; + } + NTCP2Server::NTCP2Server (): RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()), m_ProxyType(eNoProxy), m_Resolver(GetService ()), diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 5df4de6e..47354f32 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -147,6 +147,7 @@ namespace transport void SetRemoteEndpoint (const boost::asio::ip::tcp::endpoint& ep) { m_RemoteEndpoint = ep; }; bool IsEstablished () const override { return m_IsEstablished; }; + i2p::data::RouterInfo::SupportedTransports GetTransportType () const override; bool IsTerminated () const { return m_IsTerminated; }; void ClientLogin (); // Alice diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 0d53f6cd..3c074031 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1195,6 +1195,19 @@ namespace data return false; } } + + std::string RouterInfo::GetTransportName (SupportedTransports tr) + { + switch (tr) + { + case eNTCP2V4: return "NTCP2V4"; + case eNTCP2V6: return "NTCP2V6"; + case eSSU2V4: return "SSU2V4"; + case eSSU2V6: return "SSU2V6"; + case eNTCP2V6Mesh: return "Mesh"; + default: return ""; + } + } void LocalRouterInfo::CreateBuffer (const PrivateKeys& privateKeys) { diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index beeba5bf..8d11f661 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -363,6 +363,10 @@ namespace data int m_Version; Congestion m_Congestion; mutable std::shared_ptr m_Profile; + + public: + + static std::string GetTransportName (SupportedTransports tr); }; class LocalRouterInfo: public RouterInfo diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 4196e785..284ab4d8 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -3114,5 +3114,10 @@ namespace transport else if (!sent && !m_SentPackets.empty ()) // if only acks received, nothing sent and we still have something to resend Resend (i2p::util::GetMillisecondsSinceEpoch ()); // than right time to resend } + + i2p::data::RouterInfo::SupportedTransports SSU2Session::GetTransportType () const + { + return m_RemoteEndpoint.address ().is_v4 () ? i2p::data::RouterInfo::eSSU2V4 : i2p::data::RouterInfo::eSSU2V6; + } } } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 4b3139a7..acd46dd1 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -267,6 +267,7 @@ namespace transport size_t Resend (uint64_t ts); // return number of resent packets uint64_t GetLastResendTime () const { return m_LastResendTime; }; bool IsEstablished () const override { return m_State == eSSU2SessionStateEstablished; }; + i2p::data::RouterInfo::SupportedTransports GetTransportType () const override; uint64_t GetConnID () const { return m_SourceConnID; }; SSU2SessionState GetState () const { return m_State; }; void SetState (SSU2SessionState state) { m_State = state; }; diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index 7dbed003..3d3f20f2 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -10,6 +10,8 @@ #include "I2PEndian.h" #include "Crypto.h" #include "Log.h" +#include "Identity.h" +#include "RouterInfo.h" #include "RouterContext.h" #include "I2NPProtocol.h" #include "Garlic.h" @@ -41,6 +43,21 @@ namespace tunnel i2p::transport::transports.UpdateTotalTransitTransmittedBytes (TUNNEL_DATA_MSG_SIZE); } + std::string TransitTunnel::GetNextPeerName () const + { + return i2p::data::GetIdentHashAbbreviation (GetNextIdentHash ()); + } + + void TransitTunnel::SendTunnelDataMsg (std::shared_ptr msg) + { + LogPrint (eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID ()); + } + + void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr&& tunnelMsg) + { + LogPrint (eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID ()); + } + TransitTunnelParticipant::~TransitTunnelParticipant () { } @@ -67,16 +84,18 @@ namespace tunnel } } - void TransitTunnel::SendTunnelDataMsg (std::shared_ptr msg) + std::string TransitTunnelParticipant::GetNextPeerName () const { - LogPrint (eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID ()); - } - - void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr&& tunnelMsg) - { - LogPrint (eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID ()); - } - + if (m_Sender) + { + auto transport = m_Sender->GetCurrentTransport (); + if (transport) + return TransitTunnel::GetNextPeerName () + "-" + + i2p::data::RouterInfo::GetTransportName (transport->GetTransportType ()); + } + return TransitTunnel::GetNextPeerName (); + } + void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr msg) { TunnelMessageBlock block; @@ -92,6 +111,19 @@ namespace tunnel m_Gateway.SendBuffer (); } + std::string TransitTunnelGateway::GetNextPeerName () const + { + const auto& sender = m_Gateway.GetSender (); + if (sender) + { + auto transport = sender->GetCurrentTransport (); + if (transport) + return TransitTunnel::GetNextPeerName () + "-" + + i2p::data::RouterInfo::GetTransportName (transport->GetTransportType ()); + } + return TransitTunnel::GetNextPeerName (); + } + void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr&& tunnelMsg) { auto newMsg = CreateEmptyTunnelDataMsg (true); diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index 89653931..58aba35b 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.h @@ -33,11 +33,13 @@ namespace tunnel const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey); virtual size_t GetNumTransmittedBytes () const { return 0; }; + virtual std::string GetNextPeerName () const; // implements TunnelBase void SendTunnelDataMsg (std::shared_ptr msg) override; void HandleTunnelDataMsg (std::shared_ptr&& tunnelMsg) override; void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out) override; + private: i2p::crypto::AESKey m_LayerKey, m_IVKey; @@ -56,6 +58,7 @@ namespace tunnel ~TransitTunnelParticipant (); size_t GetNumTransmittedBytes () const override { return m_NumTransmittedBytes; }; + std::string GetNextPeerName () const override; void HandleTunnelDataMsg (std::shared_ptr&& tunnelMsg) override; void FlushTunnelDataMsgs () override; @@ -79,7 +82,8 @@ namespace tunnel void SendTunnelDataMsg (std::shared_ptr msg) override; void FlushTunnelDataMsgs () override; size_t GetNumTransmittedBytes () const override { return m_Gateway.GetNumSentBytes (); }; - + std::string GetNextPeerName () const override; + private: std::mutex m_SendMutex; @@ -97,10 +101,11 @@ namespace tunnel m_Endpoint (false) {}; // transit endpoint is always outbound void Cleanup () override { m_Endpoint.Cleanup (); } - + void HandleTunnelDataMsg (std::shared_ptr&& tunnelMsg) override; size_t GetNumTransmittedBytes () const override { return m_Endpoint.GetNumReceivedBytes (); } - + std::string GetNextPeerName () const override { return ""; } + private: TunnelEndpoint m_Endpoint; diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index 6c878d11..ef0044c0 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -151,6 +151,7 @@ namespace transport }; virtual void SendI2NPMessages (std::list >& msgs) = 0; virtual bool IsEstablished () const = 0; + virtual i2p::data::RouterInfo::SupportedTransports GetTransportType () const = 0; private: diff --git a/libi2pd/TunnelBase.cpp b/libi2pd/TunnelBase.cpp index 031988a6..1f437758 100644 --- a/libi2pd/TunnelBase.cpp +++ b/libi2pd/TunnelBase.cpp @@ -60,5 +60,11 @@ namespace tunnel msgs.swap (msgs1); SendMessagesTo (to, std::move (msgs1)); } + + void TunnelTransportSender::Reset () + { + m_CurrentTransport.reset (); + m_PendingTransport = std::future >(); + } } } diff --git a/libi2pd/TunnelBase.h b/libi2pd/TunnelBase.h index 91d0fafc..39d6e780 100644 --- a/libi2pd/TunnelBase.h +++ b/libi2pd/TunnelBase.h @@ -93,6 +93,9 @@ namespace tunnel void SendMessagesTo (const i2p::data::IdentHash& to, std::list >&& msgs); void SendMessagesTo (const i2p::data::IdentHash& to, std::list >& msgs); // send and clear + + std::shared_ptr GetCurrentTransport () const { return m_CurrentTransport.lock (); } + void Reset (); private: diff --git a/libi2pd/TunnelGateway.h b/libi2pd/TunnelGateway.h index 292392ae..75f27581 100644 --- a/libi2pd/TunnelGateway.h +++ b/libi2pd/TunnelGateway.h @@ -51,6 +51,7 @@ namespace tunnel void PutTunnelDataMsg (const TunnelMessageBlock& block); void SendBuffer (); size_t GetNumSentBytes () const { return m_NumSentBytes; }; + const std::unique_ptr& GetSender () const { return m_Sender; }; private: From 36939898fe782e0744ee316f83744e2056f24461 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 17 Dec 2024 20:50:54 -0500 Subject: [PATCH 300/527] send tunnel endpoint data to transport session to gateway directly --- libi2pd/TransitTunnel.cpp | 24 ++++++++++++++++++++++ libi2pd/TransitTunnel.h | 3 ++- libi2pd/TunnelBase.cpp | 3 ++- libi2pd/TunnelEndpoint.cpp | 42 +++++++++++++++++++++++++++++++------- libi2pd/TunnelEndpoint.h | 17 ++++++++++++--- 5 files changed, 77 insertions(+), 12 deletions(-) diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index 3d3f20f2..ba505ae3 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -133,6 +133,30 @@ namespace tunnel m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg); } + void TransitTunnelEndpoint::FlushTunnelDataMsgs () + { + m_Endpoint.FlushI2NPMsgs (); + } + + std::string TransitTunnelEndpoint::GetNextPeerName () const + { + auto hash = m_Endpoint.GetCurrentHash (); + if (hash) + { + const auto& sender = m_Endpoint.GetSender (); + if (sender) + { + auto transport = sender->GetCurrentTransport (); + if (transport) + return i2p::data::GetIdentHashAbbreviation (*hash) + "-" + + i2p::data::RouterInfo::GetTransportName (transport->GetTransportType ()); + else + return i2p::data::GetIdentHashAbbreviation (*hash); + } + } + return ""; + } + std::shared_ptr CreateTransitTunnel (uint32_t receiveTunnelID, const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID, const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey, diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index 58aba35b..c0f9c276 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.h @@ -103,8 +103,9 @@ namespace tunnel void Cleanup () override { m_Endpoint.Cleanup (); } void HandleTunnelDataMsg (std::shared_ptr&& tunnelMsg) override; + void FlushTunnelDataMsgs () override; size_t GetNumTransmittedBytes () const override { return m_Endpoint.GetNumReceivedBytes (); } - std::string GetNextPeerName () const override { return ""; } + std::string GetNextPeerName () const override; private: diff --git a/libi2pd/TunnelBase.cpp b/libi2pd/TunnelBase.cpp index 1f437758..b5a4a0b3 100644 --- a/libi2pd/TunnelBase.cpp +++ b/libi2pd/TunnelBase.cpp @@ -64,7 +64,8 @@ namespace tunnel void TunnelTransportSender::Reset () { m_CurrentTransport.reset (); - m_PendingTransport = std::future >(); + if (m_PendingTransport.valid ()) + m_PendingTransport = std::future >(); } } } diff --git a/libi2pd/TunnelEndpoint.cpp b/libi2pd/TunnelEndpoint.cpp index 3dc0dc07..6eb08ef3 100644 --- a/libi2pd/TunnelEndpoint.cpp +++ b/libi2pd/TunnelEndpoint.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,10 +21,7 @@ namespace i2p { namespace tunnel { - TunnelEndpoint::~TunnelEndpoint () - { - } - + void TunnelEndpoint::HandleDecryptedTunnelDataMsg (std::shared_ptr msg) { m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE; @@ -331,13 +328,13 @@ namespace tunnel break; case eDeliveryTypeTunnel: if (!m_IsInbound) // outbound transit tunnel - i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data)); + SendMessageTo (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data)); else LogPrint (eLogError, "TunnelMessage: Delivery type 'tunnel' arrived from an inbound tunnel, dropped"); break; case eDeliveryTypeRouter: if (!m_IsInbound) // outbound transit tunnel - i2p::transport::transports.SendMessage (msg.hash, msg.data); + i2p::transport::transports.SendMessage (msg.hash, msg.data); // send right away, because most likely it's single message else // we shouldn't send this message. possible leakage LogPrint (eLogError, "TunnelMessage: Delivery type 'router' arrived from an inbound tunnel, dropped"); break; @@ -366,5 +363,36 @@ namespace tunnel ++it; } } + + void TunnelEndpoint::SendMessageTo (const i2p::data::IdentHash& to, std::shared_ptr msg) + { + if (msg) + { + if (!m_Sender && m_I2NPMsgs.empty ()) // first message + m_CurrentHash = to; + else if (m_CurrentHash != to) // new target router + { + FlushI2NPMsgs (); // flush message to previous + if (m_Sender) m_Sender->Reset (); // reset sender + m_CurrentHash = to; // set new target router + } // otherwise add msg to the list for current target router + m_I2NPMsgs.push_back (msg); + i2p::transport::transports.SendMessage (to, msg); + } + } + + void TunnelEndpoint::FlushI2NPMsgs () + { + if (!m_I2NPMsgs.empty ()) + { + if (!m_Sender) m_Sender = std::make_unique(); + m_Sender->SendMessagesTo (m_CurrentHash, m_I2NPMsgs); // send and clear + } + } + + const i2p::data::IdentHash * TunnelEndpoint::GetCurrentHash () const + { + return (m_Sender || !m_I2NPMsgs.empty ()) ? &m_CurrentHash : nullptr; + } } } diff --git a/libi2pd/TunnelEndpoint.h b/libi2pd/TunnelEndpoint.h index 17590a5f..ac1e8e87 100644 --- a/libi2pd/TunnelEndpoint.h +++ b/libi2pd/TunnelEndpoint.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 * @@ -11,8 +11,10 @@ #include #include +#include #include #include +#include #include "I2NPProtocol.h" #include "TunnelBase.h" @@ -20,7 +22,7 @@ namespace i2p { namespace tunnel { - class TunnelEndpoint + class TunnelEndpoint final { struct TunnelMessageBlockEx: public TunnelMessageBlock { @@ -39,18 +41,23 @@ namespace tunnel public: TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0), m_CurrentMsgID (0) {}; - ~TunnelEndpoint (); + ~TunnelEndpoint () = default; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; void Cleanup (); void HandleDecryptedTunnelDataMsg (std::shared_ptr msg); + void FlushI2NPMsgs (); + const i2p::data::IdentHash * GetCurrentHash () const; // return null if not avaiable + const std::unique_ptr& GetSender () const { return m_Sender; }; + private: void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, uint8_t fragmentNum, const uint8_t * fragment, size_t size); bool ConcatFollowOnFragment (TunnelMessageBlockEx& msg, const uint8_t * fragment, size_t size) const; // true if success void HandleCurrenMessageFollowOnFragment (const uint8_t * fragment, size_t size, bool isLastFragment); void HandleNextMessage (const TunnelMessageBlock& msg); + void SendMessageTo (const i2p::data::IdentHash& to, std::shared_ptr msg); void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, const uint8_t * fragment, size_t size); bool ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); // true if something added @@ -65,6 +72,10 @@ namespace tunnel size_t m_NumReceivedBytes; TunnelMessageBlockEx m_CurrentMessage; uint32_t m_CurrentMsgID; + // I2NP messages to send + std::list > m_I2NPMsgs; // to send + i2p::data::IdentHash m_CurrentHash; // send msgs to + std::unique_ptr m_Sender; }; } } From 7497741846fa41570c728150d1901abcf0ef2ee1 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Dec 2024 14:22:05 -0500 Subject: [PATCH 301/527] fixed possible crash at shutdown --- libi2pd/NTCP2.cpp | 2 +- libi2pd/Tunnel.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 5ab577c0..f0545ae7 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1550,6 +1550,7 @@ namespace transport void NTCP2Server::Stop () { + m_EstablisherService.Stop (); { // we have to copy it because Terminate changes m_NTCP2Sessions auto ntcpSessions = m_NTCP2Sessions; @@ -1565,7 +1566,6 @@ namespace transport m_TerminationTimer.cancel (); m_ProxyEndpoint = nullptr; } - m_EstablisherService.Stop (); StopIOService (); } diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index e11a360d..5b72cc97 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -296,6 +296,8 @@ namespace tunnel bool m_IsRunning; std::thread * m_Thread; + i2p::util::MemoryPoolMt > m_I2NPTunnelEndpointMessagesMemoryPool; + i2p::util::MemoryPoolMt > m_I2NPTunnelMessagesMemoryPool; std::map > m_PendingInboundTunnels; // by replyMsgID std::map > m_PendingOutboundTunnels; // by replyMsgID std::list > m_InboundTunnels; @@ -306,8 +308,6 @@ namespace tunnel std::list> m_Pools; std::shared_ptr m_ExploratoryPool; i2p::util::Queue > m_Queue; - i2p::util::MemoryPoolMt > m_I2NPTunnelEndpointMessagesMemoryPool; - i2p::util::MemoryPoolMt > m_I2NPTunnelMessagesMemoryPool; uint32_t m_MaxNumTransitTunnels; // count of tunnels for total TCSR algorithm int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations; From 399544801497c466b9af4dc01f6decf8214f04cb Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Dec 2024 14:24:26 -0500 Subject: [PATCH 302/527] fixed possible crash at shutdown --- libi2pd/Transports.cpp | 7 +++++++ libi2pd/Transports.h | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 06bd724d..f3f9e5e4 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -55,6 +55,13 @@ namespace transport m_Thread->join (); m_Thread = nullptr; } + if (!m_Queue.empty ()) + { + // clean up queue + std::queue > tmp; + std::swap (m_Queue, tmp); + } + m_KeysPool.CleanUpMt (); } template diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 85330162..c1acbb2e 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -54,8 +54,8 @@ namespace transport private: const int m_QueueSize; - std::queue > m_Queue; i2p::util::MemoryPoolMt m_KeysPool; + std::queue > m_Queue; bool m_IsRunning; std::unique_ptr m_Thread; From 3bdfa5562be9ed3ea03f938acb24a1a84a9f2cb0 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 20 Dec 2024 19:42:25 -0500 Subject: [PATCH 303/527] don't send same message twice --- libi2pd/TunnelEndpoint.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libi2pd/TunnelEndpoint.cpp b/libi2pd/TunnelEndpoint.cpp index 6eb08ef3..b4908a8f 100644 --- a/libi2pd/TunnelEndpoint.cpp +++ b/libi2pd/TunnelEndpoint.cpp @@ -377,7 +377,6 @@ namespace tunnel m_CurrentHash = to; // set new target router } // otherwise add msg to the list for current target router m_I2NPMsgs.push_back (msg); - i2p::transport::transports.SendMessage (to, msg); } } From 55708d2a6d13eff3f6490fdf8c229e07e91b9b0b Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 22 Dec 2024 16:09:58 -0500 Subject: [PATCH 304/527] reduced LeaseSet lookup timeout --- libi2pd/Destination.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 7516c90f..22529df6 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -40,8 +40,8 @@ namespace client const int PUBLISH_VERIFICATION_TIMEOUT = 10; // in seconds after successful publish const int PUBLISH_MIN_INTERVAL = 20; // in seconds const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically - const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds - const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds + const int LEASESET_REQUEST_TIMEOUT = 3; // in seconds + const int MAX_LEASESET_REQUEST_TIMEOUT = 20; // in seconds const int DESTINATION_CLEANUP_TIMEOUT = 44; // in seconds const int DESTINATION_CLEANUP_TIMEOUT_VARIANCE = 30; // in seconds const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7; From 0f14f9a302c352671ed8d9a3c85ddc7d00adb586 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Dec 2024 13:47:38 -0500 Subject: [PATCH 305/527] LeaseSet request timeout in milliseconds --- libi2pd/Destination.cpp | 6 +++--- libi2pd/Destination.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 2d1aa2c8..b12038d4 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -833,7 +833,7 @@ namespace client request->requestedBlindedKey = requestedBlindedKey; // for encrypted LeaseSet2 if (requestComplete) request->requestComplete.push_back (requestComplete); - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ret = m_LeaseSetRequests.insert (std::pair >(dest,request)); if (ret.second) // inserted { @@ -916,7 +916,7 @@ namespace client nextFloodfill->GetIdentHash (), 0, msg } }); - request->requestTimeoutTimer.expires_from_now (boost::posix_time::seconds(LEASESET_REQUEST_TIMEOUT)); + request->requestTimeoutTimer.expires_from_now (boost::posix_time::milliseconds(LEASESET_REQUEST_TIMEOUT)); request->requestTimeoutTimer.async_wait (std::bind (&LeaseSetDestination::HandleRequestTimoutTimer, shared_from_this (), std::placeholders::_1, dest)); } @@ -933,7 +933,7 @@ namespace client if (it != m_LeaseSetRequests.end ()) { bool done = false; - uint64_t ts = i2p::util::GetSecondsSinceEpoch (); + uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); if (ts < it->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT) { auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, it->second->excluded); diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 22529df6..70c7ed39 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -40,8 +40,8 @@ namespace client const int PUBLISH_VERIFICATION_TIMEOUT = 10; // in seconds after successful publish const int PUBLISH_MIN_INTERVAL = 20; // in seconds const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically - const int LEASESET_REQUEST_TIMEOUT = 3; // in seconds - const int MAX_LEASESET_REQUEST_TIMEOUT = 20; // in seconds + const int LEASESET_REQUEST_TIMEOUT = 1600; // in milliseconds + const int MAX_LEASESET_REQUEST_TIMEOUT = 12000; // in milliseconds const int DESTINATION_CLEANUP_TIMEOUT = 44; // in seconds const int DESTINATION_CLEANUP_TIMEOUT_VARIANCE = 30; // in seconds const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7; From d48bf33fc5ea32cf7408056cbd55fdc6e401d6c4 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Dec 2024 17:52:14 -0500 Subject: [PATCH 306/527] request time in milliseconds. shorter intervals. interval variance --- libi2pd/NetDbRequests.cpp | 11 ++++++----- libi2pd/NetDbRequests.h | 15 ++++++++------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index 63d161cd..14e5ff19 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -21,7 +21,7 @@ namespace data { RequestedDestination::RequestedDestination (const IdentHash& destination, bool isExploratory, bool direct): m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), m_IsActive (true), - m_CreationTime (i2p::util::GetSecondsSinceEpoch ()), m_LastRequestTime (0), m_NumAttempts (0) + m_CreationTime (i2p::util::GetMillisecondsSinceEpoch ()), m_LastRequestTime (0), m_NumAttempts (0) { if (i2p::context.IsFloodfill ()) m_ExcludedPeers.insert (i2p::context.GetIdentHash ()); // exclude self if floodfill @@ -44,7 +44,7 @@ namespace data msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers); if(router) m_ExcludedPeers.insert (router->GetIdentHash ()); - m_LastRequestTime = i2p::util::GetSecondsSinceEpoch (); + m_LastRequestTime = i2p::util::GetMillisecondsSinceEpoch (); m_NumAttempts++; return msg; } @@ -55,7 +55,7 @@ namespace data i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers); m_ExcludedPeers.insert (floodfill); m_NumAttempts++; - m_LastRequestTime = i2p::util::GetSecondsSinceEpoch (); + m_LastRequestTime = i2p::util::GetMillisecondsSinceEpoch (); return msg; } @@ -210,7 +210,7 @@ namespace data void NetDbRequests::ManageRequests () { - uint64_t ts = i2p::util::GetSecondsSinceEpoch (); + uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();) { auto& dest = it->second; @@ -328,7 +328,8 @@ namespace data void NetDbRequests::ScheduleManageRequests () { - m_ManageRequestsTimer.expires_from_now (boost::posix_time::seconds(MANAGE_REQUESTS_INTERVAL)); + m_ManageRequestsTimer.expires_from_now (boost::posix_time::milliseconds(MANAGE_REQUESTS_INTERVAL + + m_Rng () % MANAGE_REQUESTS_INTERVAL_VARIANCE)); m_ManageRequestsTimer.async_wait (std::bind (&NetDbRequests::HandleManageRequestsTimer, this, std::placeholders::_1)); } diff --git a/libi2pd/NetDbRequests.h b/libi2pd/NetDbRequests.h index 1758d498..86fdb2dd 100644 --- a/libi2pd/NetDbRequests.h +++ b/libi2pd/NetDbRequests.h @@ -24,15 +24,16 @@ namespace i2p namespace data { const int MAX_NUM_REQUEST_ATTEMPTS = 5; - const uint64_t MANAGE_REQUESTS_INTERVAL = 1; // in seconds - const uint64_t MIN_REQUEST_TIME = 5; // in seconds - const uint64_t MAX_REQUEST_TIME = MAX_NUM_REQUEST_ATTEMPTS * (MIN_REQUEST_TIME + MANAGE_REQUESTS_INTERVAL); + const uint64_t MANAGE_REQUESTS_INTERVAL = 400; // in milliseconds + const uint64_t MANAGE_REQUESTS_INTERVAL_VARIANCE = 300; // in milliseconds + const uint64_t MIN_REQUEST_TIME = 1200; // in milliseconds + const uint64_t MAX_REQUEST_TIME = MAX_NUM_REQUEST_ATTEMPTS * (MIN_REQUEST_TIME + MANAGE_REQUESTS_INTERVAL + MANAGE_REQUESTS_INTERVAL_VARIANCE); const uint64_t EXPLORATORY_REQUEST_INTERVAL = 55; // in seconds const uint64_t EXPLORATORY_REQUEST_INTERVAL_VARIANCE = 170; // in seconds const uint64_t DISCOVERED_REQUEST_INTERVAL = 360; // in milliseconds const uint64_t DISCOVERED_REQUEST_INTERVAL_VARIANCE = 540; // in milliseconds - const uint64_t MAX_EXPLORATORY_REQUEST_TIME = 30; // in seconds - const uint64_t REQUEST_CACHE_TIME = MAX_REQUEST_TIME + 40; // in seconds + const uint64_t MAX_EXPLORATORY_REQUEST_TIME = 30000; // in milliseconds + const uint64_t REQUEST_CACHE_TIME = MAX_REQUEST_TIME + 40000; // in milliseconds const uint64_t REQUESTED_DESTINATIONS_POOL_CLEANUP_INTERVAL = 191; // in seconds class RequestedDestination @@ -71,7 +72,7 @@ namespace data IdentHash m_Destination; bool m_IsExploratory, m_IsDirect, m_IsActive; std::unordered_set m_ExcludedPeers; - uint64_t m_CreationTime, m_LastRequestTime; // in seconds + uint64_t m_CreationTime, m_LastRequestTime; // in milliseconds std::list m_RequestComplete; int m_NumAttempts; }; @@ -115,9 +116,9 @@ namespace data private: + i2p::util::MemoryPoolMt m_RequestedDestinationsPool; std::unordered_map > m_RequestedDestinations; std::list m_DiscoveredRouterHashes; - i2p::util::MemoryPoolMt m_RequestedDestinationsPool; boost::asio::deadline_timer m_ManageRequestsTimer, m_ExploratoryTimer, m_CleanupTimer, m_DiscoveredRoutersTimer; std::mt19937 m_Rng; From 8713974f4017a2a9e471424a1a4370c28de476d7 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 29 Dec 2024 17:25:54 -0500 Subject: [PATCH 307/527] 2.55.0 --- ChangeLog | 43 ++++++++++++++++++++++++++++++++++++++- contrib/rpm/i2pd-git.spec | 5 ++++- contrib/rpm/i2pd.spec | 5 ++++- debian/changelog | 6 ++++++ libi2pd/version.h | 2 +- 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index b3559fb7..4d058113 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,47 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.55.0] - 2024-12-30 +### Added +- Support boost 1.87 +- "i2p.streaming.maxConcurrentStreams" tunnel's param to limit number of simultaneous streams +- Separate thread for tunnel build requests +- Show next peer and connectivity on "Transit tunnels" page +- Tunnel name for local destination thread +- Throttle incoming ECIESx25519 sessions +- Send tunnel data to transport session directly if possible +- Publish 'R' cap for yggdrasil-only routers, and 'U' cap for routers through proxy +- Random tunnel rejection when medium congestion +- Save unreachable router's endpoint to use it next time without introducers +- Recognize symmetric NAT from peer test message 7 +- Resend HolePunch and RelayResponse messages +### Changed +- Removed own implementation of AESNI and always use one from openssl +- Renamed main thread to i2pd-daemon +- Set i2p.streaming.profile=2 for shared local destination +- Reduced LeaseSet and RouterInfo lookup timeouts +- Cleanup ECIES sessions and tags more often +- Check LeaseSet expiration time +- Handle NTCP2 session handshakes in separate thread +- Limit last decline time by 1.5 hours in router's profile +- Don't handle RelayRequest and RelayIntro with same nonce twice +- Increased hole punch expiration interval +- Send peer test message 6 with delay if message 4 was received before message 5 +- Pre-calculate more x25519 keys for transports in runtime +- Don't request LeaseSet for incoming stream +- Terminate incoming stream right away if no remote LeaseSet +- Handle choked, new RTO and window size calculation and resetting algorithm for streams +### Fixed +- Empty string in addressbook subscriptions +- ECIESx25519 sessions without destination +- Missing RouterInfo buffer in NetDb +- Invalid I2PControl certificate +- Routers disappear from NetDb when offline +- Peer test message 6 sent to unknown endpoint +- Race condition with LeaseSet update +- Excessive CPU usage by streams +- Crash on shutdown + ## [2.54.0] - 2024-10-06 ### Added - Maintain recently connected routers list to avoid false-positive peer test @@ -154,7 +195,7 @@ - New SSU2 session gets teminated upon termination of old one - Peer test to non-supporting router - Streaming ackThrough off 1 if number of NACKs exceeds 255 -- Race condition in ECIESx25519 tags table +- Race condition in tags table - Good tunnel becomes failed - Crash when packet comes to terminated stream - Stream hangs during LeaseSet update diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 05158bc9..fb5dfb52 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -1,7 +1,7 @@ %define git_hash %(git rev-parse HEAD | cut -c -7) Name: i2pd-git -Version: 2.54.0 +Version: 2.55.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -148,6 +148,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Mon Dec 30 2024 orignal - 2.55.0 +- update to 2.55.0 + * Sun Oct 6 2024 orignal - 2.54.0 - update to 2.54.0 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 4b1e573b..ed85a079 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.54.0 +Version: 2.55.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git @@ -146,6 +146,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Mon Dec 30 2024 orignal - 2.55.0 +- update to 2.55.0 + * Sun Oct 6 2024 orignal - 2.54.0 - update to 2.54.0 diff --git a/debian/changelog b/debian/changelog index fd7b8d57..d84ae445 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.55.0-1) unstable; urgency=medium + + * updated to version 2.55.0 + + -- orignal Mon, 30 Dec 2024 16:00:00 +0000 + i2pd (2.54.0-1) unstable; urgency=medium * updated to version 2.54.0/0.9.64 diff --git a/libi2pd/version.h b/libi2pd/version.h index 40d07845..09209c1c 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -18,7 +18,7 @@ #define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 54 +#define I2PD_VERSION_MINOR 55 #define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #ifdef GITVER From 24bcc651e00593dd4fa06b259cbb69b8ad01169f Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 29 Dec 2024 17:44:32 -0500 Subject: [PATCH 308/527] Fixed typo --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 4d058113..e638a919 100644 --- a/ChangeLog +++ b/ChangeLog @@ -195,7 +195,7 @@ - New SSU2 session gets teminated upon termination of old one - Peer test to non-supporting router - Streaming ackThrough off 1 if number of NACKs exceeds 255 -- Race condition in tags table +- Race condition in ECIESx25519 tags table - Good tunnel becomes failed - Crash when packet comes to terminated stream - Stream hangs during LeaseSet update From 1293e122bcbe035a1c9c5370b4f473a5bb66719a Mon Sep 17 00:00:00 2001 From: r4sas Date: Mon, 30 Dec 2024 21:44:54 +0000 Subject: [PATCH 309/527] [deb] update patch Signed-off-by: r4sas --- contrib/debian/trusty/patches/01-upnp.patch | 6 +++--- contrib/debian/xenial/patches/01-upnp.patch | 6 +++--- debian/patches/01-upnp.patch | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/contrib/debian/trusty/patches/01-upnp.patch b/contrib/debian/trusty/patches/01-upnp.patch index bec8f2b0..74d36c06 100644 --- a/contrib/debian/trusty/patches/01-upnp.patch +++ b/contrib/debian/trusty/patches/01-upnp.patch @@ -2,13 +2,13 @@ Description: Enable UPnP usage in package Author: r4sas Reviewed-By: r4sas -Last-Update: 2022-03-23 +Last-Update: 2024-12-30 --- i2pd.orig/Makefile +++ i2pd/Makefile -@@ -31,7 +31,7 @@ include filelist.mk +@@ -31,7 +31,7 @@ # import source files lists + include filelist.mk - USE_AESNI := $(or $(USE_AESNI),yes) USE_STATIC := $(or $(USE_STATIC),no) -USE_UPNP := $(or $(USE_UPNP),no) +USE_UPNP := $(or $(USE_UPNP),yes) diff --git a/contrib/debian/xenial/patches/01-upnp.patch b/contrib/debian/xenial/patches/01-upnp.patch index bec8f2b0..74d36c06 100644 --- a/contrib/debian/xenial/patches/01-upnp.patch +++ b/contrib/debian/xenial/patches/01-upnp.patch @@ -2,13 +2,13 @@ Description: Enable UPnP usage in package Author: r4sas Reviewed-By: r4sas -Last-Update: 2022-03-23 +Last-Update: 2024-12-30 --- i2pd.orig/Makefile +++ i2pd/Makefile -@@ -31,7 +31,7 @@ include filelist.mk +@@ -31,7 +31,7 @@ # import source files lists + include filelist.mk - USE_AESNI := $(or $(USE_AESNI),yes) USE_STATIC := $(or $(USE_STATIC),no) -USE_UPNP := $(or $(USE_UPNP),no) +USE_UPNP := $(or $(USE_UPNP),yes) diff --git a/debian/patches/01-upnp.patch b/debian/patches/01-upnp.patch index bec8f2b0..74d36c06 100644 --- a/debian/patches/01-upnp.patch +++ b/debian/patches/01-upnp.patch @@ -2,13 +2,13 @@ Description: Enable UPnP usage in package Author: r4sas Reviewed-By: r4sas -Last-Update: 2022-03-23 +Last-Update: 2024-12-30 --- i2pd.orig/Makefile +++ i2pd/Makefile -@@ -31,7 +31,7 @@ include filelist.mk +@@ -31,7 +31,7 @@ # import source files lists + include filelist.mk - USE_AESNI := $(or $(USE_AESNI),yes) USE_STATIC := $(or $(USE_STATIC),no) -USE_UPNP := $(or $(USE_UPNP),no) +USE_UPNP := $(or $(USE_UPNP),yes) From 619ec5d9c1dd26df267cc6ef39f463558d309540 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 2 Jan 2025 09:04:57 -0500 Subject: [PATCH 310/527] fixed AEAD/Chacha20/Poly1305 test --- tests/test-aeadchacha20poly1305.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test-aeadchacha20poly1305.cpp b/tests/test-aeadchacha20poly1305.cpp index 64a0f358..265b831a 100644 --- a/tests/test-aeadchacha20poly1305.cpp +++ b/tests/test-aeadchacha20poly1305.cpp @@ -54,7 +54,8 @@ int main () // test encryption of multiple buffers memcpy (buf, text, 114); std::vector > bufs{ std::make_pair (buf, 20), std::make_pair (buf + 20, 10), std::make_pair (buf + 30, 70), std::make_pair (buf + 100, 14) }; - i2p::crypto::AEADChaCha20Poly1305Encrypt (bufs, key, nonce, buf + 114); + i2p::crypto::AEADChaCha20Poly1305Encryptor encryptor; + encryptor.Encrypt (bufs, key, nonce, buf + 114); i2p::crypto::AEADChaCha20Poly1305 (buf, 114, nullptr, 0, key, nonce, buf1, 114, false); assert (memcmp (buf1, text, 114) == 0); } From fc16a70f7bad5befe972f0d70c714e705feb77a5 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 2 Jan 2025 18:30:16 -0500 Subject: [PATCH 311/527] use AEADChaCha20Poly1305Encryptor and AEADChaCha20Poly1305Decryptor for test --- tests/test-aeadchacha20poly1305.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test-aeadchacha20poly1305.cpp b/tests/test-aeadchacha20poly1305.cpp index 265b831a..2ba6a253 100644 --- a/tests/test-aeadchacha20poly1305.cpp +++ b/tests/test-aeadchacha20poly1305.cpp @@ -43,19 +43,20 @@ uint8_t encrypted[114] = int main () { uint8_t buf[114+16]; + i2p::crypto::AEADChaCha20Poly1305Encryptor encryptor; // test encryption - i2p::crypto::AEADChaCha20Poly1305 ((uint8_t *)text, 114, ad, 12, key, nonce, buf, 114 + 16, true); + encryptor.Encrypt ((uint8_t *)text, 114, ad, 12, key, nonce, buf, 114 + 16); assert (memcmp (buf, encrypted, 114) == 0); assert (memcmp (buf + 114, tag, 16) == 0); // test decryption uint8_t buf1[114]; - assert (i2p::crypto::AEADChaCha20Poly1305 (buf, 114, ad, 12, key, nonce, buf1, 114, false)); + i2p::crypto::AEADChaCha20Poly1305Decryptor decryptor; + assert (decryptor.Decrypt (buf, 114, ad, 12, key, nonce, buf1, 114)); assert (memcmp (buf1, text, 114) == 0); // test encryption of multiple buffers memcpy (buf, text, 114); std::vector > bufs{ std::make_pair (buf, 20), std::make_pair (buf + 20, 10), std::make_pair (buf + 30, 70), std::make_pair (buf + 100, 14) }; - i2p::crypto::AEADChaCha20Poly1305Encryptor encryptor; encryptor.Encrypt (bufs, key, nonce, buf + 114); - i2p::crypto::AEADChaCha20Poly1305 (buf, 114, nullptr, 0, key, nonce, buf1, 114, false); + decryptor.Decrypt (buf, 114, nullptr, 0, key, nonce, buf1, 114); assert (memcmp (buf1, text, 114) == 0); } From 18707dd844dff973ce9fe4c9181bda9a70ca4d27 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Jan 2025 22:04:09 -0500 Subject: [PATCH 312/527] don't recalculate and process ranges for every Ack block --- libi2pd/SSU2Session.cpp | 166 ++++++++++++++++++++++------------------ libi2pd/SSU2Session.h | 4 +- 2 files changed, 94 insertions(+), 76 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 284ab4d8..bcfce662 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022-2024, The PurpleI2P Project +* Copyright (c) 2022-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -92,7 +92,7 @@ namespace transport m_RTO (SSU2_INITIAL_RTO), m_RelayTag (0),m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose), m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32), // min size - m_LastResendTime (0), m_LastResendAttemptTime (0) + m_LastResendTime (0), m_LastResendAttemptTime (0), m_NumRanges (0) { if (noise) m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState); @@ -1744,6 +1744,7 @@ namespace transport HandleAckRange (firstPacketNum, ackThrough, i2p::util::GetMillisecondsSinceEpoch ()); // acnt // ranges len -= 5; + if (!len || m_SentPackets.empty ()) return; // don't handle ranges if nothing to acknowledge const uint8_t * ranges = buf + 5; while (len > 0 && firstPacketNum && ackThrough - firstPacketNum < SSU2_MAX_NUM_ACK_PACKETS) { @@ -2624,17 +2625,17 @@ namespace transport size_t SSU2Session::CreateAckBlock (uint8_t * buf, size_t len) { if (len < 8) return 0; - int maxNumRanges = (len - 8) >> 1; - if (maxNumRanges > SSU2_MAX_NUM_ACK_RANGES) maxNumRanges = SSU2_MAX_NUM_ACK_RANGES; buf[0] = eSSU2BlkAck; uint32_t ackThrough = m_OutOfSequencePackets.empty () ? m_ReceivePacketNum : *m_OutOfSequencePackets.rbegin (); htobe32buf (buf + 3, ackThrough); // Ack Through uint16_t acnt = 0; - int numRanges = 0; if (ackThrough) { if (m_OutOfSequencePackets.empty ()) + { acnt = std::min ((int)ackThrough, SSU2_MAX_NUM_ACNT); // no gaps + m_NumRanges = 0; + } else { auto it = m_OutOfSequencePackets.rbegin (); it++; // prev packet num @@ -2647,87 +2648,96 @@ namespace transport it++; } // ranges - uint32_t lastNum = ackThrough - acnt; - if (acnt > SSU2_MAX_NUM_ACNT) - { - auto d = std::div (acnt - SSU2_MAX_NUM_ACNT, SSU2_MAX_NUM_ACNT); - acnt = SSU2_MAX_NUM_ACNT; - if (d.quot > maxNumRanges) + if (!m_NumRanges) + { + int maxNumRanges = (len - 8) >> 1; + if (maxNumRanges > SSU2_MAX_NUM_ACK_RANGES) maxNumRanges = SSU2_MAX_NUM_ACK_RANGES; + int numRanges = 0; + uint32_t lastNum = ackThrough - acnt; + if (acnt > SSU2_MAX_NUM_ACNT) { - d.quot = maxNumRanges; - d.rem = 0; - } - // Acks only ranges for acnt - for (int i = 0; i < d.quot; i++) - { - buf[8 + numRanges*2] = 0; buf[8 + numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // NACKs 0, Acks 255 - numRanges++; - } - if (d.rem > 0) - { - buf[8 + numRanges*2] = 0; buf[8 + numRanges*2 + 1] = d.rem; - numRanges++; - } - } - int numPackets = acnt + numRanges*SSU2_MAX_NUM_ACNT; - while (it != m_OutOfSequencePackets.rend () && - numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS) - { - if (lastNum - (*it) > SSU2_MAX_NUM_ACNT) - { - // NACKs only ranges - if (lastNum > (*it) + SSU2_MAX_NUM_ACNT*(maxNumRanges - numRanges)) break; // too many NACKs - while (lastNum - (*it) > SSU2_MAX_NUM_ACNT) + auto d = std::div (acnt - SSU2_MAX_NUM_ACNT, SSU2_MAX_NUM_ACNT); + acnt = SSU2_MAX_NUM_ACNT; + if (d.quot > maxNumRanges) { - buf[8 + numRanges*2] = SSU2_MAX_NUM_ACNT; buf[8 + numRanges*2 + 1] = 0; // NACKs 255, Acks 0 - lastNum -= SSU2_MAX_NUM_ACNT; + d.quot = maxNumRanges; + d.rem = 0; + } + // Acks only ranges for acnt + for (int i = 0; i < d.quot; i++) + { + m_Ranges[numRanges*2] = 0; m_Ranges[numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // NACKs 0, Acks 255 + numRanges++; + } + if (d.rem > 0) + { + m_Ranges[numRanges*2] = 0; m_Ranges[numRanges*2 + 1] = d.rem; numRanges++; - numPackets += SSU2_MAX_NUM_ACNT; } } - // NACKs and Acks ranges - buf[8 + numRanges*2] = lastNum - (*it) - 1; // NACKs - numPackets += buf[8 + numRanges*2]; - lastNum = *it; it++; - int numAcks = 1; - while (it != m_OutOfSequencePackets.rend () && lastNum > 0 && *it == lastNum - 1) + int numPackets = acnt + numRanges*SSU2_MAX_NUM_ACNT; + while (it != m_OutOfSequencePackets.rend () && + numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS) { - numAcks++; lastNum--; - it++; - } - while (numAcks > SSU2_MAX_NUM_ACNT) - { - // Acks only ranges - buf[8 + numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // Acks 255 - numAcks -= SSU2_MAX_NUM_ACNT; - numRanges++; - numPackets += SSU2_MAX_NUM_ACNT; - buf[8 + numRanges*2] = 0; // NACKs 0 - if (numRanges >= maxNumRanges || numPackets >= SSU2_MAX_NUM_ACK_PACKETS) break; - } - if (numAcks > SSU2_MAX_NUM_ACNT) numAcks = SSU2_MAX_NUM_ACNT; - buf[8 + numRanges*2 + 1] = (uint8_t)numAcks; // Acks - numPackets += numAcks; - numRanges++; - } - if (it == m_OutOfSequencePackets.rend () && - numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS) - { - // add range between out-of-sequence and received - int nacks = *m_OutOfSequencePackets.begin () - m_ReceivePacketNum - 1; - if (nacks > 0) - { - if (nacks > SSU2_MAX_NUM_ACNT) nacks = SSU2_MAX_NUM_ACNT; - buf[8 + numRanges*2] = nacks; - buf[8 + numRanges*2 + 1] = std::min ((int)m_ReceivePacketNum + 1, SSU2_MAX_NUM_ACNT); + if (lastNum - (*it) > SSU2_MAX_NUM_ACNT) + { + // NACKs only ranges + if (lastNum > (*it) + SSU2_MAX_NUM_ACNT*(maxNumRanges - numRanges)) break; // too many NACKs + while (lastNum - (*it) > SSU2_MAX_NUM_ACNT) + { + m_Ranges[numRanges*2] = SSU2_MAX_NUM_ACNT; m_Ranges[numRanges*2 + 1] = 0; // NACKs 255, Acks 0 + lastNum -= SSU2_MAX_NUM_ACNT; + numRanges++; + numPackets += SSU2_MAX_NUM_ACNT; + } + } + // NACKs and Acks ranges + m_Ranges[numRanges*2] = lastNum - (*it) - 1; // NACKs + numPackets += m_Ranges[numRanges*2]; + lastNum = *it; it++; + int numAcks = 1; + while (it != m_OutOfSequencePackets.rend () && lastNum > 0 && *it == lastNum - 1) + { + numAcks++; lastNum--; + it++; + } + while (numAcks > SSU2_MAX_NUM_ACNT) + { + // Acks only ranges + m_Ranges[numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // Acks 255 + numAcks -= SSU2_MAX_NUM_ACNT; + numRanges++; + numPackets += SSU2_MAX_NUM_ACNT; + m_Ranges[numRanges*2] = 0; // NACKs 0 + if (numRanges >= maxNumRanges || numPackets >= SSU2_MAX_NUM_ACK_PACKETS) break; + } + if (numAcks > SSU2_MAX_NUM_ACNT) numAcks = SSU2_MAX_NUM_ACNT; + m_Ranges[numRanges*2 + 1] = (uint8_t)numAcks; // Acks + numPackets += numAcks; numRanges++; } - } + if (it == m_OutOfSequencePackets.rend () && + numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS) + { + // add range between out-of-sequence and received + int nacks = *m_OutOfSequencePackets.begin () - m_ReceivePacketNum - 1; + if (nacks > 0) + { + if (nacks > SSU2_MAX_NUM_ACNT) nacks = SSU2_MAX_NUM_ACNT; + m_Ranges[numRanges*2] = nacks; + m_Ranges[numRanges*2 + 1] = std::min ((int)m_ReceivePacketNum + 1, SSU2_MAX_NUM_ACNT); + numRanges++; + } + } + m_NumRanges = numRanges; + } + if (m_NumRanges) + memcpy (buf + 8, m_Ranges, m_NumRanges*2); } } buf[7] = (uint8_t)acnt; // acnt - htobe16buf (buf + 1, 5 + numRanges*2); - return 8 + numRanges*2; + htobe16buf (buf + 1, 5 + m_NumRanges*2); + return 8 + m_NumRanges*2; } size_t SSU2Session::CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize) @@ -2961,11 +2971,17 @@ namespace transport } m_OutOfSequencePackets.erase (m_OutOfSequencePackets.begin (), it); } + m_NumRanges = 0; // recalculate ranges when create next Ack } m_ReceivePacketNum = packetNum; } else + { + if (m_NumRanges && (m_OutOfSequencePackets.empty () || + packetNum != (*m_OutOfSequencePackets.rbegin ()) + 1)) + m_NumRanges = 0; // reset ranges if received packet is not next m_OutOfSequencePackets.insert (packetNum); + } return true; } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index acd46dd1..ee295acb 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022-2024, The PurpleI2P Project +* Copyright (c) 2022-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -397,6 +397,8 @@ namespace transport 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; + uint8_t m_Ranges[SSU2_MAX_NUM_ACK_RANGES*2]; // ranges sent with previous Ack if any }; inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) From 3236de0d5af92a32fff6e96178ed9bf0abb19d0f Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 6 Jan 2025 19:36:15 -0500 Subject: [PATCH 313/527] reduce publishing confimation intervals --- libi2pd/Destination.cpp | 17 +++++++++-------- libi2pd/Destination.h | 7 ++++--- libi2pd/RouterContext.cpp | 6 +++--- libi2pd/RouterContext.h | 4 ++-- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index b12038d4..32182c37 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.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 * @@ -597,7 +597,8 @@ namespace client m_ExcludedFloodfills.clear (); m_PublishReplyToken = 0; // schedule verification - m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT)); + m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT + + (m_Pool ? m_Pool->GetRng ()() % PUBLISH_VERIFICATION_TIMEOUT_VARIANCE : 0))); m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, shared_from_this (), std::placeholders::_1)); } @@ -676,8 +677,8 @@ namespace client m_ExcludedFloodfills.clear (); m_PublishReplyToken = 1; // dummy non-zero value // try again after a while - LogPrint (eLogInfo, "Destination: Can't publish LeasetSet because destination is not ready. Try publishing again after ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds"); - m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); + LogPrint (eLogInfo, "Destination: Can't publish LeasetSet because destination is not ready. Try publishing again after ", PUBLISH_CONFIRMATION_TIMEOUT, " milliseconds"); + m_PublishConfirmationTimer.expires_from_now (boost::posix_time::milliseconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer, shared_from_this (), std::placeholders::_1)); return; @@ -696,7 +697,7 @@ namespace client s->HandlePublishConfirmationTimer (boost::system::error_code()); }); }; - m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); + m_PublishConfirmationTimer.expires_from_now (boost::posix_time::milliseconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer, shared_from_this (), std::placeholders::_1)); outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0, msg); @@ -712,15 +713,15 @@ 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 or failed. will try again"); + LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " milliseconds or failed. will try again"); Publish (); } else { - LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds from Java floodfill for crypto type ", (int)GetIdentity ()->GetCryptoKeyType ()); + LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " milliseconds from Java floodfill for crypto type ", (int)GetIdentity ()->GetCryptoKeyType ()); // Java floodfill never sends confirmation back for unknown crypto type // assume it successive and try to verify - m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT)); + m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT + PUBLISH_VERIFICATION_TIMEOUT_VARIANCE)); // always max m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, shared_from_this (), std::placeholders::_1)); diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 70c7ed39..4278f1fd 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.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 * @@ -36,8 +36,9 @@ namespace client const uint8_t PROTOCOL_TYPE_STREAMING = 6; const uint8_t PROTOCOL_TYPE_DATAGRAM = 17; const uint8_t PROTOCOL_TYPE_RAW = 18; - const int PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds - const int PUBLISH_VERIFICATION_TIMEOUT = 10; // in seconds after successful publish + const int PUBLISH_CONFIRMATION_TIMEOUT = 1800; // in milliseconds + const int PUBLISH_VERIFICATION_TIMEOUT = 5; // in seconds after successful publish + const int PUBLISH_VERIFICATION_TIMEOUT_VARIANCE = 3; // in seconds const int PUBLISH_MIN_INTERVAL = 20; // in seconds const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically const int LEASESET_REQUEST_TIMEOUT = 1600; // in milliseconds diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index fdcdb145..7dfb97e4 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.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 * @@ -1434,7 +1434,7 @@ namespace i2p i2p::garlic::WrapECIESX25519MessageForRouter (msg, floodfill->GetIdentity ()->GetEncryptionPublicKey ())); } else - LogPrint (eLogInfo, "Router: Can't publish our RouterInfo. No tunnles. Try again in ", ROUTER_INFO_CONFIRMATION_TIMEOUT, " seconds"); + LogPrint (eLogInfo, "Router: Can't publish our RouterInfo. No tunnels. Try again in ", ROUTER_INFO_CONFIRMATION_TIMEOUT, " milliseconds"); } m_PublishExcluded.insert (floodfill->GetIdentHash ()); m_PublishReplyToken = replyToken; @@ -1448,7 +1448,7 @@ namespace i2p if (m_PublishTimer) { m_PublishTimer->cancel (); - m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CONFIRMATION_TIMEOUT)); + m_PublishTimer->expires_from_now (boost::posix_time::milliseconds(ROUTER_INFO_CONFIRMATION_TIMEOUT)); m_PublishTimer->async_wait (std::bind (&RouterContext::HandlePublishResendTimer, this, std::placeholders::_1)); } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 5060866a..6fb06fc1 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.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 * @@ -34,7 +34,7 @@ namespace garlic const int ROUTER_INFO_PUBLISH_INTERVAL = 39*60; // in seconds const int ROUTER_INFO_INITIAL_PUBLISH_INTERVAL = 10; // in seconds const int ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE = 105;// in seconds - const int ROUTER_INFO_CONFIRMATION_TIMEOUT = 5; // in seconds + const int ROUTER_INFO_CONFIRMATION_TIMEOUT = 1600; // in milliseconds 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 = 102; // in seconds From fce4fab07146d3f2a563e762e151cfe45891927c Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 7 Jan 2025 13:58:19 -0500 Subject: [PATCH 314/527] configurable shared local destination --- libi2pd/Config.cpp | 14 +++++++++++++- libi2pd_client/ClientContext.cpp | 15 +++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index fc1b2272..cd5b0200 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.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 * @@ -154,6 +154,17 @@ namespace config { ("socksproxy.i2p.streaming.profile", value()->default_value("1"), "SOCKS Proxy bandwidth usage profile. 1 - bulk(high), 2- interactive(low)") ; + options_description shareddest("Shared local destination options"); + shareddest.add_options() + ("shareddest.inbound.length", value()->default_value("3"), "Shared local destination inbound tunnel length") + ("shareddest.outbound.length", value()->default_value("3"), "Shared local destination outbound tunnel length") + ("shareddest.inbound.quantity", value()->default_value("3"), "Shared local destination inbound tunnels quantity") + ("shareddest.outbound.quantity", value()->default_value("3"), "Shared local destination outbound tunnels quantity") + ("shareddest.i2cp.leaseSetType", value()->default_value("3"), "Shared local destination's LeaseSet type") + ("shareddest.i2cp.leaseSetEncType", value()->default_value("0,4"), "Shared local destination's LeaseSet encryption type") + ("shareddest.i2p.streaming.profile", value()->default_value("2"), "Shared local destination bandwidth usage profile. 1 - bulk(high), 2- interactive(low)") + ; + options_description sam("SAM bridge options"); sam.add_options() ("sam.enabled", value()->default_value(true), "Enable or disable SAM Application bridge") @@ -341,6 +352,7 @@ namespace config { .add(httpserver) .add(httpproxy) .add(socksproxy) + .add(shareddest) .add(sam) .add(bob) .add(i2cp) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 8c8c2bfa..570df9b0 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.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 * @@ -416,15 +416,10 @@ namespace client void ClientContext::CreateNewSharedLocalDestination () { - std::map params - { - { I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, "3" }, - { I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, "3" }, - { I2CP_PARAM_LEASESET_TYPE, "3" }, - { I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "0,4" }, - { I2CP_PARAM_OUTBOUND_NICKNAME, "SharedDest" }, - { I2CP_PARAM_STREAMING_PROFILE, "2" } - }; + std::map params; + ReadI2CPOptionsFromConfig ("shareddest.", params); + params[I2CP_PARAM_OUTBOUND_NICKNAME] = "SharedDest"; + m_SharedLocalDestination = CreateNewLocalDestination (false, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL, ¶ms); // non-public, EDDSA m_SharedLocalDestination->Acquire (); From 0b788de627e43396254915dd95e5033e57813388 Mon Sep 17 00:00:00 2001 From: Vort Date: Tue, 7 Jan 2025 22:15:08 +0200 Subject: [PATCH 315/527] fix Windows XP build --- .github/workflows/build-windows.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index e32fdccb..6f10e62b 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -133,6 +133,8 @@ jobs: git clone https://github.com/msys2/MINGW-packages cd MINGW-packages git checkout 4cbb366edf2f268ac3146174b40ce38604646fc5 mingw-w64-boost + cd mingw-w64-boost + sed -i 's/boostorg.jfrog.io\/artifactory\/main/archives.boost.io/' PKGBUILD # headers - name: Get headers package version From 3e3e0e0a6279a790189ad36d1c0c6eac33eae616 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 8 Jan 2025 20:52:38 -0500 Subject: [PATCH 316/527] shorter ack request interval for datagrams --- libi2pd/Datagram.cpp | 13 ++++++++----- libi2pd/Datagram.h | 3 ++- libi2pd/ECIESX25519AEADRatchetSession.cpp | 4 ++-- libi2pd/ECIESX25519AEADRatchetSession.h | 18 ++++++++++-------- libi2pd/Garlic.h | 5 +++-- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 1e0c06cc..1b23bd70 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.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 * @@ -104,8 +104,7 @@ namespace datagram if (verified) { - auto h = identity.GetIdentHash(); - auto session = ObtainSession(h); + auto session = ObtainSession (identity.GetIdentHash()); session->Ack(); auto r = FindReceiver(toPort); if(r) @@ -381,8 +380,12 @@ namespace datagram if (!found) { m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true); - if (!m_RoutingSession->GetOwner () || !m_RoutingSession->IsReadyToSend ()) - m_PendingRoutingSessions.push_back (m_RoutingSession); + if (m_RoutingSession) + { + m_RoutingSession->SetAckRequestInterval (DATAGRAM_SESSION_ACK_REQUEST_INTERVAL); + if (!m_RoutingSession->GetOwner () || !m_RoutingSession->IsReadyToSend ()) + m_PendingRoutingSessions.push_back (m_RoutingSession); + } } } diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index 5a0bfc93..97ade8ce 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.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 * @@ -44,6 +44,7 @@ namespace datagram // max 64 messages buffered in send queue for each datagram session const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64; const uint64_t DATAGRAM_MAX_FLUSH_INTERVAL = 5; // in milliseconds + const int DATAGRAM_SESSION_ACK_REQUEST_INTERVAL = 5500; // in milliseconds class DatagramSession : public std::enable_shared_from_this { diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 0fb85378..bdf5f7f7 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.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 * @@ -913,7 +913,7 @@ namespace garlic } } if (!sendAckRequest && !first && - ((!m_AckRequestMsgID && ts > m_LastAckRequestSendTime + ECIESX25519_ACK_REQUEST_INTERVAL) || // regular request + ((!m_AckRequestMsgID && ts > m_LastAckRequestSendTime + m_AckRequestInterval) || // regular request (m_AckRequestMsgID && ts > m_LastAckRequestSendTime + LEASESET_CONFIRMATION_TIMEOUT))) // previous request failed. try again { // not LeaseSet diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 960dedb8..af3ec8a2 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.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 * @@ -33,7 +33,7 @@ namespace garlic const int ECIESX25519_SESSION_CREATE_TIMEOUT = 3; // in seconds, NSR must be send after NS received const int ECIESX25519_SESSION_ESTABLISH_TIMEOUT = 15; // in seconds const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // in seconds - const int ECIESX25519_ACK_REQUEST_INTERVAL = 33000; // in milliseconds + const int ECIESX25519_DEFAULT_ACK_REQUEST_INTERVAL = 33000; // in milliseconds const int ECIESX25519_ACK_REQUEST_MAX_NUM_ATTEMPTS = 3; const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 8192; // number of tags we request new tagset after const int ECIESX25519_MIN_NUM_GENERATED_TAGS = 24; @@ -164,7 +164,7 @@ namespace garlic ~ECIESX25519AEADRatchetSession (); bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr receiveTagset, int index = 0); - std::shared_ptr WrapSingleMessage (std::shared_ptr msg); + std::shared_ptr WrapSingleMessage (std::shared_ptr msg) override; std::shared_ptr WrapOneTimeMessage (std::shared_ptr msg); const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } @@ -180,11 +180,12 @@ namespace garlic 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); } - bool IsRatchets () const { return true; }; - bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; }; - bool IsTerminated () const { return m_IsTerminated; } - uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; }; - bool CleanupUnconfirmedTags (); // return true if unaswered Ack requests, called from I2CP + bool IsRatchets () const override { return true; }; + bool IsReadyToSend () const override { return m_State != eSessionStateNewSessionSent; }; + bool IsTerminated () const override { return m_IsTerminated; } + uint64_t GetLastActivityTimestamp () const override { return m_LastActivityTimestamp; }; + void SetAckRequestInterval (int interval) override { m_AckRequestInterval = interval; }; + bool CleanupUnconfirmedTags () override; // return true if unaswered Ack requests, called from I2CP protected: @@ -235,6 +236,7 @@ namespace garlic uint64_t m_LastAckRequestSendTime = 0; // milliseconds uint32_t m_AckRequestMsgID = 0; int m_AckRequestNumAttempts = 0; + int m_AckRequestInterval = ECIESX25519_DEFAULT_ACK_REQUEST_INTERVAL; // milliseconds public: diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 5baeeb99..6283d740 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.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 * @@ -116,7 +116,8 @@ namespace garlic virtual bool IsReadyToSend () const { return true; }; virtual bool IsTerminated () const { return !GetOwner (); }; virtual uint64_t GetLastActivityTimestamp () const { return 0; }; // non-zero for rathets only - + virtual void SetAckRequestInterval (int interval) {}; // in milliseconds, override in ECIESX25519AEADRatchetSession + void SetLeaseSetUpdated () { if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated; From 915429bb4901a70e2875695cbfbeacd50a9acd18 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 10 Jan 2025 11:16:07 -0500 Subject: [PATCH 317/527] don't drop routing path if no data received --- libi2pd/Datagram.cpp | 4 ++-- libi2pd/Datagram.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 1b23bd70..732efca7 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -390,9 +390,9 @@ namespace datagram } auto path = m_RoutingSession->GetSharedRoutingPath(); - if (path && m_RoutingSession->IsRatchets () && (m_RoutingSession->CleanupUnconfirmedTags () || - m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT)) + if (path && m_RoutingSession->IsRatchets () && m_RoutingSession->CleanupUnconfirmedTags ()) { + LogPrint (eLogDebug, "Datagram: path reset"); m_RoutingSession->SetSharedRoutingPath (nullptr); path = nullptr; } diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index 97ade8ce..dd358434 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -31,8 +31,6 @@ namespace datagram { // milliseconds for max session idle time const uint64_t DATAGRAM_SESSION_MAX_IDLE = 10 * 60 * 1000; - // milliseconds for how long we try sticking to a dead routing path before trying to switch - const uint64_t DATAGRAM_SESSION_PATH_TIMEOUT = 10 * 1000; // milliseconds interval a routing path is used before switching const uint64_t DATAGRAM_SESSION_PATH_SWITCH_INTERVAL = 20 * 60 * 1000; // milliseconds before lease expire should we try switching leases From efd8e6e65b21dafdce3a017af2bfa4d5098f1e59 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 11 Jan 2025 22:34:18 -0500 Subject: [PATCH 318/527] use string_view in ExtractString and PutString --- libi2pd_client/I2CP.cpp | 18 +++++++++--------- libi2pd_client/I2CP.h | 7 ++++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index f6bc3268..eade0927 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.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 * @@ -555,20 +555,20 @@ namespace client m_IsSending = false; } - std::string I2CPSession::ExtractString (const uint8_t * buf, size_t len) + std::string_view I2CPSession::ExtractString (const uint8_t * buf, size_t len) { uint8_t l = buf[0]; if (l > len) l = len; - return std::string ((const char *)(buf + 1), l); + return { (const char *)(buf + 1), l }; } - size_t I2CPSession::PutString (uint8_t * buf, size_t len, const std::string& str) + size_t I2CPSession::PutString (uint8_t * buf, size_t len, std::string_view str) { auto l = str.length (); if (l + 1 >= len) l = len - 1; if (l > 255) l = 255; // 1 byte max buf[0] = l; - memcpy (buf + 1, str.c_str (), l); + memcpy (buf + 1, str.data (), l); return l + 1; } @@ -578,7 +578,7 @@ namespace client size_t offset = 0; while (offset < len) { - std::string param = ExtractString (buf + offset, len - offset); + auto param = ExtractString (buf + offset, len - offset); offset += param.length () + 1; if (buf[offset] != '=') { @@ -587,7 +587,7 @@ namespace client } offset++; - std::string value = ExtractString (buf + offset, len - offset); + auto value = ExtractString (buf + offset, len - offset); offset += value.length () + 1; if (buf[offset] != ';') { @@ -595,7 +595,7 @@ namespace client break; } offset++; - mapping.insert (std::make_pair (param, value)); + mapping.emplace (param, value); } } @@ -921,7 +921,7 @@ namespace client case 1: // address { auto name = ExtractString (buf + 11, len - 11); - auto addr = i2p::client::context.GetAddressBook ().GetAddress (name); + auto addr = i2p::client::context.GetAddressBook ().GetAddress (std::string (name)); // TODO: GetAddress should take string_view if (!addr || !addr->IsIdentHash ()) { // TODO: handle blinded addresses diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index e929c1e1..d974ebba 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.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 * @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -191,8 +192,8 @@ namespace client void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); - std::string ExtractString (const uint8_t * buf, size_t len); - size_t PutString (uint8_t * buf, size_t len, const std::string& str); + std::string_view ExtractString (const uint8_t * buf, size_t len); + size_t PutString (uint8_t * buf, size_t len, std::string_view str); void ExtractMapping (const uint8_t * buf, size_t len, std::map& mapping); void SendSessionStatusMessage (I2CPSessionStatus status); void SendHostReplyMessage (uint32_t requestID, std::shared_ptr identity); From 634ceceb1cc27f52bb0f122a5878fecc2b6f75d7 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 12 Jan 2025 12:23:26 -0500 Subject: [PATCH 319/527] use std::string_view instead const std::string& --- libi2pd/Blinding.cpp | 6 ++--- libi2pd/Blinding.h | 5 ++-- libi2pd/Identity.cpp | 8 +++---- libi2pd/Identity.h | 5 ++-- libi2pd/Tag.h | 18 ++++++++------ libi2pd_client/AddressBook.cpp | 44 +++++++++++++++++----------------- libi2pd_client/AddressBook.h | 22 +++++++++-------- libi2pd_client/I2CP.cpp | 2 +- 8 files changed, 58 insertions(+), 52 deletions(-) diff --git a/libi2pd/Blinding.cpp b/libi2pd/Blinding.cpp index ced086e1..5266a6eb 100644 --- a/libi2pd/Blinding.cpp +++ b/libi2pd/Blinding.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2022, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -152,11 +152,11 @@ namespace data m_BlindedSigType = m_SigType; } - BlindedPublicKey::BlindedPublicKey (const std::string& b33): + BlindedPublicKey::BlindedPublicKey (std::string_view b33): m_SigType (0) // 0 means invalid, we can't blind DSA, set it later { uint8_t addr[40]; // TODO: define length from b33 - size_t l = i2p::data::Base32ToByteStream (b33.c_str (), b33.length (), addr, 40); + size_t l = i2p::data::Base32ToByteStream (b33.data (), b33.length (), addr, 40); if (l < 32) { LogPrint (eLogError, "Blinding: Malformed b33 ", b33); diff --git a/libi2pd/Blinding.h b/libi2pd/Blinding.h index c78db003..fc11f613 100644 --- a/libi2pd/Blinding.h +++ b/libi2pd/Blinding.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2020, 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 +#include #include #include "Identity.h" @@ -23,7 +24,7 @@ namespace data public: BlindedPublicKey (std::shared_ptr identity, bool clientAuth = false); - BlindedPublicKey (const std::string& b33); // from b33 without .b32.i2p + BlindedPublicKey (std::string_view b33); // from b33 without .b32.i2p std::string ToB33 () const; const uint8_t * GetPublicKey () const { return m_PublicKey.data (); }; diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 2b8b454e..89bf71d4 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.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 * @@ -262,11 +262,11 @@ namespace data return fullLen; } - size_t IdentityEx::FromBase64(const std::string& s) + size_t IdentityEx::FromBase64(std::string_view s) { const size_t slen = s.length(); std::vector buf(slen); // binary data can't exceed base64 - const size_t len = Base64ToByteStream (s.c_str(), slen, buf.data(), slen); + const size_t len = Base64ToByteStream (s.data(), slen, buf.data(), slen); return FromBuffer (buf.data(), len); } @@ -728,9 +728,7 @@ namespace data case SIGNING_KEY_TYPE_RSA_SHA384_3072: case SIGNING_KEY_TYPE_RSA_SHA512_4096: LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA"); -#if (__cplusplus >= 201703L) // C++ 17 or higher [[fallthrough]]; -#endif // no break here case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: i2p::crypto::CreateEDDSA25519RandomKeys (priv, pub); diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index 5edd4545..73c77675 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.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 * @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "Base.h" @@ -99,7 +100,7 @@ namespace data size_t FromBuffer (const uint8_t * buf, size_t len); size_t ToBuffer (uint8_t * buf, size_t len) const; - size_t FromBase64(const std::string& s); + size_t FromBase64(std::string_view s); std::string ToBase64 () const; const Identity& GetStandardIdentity () const { return m_StandardIdentity; }; diff --git a/libi2pd/Tag.h b/libi2pd/Tag.h index 72f181a2..92dfd090 100644 --- a/libi2pd/Tag.h +++ b/libi2pd/Tag.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2023, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -12,10 +12,14 @@ #include #include #include +#include +#include #include "Base.h" -namespace i2p { -namespace data { +namespace i2p +{ +namespace data +{ template class Tag { @@ -70,14 +74,14 @@ namespace data { return std::string (str, str + l); } - size_t FromBase32 (const std::string& s) + size_t FromBase32 (std::string_view s) { - return i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz); + return i2p::data::Base32ToByteStream (s.data (), s.length (), m_Buf, sz); } - size_t FromBase64 (const std::string& s) + size_t FromBase64 (std::string_view s) { - return i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz); + return i2p::data::Base64ToByteStream (s.data (), s.length (), m_Buf, sz); } uint8_t GetBit (int i) const diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index c9452cc6..b5c08d3a 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.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 * @@ -49,22 +49,22 @@ namespace client if (m_IsPersist) i2p::config::GetOption("addressbook.hostsfile", m_HostsFile); } - std::shared_ptr GetAddress (const i2p::data::IdentHash& ident) const; - void AddAddress (std::shared_ptr address); - void RemoveAddress (const i2p::data::IdentHash& ident); + std::shared_ptr GetAddress (const i2p::data::IdentHash& ident) const override; + void AddAddress (std::shared_ptr address) override; + void RemoveAddress (const i2p::data::IdentHash& ident) override; - bool Init (); - int Load (std::map > & addresses); - int LoadLocal (std::map >& addresses); - int Save (const std::map >& addresses); + bool Init () override; + int Load (Addresses& addresses) override; + int LoadLocal (Addresses& addresses) override; + int Save (const Addresses& addresses) override; - void SaveEtag (const i2p::data::IdentHash& subsciption, const std::string& etag, const std::string& lastModified); - bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified); - void ResetEtags (); + void SaveEtag (const i2p::data::IdentHash& subsciption, const std::string& etag, const std::string& lastModified) override; + bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified) override; + void ResetEtags () override; private: - int LoadFromFile (const std::string& filename, std::map >& addresses); // returns -1 if can't open file, otherwise number of records + int LoadFromFile (const std::string& filename, Addresses& addresses); // returns -1 if can't open file, otherwise number of records private: @@ -142,7 +142,7 @@ namespace client storage.Remove( ident.ToBase32() ); } - int AddressBookFilesystemStorage::LoadFromFile (const std::string& filename, std::map >& addresses) + int AddressBookFilesystemStorage::LoadFromFile (const std::string& filename, Addresses& addresses) { int num = 0; std::ifstream f (filename, std::ifstream::in); // in text mode @@ -168,7 +168,7 @@ namespace client return num; } - int AddressBookFilesystemStorage::Load (std::map >& addresses) + int AddressBookFilesystemStorage::Load (Addresses& addresses) { int num = LoadFromFile (indexPath, addresses); if (num < 0) @@ -182,7 +182,7 @@ namespace client return num; } - int AddressBookFilesystemStorage::LoadLocal (std::map >& addresses) + int AddressBookFilesystemStorage::LoadLocal (Addresses& addresses) { int num = LoadFromFile (localPath, addresses); if (num < 0) return 0; @@ -190,7 +190,7 @@ namespace client return num; } - int AddressBookFilesystemStorage::Save (const std::map >& addresses) + int AddressBookFilesystemStorage::Save (const Addresses& addresses) { if (addresses.empty()) { @@ -283,7 +283,7 @@ namespace client //--------------------------------------------------------------------- - Address::Address (const std::string& b32): + Address::Address (std::string_view b32): addressType (eAddressInvalid) { if (b32.length () <= B33_ADDRESS_THRESHOLD) @@ -377,7 +377,7 @@ namespace client m_Subscriptions.clear (); } - std::shared_ptr AddressBook::GetAddress (const std::string& address) + std::shared_ptr AddressBook::GetAddress (std::string_view address) { auto pos = address.find(".b32.i2p"); if (pos != std::string::npos) @@ -404,7 +404,7 @@ namespace client return std::make_shared(dest.GetIdentHash ()); } - std::shared_ptr AddressBook::FindAddress (const std::string& address) + std::shared_ptr AddressBook::FindAddress (std::string_view address) { auto it = m_Addresses.find (address); if (it != m_Addresses.end ()) @@ -609,7 +609,7 @@ namespace client void AddressBook::LoadLocal () { if (!m_Storage) return; - std::map> localAddresses; + AddressBookStorage::Addresses localAddresses; m_Storage->LoadLocal (localAddresses); for (const auto& it: localAddresses) { @@ -766,7 +766,7 @@ namespace client } } - void AddressBook::LookupAddress (const std::string& address) + void AddressBook::LookupAddress (std::string_view address) { std::shared_ptr addr; auto dot = address.find ('.'); @@ -796,7 +796,7 @@ namespace client memset (buf, 0, 4); htobe32buf (buf + 4, nonce); buf[8] = address.length (); - memcpy (buf + 9, address.c_str (), address.length ()); + memcpy (buf + 9, address.data (), address.length ()); datagram->SendDatagramTo (buf, len, addr->identHash, ADDRESS_RESPONSE_DATAGRAM_PORT, ADDRESS_RESOLVER_DATAGRAM_PORT); delete[] buf; } diff --git a/libi2pd_client/AddressBook.h b/libi2pd_client/AddressBook.h index 553ae51b..40946a5c 100644 --- a/libi2pd_client/AddressBook.h +++ b/libi2pd_client/AddressBook.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 * @@ -47,7 +47,7 @@ namespace client i2p::data::IdentHash identHash; std::shared_ptr blindedPublicKey; - Address (const std::string& b32); + Address (std::string_view b32); Address (const i2p::data::IdentHash& hash); bool IsIdentHash () const { return addressType == eAddressIndentHash; }; bool IsValid () const { return addressType != eAddressInvalid; }; @@ -59,15 +59,17 @@ namespace client { public: + typedef std::map, std::less<> > Addresses; + virtual ~AddressBookStorage () {}; virtual std::shared_ptr GetAddress (const i2p::data::IdentHash& ident) const = 0; virtual void AddAddress (std::shared_ptr address) = 0; virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0; virtual bool Init () = 0; - virtual int Load (std::map >& addresses) = 0; - virtual int LoadLocal (std::map >& addresses) = 0; - virtual int Save (const std::map >& addresses) = 0; + virtual int Load (Addresses& addresses) = 0; + virtual int LoadLocal (Addresses& addresses) = 0; + virtual int Save (const Addresses& addresses) = 0; virtual void SaveEtag (const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified) = 0; virtual bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified) = 0; @@ -79,16 +81,16 @@ namespace client class AddressBook { public: - + AddressBook (); ~AddressBook (); void Start (); void StartResolvers (); void Stop (); - std::shared_ptr GetAddress (const std::string& address); + std::shared_ptr GetAddress (std::string_view address); std::shared_ptr GetFullAddress (const std::string& address); - std::shared_ptr FindAddress (const std::string& address); - void LookupAddress (const std::string& address); + std::shared_ptr FindAddress (std::string_view address); + void LookupAddress (std::string_view address); void InsertAddress (const std::string& address, const std::string& jump); // for jump links void InsertFullAddress (std::shared_ptr address); @@ -121,7 +123,7 @@ namespace client private: std::mutex m_AddressBookMutex; - std::map > m_Addresses; + AddressBookStorage::Addresses m_Addresses; std::map > m_Resolvers; // local destination->resolver std::mutex m_LookupsMutex; std::map m_Lookups; // nonce -> address diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index eade0927..6bbf58dd 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -921,7 +921,7 @@ namespace client case 1: // address { auto name = ExtractString (buf + 11, len - 11); - auto addr = i2p::client::context.GetAddressBook ().GetAddress (std::string (name)); // TODO: GetAddress should take string_view + auto addr = i2p::client::context.GetAddressBook ().GetAddress (name); if (!addr || !addr->IsIdentHash ()) { // TODO: handle blinded addresses From 08a680b53d970e88f8cc6600d96a54a2f8452409 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 12 Jan 2025 18:36:35 -0500 Subject: [PATCH 320/527] use std::string_view instead const std::string& --- libi2pd_client/HTTPProxy.cpp | 42 +++++++++++++++++------------------ libi2pd_client/I2PService.cpp | 4 ++-- libi2pd_client/I2PService.h | 4 ++-- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 13e0f571..4c2771b5 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.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 * @@ -60,7 +60,7 @@ namespace proxy { "\r\n" ; - static bool str_rmatch(std::string & str, const char *suffix) + static bool str_rmatch(std::string_view str, const char *suffix) { auto pos = str.rfind (suffix); if (pos == std::string::npos) @@ -84,16 +84,16 @@ namespace proxy { void SentHTTPFailed(const boost::system::error_code & ecode); void HandleStreamRequestComplete (std::shared_ptr stream); /* error helpers */ - void GenericProxyError(const std::string& title, const std::string& description); - void GenericProxyInfo(const std::string& title, const std::string& description); - void HostNotFound(const std::string& host); - void SendProxyError(const std::string& content); + void GenericProxyError(std::string_view title, std::string_view description); + void GenericProxyInfo(std::string_view title, std::string_view description); + void HostNotFound(std::string_view host); + void SendProxyError(std::string_view content); void SendRedirect(const std::string& address); void ForwardToUpstreamProxy(); void HandleUpstreamHTTPProxyConnect(const boost::system::error_code & ec); void HandleUpstreamSocksProxyConnect(const boost::system::error_code & ec); - void HTTPConnect(const std::string & host, uint16_t port); + void HTTPConnect(std::string_view host, uint16_t port); void HandleHTTPConnectStreamRequestComplete(std::shared_ptr stream); typedef std::function ProxyResolvedHandler; @@ -162,23 +162,23 @@ namespace proxy { Done(shared_from_this()); } - void HTTPReqHandler::GenericProxyError(const std::string& title, const std::string& description) { + void HTTPReqHandler::GenericProxyError(std::string_view title, std::string_view description) + { std::stringstream ss; ss << "

" << tr("Proxy error") << ": " << title << "

\r\n"; ss << "

" << description << "

\r\n"; - std::string content = ss.str(); - SendProxyError(content); + SendProxyError(ss.str ()); } - void HTTPReqHandler::GenericProxyInfo(const std::string& title, const std::string& description) { + void HTTPReqHandler::GenericProxyInfo(std::string_view title, std::string_view description) + { std::stringstream ss; ss << "

" << tr("Proxy info") << ": " << title << "

\r\n"; ss << "

" << description << "

\r\n"; - std::string content = ss.str(); - SendProxyError(content); + SendProxyError(ss.str ()); } - void HTTPReqHandler::HostNotFound(const std::string& host) + void HTTPReqHandler::HostNotFound(std::string_view host) { std::stringstream ss; ss << "

" << tr("Proxy error: Host not found") << "

\r\n" @@ -192,11 +192,10 @@ namespace proxy { ss << "
  • second << host << "\">" << js->first << "
  • \r\n"; } ss << "\r\n"; - std::string content = ss.str(); - SendProxyError(content); + SendProxyError(ss.str ()); } - void HTTPReqHandler::SendProxyError(const std::string& content) + void HTTPReqHandler::SendProxyError(std::string_view content) { i2p::http::HTTPRes res; res.code = 500; @@ -473,7 +472,7 @@ namespace proxy { if (dest_host != "") { /* absolute url, replace 'Host' header */ - std::string h = dest_host; + std::string h (dest_host); if (dest_port != 0 && dest_port != 80) h += ":" + std::to_string(dest_port); m_ClientRequest.UpdateHeader("Host", h); @@ -513,7 +512,7 @@ namespace proxy { GenericProxyError(tr("Outproxy failure"), tr("Bad outproxy settings")); } else { LogPrint (eLogWarning, "HTTPProxy: Outproxy failure for ", dest_host, ": no outproxy enabled"); - std::stringstream ss; ss << tr("Host %s is not inside I2P network, but outproxy is not enabled", dest_host.c_str()); + std::stringstream ss; ss << tr("Host %s is not inside I2P network, but outproxy is not enabled", dest_host.c_str ()); GenericProxyError(tr("Outproxy failure"), ss.str()); } return true; @@ -653,11 +652,10 @@ namespace proxy { Terminate(); } - void HTTPReqHandler::HTTPConnect(const std::string & host, uint16_t port) + void HTTPReqHandler::HTTPConnect(std::string_view host, uint16_t port) { LogPrint(eLogDebug, "HTTPProxy: CONNECT ",host, ":", port); - std::string hostname(host); - if(str_rmatch(hostname, ".i2p")) + if(str_rmatch(host, ".i2p")) GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleHTTPConnectStreamRequestComplete, shared_from_this(), std::placeholders::_1), host, port); else diff --git a/libi2pd_client/I2PService.cpp b/libi2pd_client/I2PService.cpp index e9513e48..4ec2648a 100644 --- a/libi2pd_client/I2PService.cpp +++ b/libi2pd_client/I2PService.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 * @@ -107,7 +107,7 @@ namespace client m_ReadyTimerTriggered = false; } - void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, uint16_t port) { + void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, std::string_view dest, uint16_t port) { assert(streamRequestComplete); auto address = i2p::client::context.GetAddressBook ().GetAddress (dest); if (address) diff --git a/libi2pd_client/I2PService.h b/libi2pd_client/I2PService.h index d3ed36fa..d19c28e2 100644 --- a/libi2pd_client/I2PService.h +++ b/libi2pd_client/I2PService.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 * @@ -59,7 +59,7 @@ namespace client if (dest) dest->Acquire (); m_LocalDestination = dest; } - void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, uint16_t port = 0); + void CreateStream (StreamRequestComplete streamRequestComplete, std::string_view dest, uint16_t port = 0); void CreateStream(StreamRequestComplete complete, std::shared_ptr address, uint16_t port); auto& GetService () { return m_LocalDestination->GetService (); } From f2b560658347fcd705c6d3b00dc777a41ce3bfd7 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 13 Jan 2025 20:36:27 -0500 Subject: [PATCH 321/527] store fragments inside m_OutOfSequenceFragments --- libi2pd/TunnelEndpoint.cpp | 15 +++++++-------- libi2pd/TunnelEndpoint.h | 7 ++++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libi2pd/TunnelEndpoint.cpp b/libi2pd/TunnelEndpoint.cpp index b4908a8f..66b7effa 100644 --- a/libi2pd/TunnelEndpoint.cpp +++ b/libi2pd/TunnelEndpoint.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 * @@ -258,9 +258,8 @@ namespace tunnel void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, const uint8_t * fragment, size_t size) { - std::unique_ptr f(new Fragment (isLastFragment, i2p::util::GetMillisecondsSinceEpoch (), size)); - memcpy (f->data.data (), fragment, size); - if (!m_OutOfSequenceFragments.emplace ((uint64_t)msgID << 32 | fragmentNum, std::move (f)).second) + if (!m_OutOfSequenceFragments.try_emplace ((uint64_t)msgID << 32 | fragmentNum, + isLastFragment, i2p::util::GetMillisecondsSinceEpoch (), fragment, size).second) LogPrint (eLogInfo, "TunnelMessage: Duplicate out-of-sequence fragment ", fragmentNum, " of message ", msgID); } @@ -290,7 +289,7 @@ namespace tunnel if (it != m_OutOfSequenceFragments.end ()) { LogPrint (eLogDebug, "TunnelMessage: Out-of-sequence fragment ", (int)msg.nextFragmentNum, " of message ", msgID, " found"); - size_t size = it->second->data.size (); + size_t size = it->second.data.size (); if (msg.data->len + size > msg.data->maxLen) { LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough"); @@ -298,9 +297,9 @@ namespace tunnel *newMsg = *(msg.data); msg.data = newMsg; } - if (msg.data->Concat (it->second->data.data (), size) < size) // concatenate out-of-sync fragment + if (msg.data->Concat (it->second.data.data (), size) < size) // concatenate out-of-sync fragment LogPrint (eLogError, "TunnelMessage: Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen); - if (it->second->isLastFragment) + if (it->second.isLastFragment) // message complete msg.nextFragmentNum = 0; else @@ -349,7 +348,7 @@ namespace tunnel // out-of-sequence fragments for (auto it = m_OutOfSequenceFragments.begin (); it != m_OutOfSequenceFragments.end ();) { - if (ts > it->second->receiveTime + i2p::I2NP_MESSAGE_EXPIRATION_TIMEOUT) + if (ts > it->second.receiveTime + i2p::I2NP_MESSAGE_EXPIRATION_TIMEOUT) it = m_OutOfSequenceFragments.erase (it); else ++it; diff --git a/libi2pd/TunnelEndpoint.h b/libi2pd/TunnelEndpoint.h index ac1e8e87..473e0024 100644 --- a/libi2pd/TunnelEndpoint.h +++ b/libi2pd/TunnelEndpoint.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 * @@ -32,7 +32,8 @@ namespace tunnel struct Fragment { - Fragment (bool last, uint64_t t, size_t size): isLastFragment (last), receiveTime (t), data (size) {}; + Fragment (bool last, uint64_t t, const uint8_t * buf, size_t size): + isLastFragment (last), receiveTime (t), data (buf, buf + size) {}; bool isLastFragment; uint64_t receiveTime; // milliseconds since epoch std::vector data; @@ -67,7 +68,7 @@ namespace tunnel private: std::unordered_map m_IncompleteMessages; - std::unordered_map > m_OutOfSequenceFragments; // ((msgID << 8) + fragment#)->fragment + std::unordered_map m_OutOfSequenceFragments; // ((msgID << 8) + fragment#)->fragment bool m_IsInbound; size_t m_NumReceivedBytes; TunnelMessageBlockEx m_CurrentMessage; From 5f1c599f812ef1cc1c1d1533feb3ee2d777706d6 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 13 Jan 2025 21:37:40 -0500 Subject: [PATCH 322/527] fixed warning --- libi2pd/ECIESX25519AEADRatchetSession.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index af3ec8a2..d17565a8 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -193,7 +193,7 @@ namespace garlic void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; }; void CreateNonce (uint64_t seqn, uint8_t * nonce); void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr& receiveTagset, int index); - bool MessageConfirmed (uint32_t msgID); + bool MessageConfirmed (uint32_t msgID) override; private: From 8c555fe5926f8d69bb62d2b8fd6e9e7494adc572 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 14 Jan 2025 13:30:47 -0500 Subject: [PATCH 323/527] copy fragment faster --- libi2pd/TunnelEndpoint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/TunnelEndpoint.h b/libi2pd/TunnelEndpoint.h index 473e0024..79393efe 100644 --- a/libi2pd/TunnelEndpoint.h +++ b/libi2pd/TunnelEndpoint.h @@ -33,7 +33,7 @@ namespace tunnel struct Fragment { Fragment (bool last, uint64_t t, const uint8_t * buf, size_t size): - isLastFragment (last), receiveTime (t), data (buf, buf + size) {}; + isLastFragment (last), receiveTime (t), data (size) { memcpy (data.data(), buf, size); }; bool isLastFragment; uint64_t receiveTime; // milliseconds since epoch std::vector data; From 4bb82110ab7ac47e2f27bd8efba1fecb35cbc1c4 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 15 Jan 2025 21:13:50 -0500 Subject: [PATCH 324/527] don't create EVP_CIPHER_CTX for each ChaCha20 --- libi2pd/Crypto.cpp | 30 ++++++++++++++++++++++++++---- libi2pd/Crypto.h | 15 ++++++++++++++- libi2pd/SSU2.cpp | 7 ++++++- libi2pd/SSU2.h | 4 +++- libi2pd/SSU2OutOfSession.cpp | 8 ++++---- libi2pd/SSU2Session.cpp | 20 ++++++++++---------- 6 files changed, 63 insertions(+), 21 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 1b663e41..095f25d6 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.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 * @@ -710,19 +710,41 @@ namespace crypto { return AEADChaCha20Poly1305 (m_Ctx, msg, msgLen, ad, adLen, key, nonce, buf, len, false); } - - void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out) + + static void ChaCha20 (EVP_CIPHER_CTX *ctx, const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out) { - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); uint32_t iv[4]; iv[0] = htole32 (1); memcpy (iv + 1, nonce, 12); // counter | nonce EVP_EncryptInit_ex(ctx, EVP_chacha20 (), NULL, key, (const uint8_t *)iv); int outlen = 0; EVP_EncryptUpdate(ctx, out, &outlen, msg, msgLen); EVP_EncryptFinal_ex(ctx, NULL, &outlen); + } + + void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out) + { + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); + ChaCha20 (ctx, msg, msgLen, key, nonce, out); EVP_CIPHER_CTX_free (ctx); } + + ChaCha20Context::ChaCha20Context () + { + m_Ctx = EVP_CIPHER_CTX_new (); + } + + ChaCha20Context::~ChaCha20Context () + { + if (m_Ctx) + EVP_CIPHER_CTX_free (m_Ctx); + } + + void ChaCha20Context::operator ()(const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out) + { + ChaCha20 (m_Ctx, msg, msgLen, key, nonce, out); + } + void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out, size_t outLen) { diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 75b259a5..051f214f 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.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 * @@ -226,6 +226,19 @@ namespace crypto // ChaCha20 void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out); + class ChaCha20Context + { + public: + + ChaCha20Context (); + ~ChaCha20Context (); + void operator ()(const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out); + + private: + + EVP_CIPHER_CTX * m_Ctx; + }; + // HKDF void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out, size_t outLen = 64); // salt - 32, out - 32 or 64, info <= 32 diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index cbd6d38e..e6d62801 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022-2024, The PurpleI2P Project +* Copyright (c) 2022-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -1527,6 +1527,11 @@ namespace transport { return m_Decryptor.Decrypt (msg, msgLen, ad, adLen, key, nonce, buf, len); } + + void SSU2Server::ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out) + { + m_ChaCha20 (msg, msgLen, key, nonce, out); + } void SSU2Server::SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index d6ff415b..a8598ce3 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022-2024, The PurpleI2P Project +* Copyright (c) 2022-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -86,6 +86,7 @@ namespace transport const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); bool AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); + void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out); bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; } bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; void AdjustTimeOffset (int64_t offset, std::shared_ptr from); @@ -206,6 +207,7 @@ namespace transport mutable std::mutex m_ReceivedPacketsQueueMutex; i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor; i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor; + i2p::crypto::ChaCha20Context m_ChaCha20; // proxy bool m_IsThroughProxy; diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index 333c1c92..c4a6f9e4 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024, The PurpleI2P Project +* Copyright (c) 2024-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -46,7 +46,7 @@ namespace transport } uint8_t nonce[12] = {0}; uint64_t headerX[2]; // sourceConnID, token - i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); + GetServer ().ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); SetDestConnID (headerX[0]); // decrypt and handle payload uint8_t * payload = buf + 32; @@ -183,7 +183,7 @@ namespace transport header.ll[0] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 24)); header.ll[1] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 12)); memset (n, 0, 12); - i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16); + GetServer ().ChaCha20 (h + 16, 16, addr->i, n, h + 16); // send GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ()); UpdateNumSentBytes (payloadSize + 32); @@ -305,7 +305,7 @@ namespace transport header.ll[0] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 24)); header.ll[1] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 12)); memset (n, 0, 12); - i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16); + GetServer ().ChaCha20 (h + 16, 16, addr->i, n, h + 16); // send GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep); UpdateNumSentBytes (payloadSize + 32); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index bcfce662..15147985 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -682,7 +682,7 @@ namespace transport } const uint8_t nonce[12] = {0}; uint64_t headerX[2]; - i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); + m_Server.ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); LogPrint (eLogWarning, "SSU2: Unexpected PeerTest message SourceConnID=", connID, " DestConnID=", headerX[0]); break; } @@ -748,7 +748,7 @@ namespace transport payloadSize += 16; header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24)); header.ll[1] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 12)); - i2p::crypto::ChaCha20 (headerX, 48, m_Address->i, nonce, headerX); + m_Server.ChaCha20 (headerX, 48, m_Address->i, nonce, headerX); m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted payload from Session Request) for SessionCreated m_SentHandshakePacket->payloadSize = payloadSize; // send @@ -775,7 +775,7 @@ namespace transport } const uint8_t nonce[12] = {0}; uint8_t headerX[48]; - i2p::crypto::ChaCha20 (buf + 16, 48, i2p::context.GetSSU2IntroKey (), nonce, headerX); + m_Server.ChaCha20 (buf + 16, 48, i2p::context.GetSSU2IntroKey (), nonce, headerX); memcpy (&m_DestConnID, headerX, 8); uint64_t token; memcpy (&token, headerX + 8, 8); @@ -874,7 +874,7 @@ namespace transport m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted Noise payload from Session Created) header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 24)); header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12)); - i2p::crypto::ChaCha20 (headerX, 48, kh2, nonce, headerX); + m_Server.ChaCha20 (headerX, 48, kh2, nonce, headerX); m_State = eSSU2SessionStateSessionCreatedSent; m_SentHandshakePacket->payloadSize = payloadSize; // send @@ -902,7 +902,7 @@ namespace transport m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval; const uint8_t nonce[12] = {0}; uint8_t headerX[48]; - i2p::crypto::ChaCha20 (buf + 16, 48, kh2, nonce, headerX); + m_Server.ChaCha20 (buf + 16, 48, kh2, nonce, headerX); // KDF for SessionCreated m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header) m_NoiseState->MixHash (headerX + 16, 32); // h = SHA256(h || bepk); @@ -1264,7 +1264,7 @@ namespace transport header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24)); header.ll[1] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 12)); memset (nonce, 0, 12); - i2p::crypto::ChaCha20 (h + 16, 16, m_Address->i, nonce, h + 16); + m_Server.ChaCha20 (h + 16, 16, m_Address->i, nonce, h + 16); // send if (m_Server.AddPendingOutgoingSession (shared_from_this ())) m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint); @@ -1286,7 +1286,7 @@ namespace transport uint8_t nonce[12] = {0}; uint8_t h[32]; memcpy (h, header.buf, 16); - i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16); + m_Server.ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16); memcpy (&m_DestConnID, h + 16, 8); // decrypt CreateNonce (be32toh (header.h.packetNum), nonce); @@ -1338,7 +1338,7 @@ namespace transport header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 24)); header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 12)); memset (nonce, 0, 12); - i2p::crypto::ChaCha20 (h + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16); + m_Server.ChaCha20 (h + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16); // send m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint); } @@ -1362,7 +1362,7 @@ namespace transport } uint8_t nonce[12] = {0}; uint64_t headerX[2]; // sourceConnID, token - i2p::crypto::ChaCha20 (buf + 16, 16, m_Address->i, nonce, (uint8_t *)headerX); + m_Server.ChaCha20 (buf + 16, 16, m_Address->i, nonce, (uint8_t *)headerX); uint64_t token = headerX[1]; if (token) m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT); @@ -1411,7 +1411,7 @@ namespace transport } uint8_t nonce[12] = {0}; uint64_t headerX[2]; // sourceConnID, token - i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); + m_Server.ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); m_DestConnID = headerX[0]; // decrypt and handle payload uint8_t * payload = buf + 32; From 4c5a1e064d18ac571cba36acb73cd8e1e302a7d3 Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Thu, 16 Jan 2025 17:54:38 +0200 Subject: [PATCH 325/527] Fix uninitialized variables --- libi2pd/Destination.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 32182c37..be079ee3 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -195,7 +195,7 @@ namespace client m_IsPublic = itr->second != "true"; } - int inLen, outLen, inQuant, outQuant, numTags, minLatency, maxLatency; + int inLen = 0, outLen = 0, inQuant = 0, outQuant = 0, numTags = 0, minLatency = 0, maxLatency = 0; std::map intOpts = { {I2CP_PARAM_INBOUND_TUNNEL_LENGTH, inLen}, {I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, outLen}, From b6319d78bf9cf483cef8e2bf79b02d75a81907e5 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Jan 2025 19:06:33 -0500 Subject: [PATCH 326/527] don't delete buffer of connected routers --- libi2pd/NetDb.cpp | 9 ++++++--- libi2pd/RouterInfo.h | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 09182948..48c0a690 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.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 * @@ -696,9 +696,12 @@ namespace data r->SetUnreachable (true); } } - // make router reachable back if connected now - if (r->IsUnreachable () && i2p::transport::transports.IsConnected (ident)) + // make router reachable back and don't delete buffer if connected now + if ((r->IsUnreachable () || r->IsBufferScheduledToDelete ()) && i2p::transport::transports.IsConnected (ident)) + { r->SetUnreachable (false); + r->CancelBufferToDelete (); + } if (r->IsUnreachable ()) { diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 8d11f661..3a4f4fc8 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.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 * @@ -294,6 +294,7 @@ namespace data std::shared_ptr GetSharedBuffer () const { return m_Buffer; }; std::shared_ptr CopyBuffer () const; void ScheduleBufferToDelete () { m_IsBufferScheduledToDelete = true; }; + void CancelBufferToDelete () { m_IsBufferScheduledToDelete = false; }; bool IsBufferScheduledToDelete () const { return m_IsBufferScheduledToDelete; }; bool IsUpdated () const { return m_IsUpdated; }; From c600b834e363cbb5ec2d5fe0d4b3c45e58603710 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 18 Jan 2025 18:26:16 -0500 Subject: [PATCH 327/527] postpone reading from file and updating router profile --- libi2pd/NetDb.cpp | 18 +++++++++++-- libi2pd/NetDb.hpp | 4 +-- libi2pd/Profiling.cpp | 60 +++++++++++++++++++++++++++++++++++------ libi2pd/Profiling.h | 7 ++++- libi2pd/SSU2Session.cpp | 11 +++++++- 5 files changed, 86 insertions(+), 14 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 48c0a690..eb029f59 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -119,8 +119,9 @@ namespace data i2p::util::SetThreadName("NetDB"); uint64_t lastManage = 0; - uint64_t lastProfilesCleanup = i2p::util::GetMonotonicMilliseconds (), lastObsoleteProfilesCleanup = lastProfilesCleanup; - int16_t profilesCleanupVariance = 0, obsoleteProfilesCleanVariance = 0; + uint64_t lastProfilesCleanup = i2p::util::GetMonotonicMilliseconds (), + lastObsoleteProfilesCleanup = lastProfilesCleanup, lastApplingProfileUpdates = lastProfilesCleanup; + int16_t profilesCleanupVariance = 0, obsoleteProfilesCleanVariance = 0, applingProfileUpdatesVariance = 0; std::list > msgs; while (m_IsRunning) @@ -199,6 +200,19 @@ namespace data lastObsoleteProfilesCleanup = mts; obsoleteProfilesCleanVariance = rand () % i2p::data::PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE; } + if (mts >= lastApplingProfileUpdates + i2p::data::PEER_PROFILE_APPLY_POSTPONED_TIMEOUT + applingProfileUpdatesVariance) + { + bool isAppling = m_ApplingProfileUpdates.valid (); + if (isAppling && m_ApplingProfileUpdates.wait_for(std::chrono::seconds(0)) == std::future_status::ready) // still active? + { + m_ApplingProfileUpdates.get (); + isAppling = false; + } + if (!isAppling) + m_ApplingProfileUpdates = i2p::data::FlushPostponedRouterProfileUpdates (); + lastApplingProfileUpdates = mts; + applingProfileUpdatesVariance = rand () % i2p::data::PEER_PROFILE_APPLY_POSTPONED_TIMEOUT_VARIANCE; + } } catch (std::exception& ex) { diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 9d8b875a..700941b8 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -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 * @@ -185,7 +185,7 @@ namespace data std::shared_ptr m_Requests; bool m_PersistProfiles; - std::future m_SavingProfiles, m_DeletingProfiles, m_PersistingRouters; + std::future m_SavingProfiles, m_DeletingProfiles, m_ApplingProfileUpdates, m_PersistingRouters; std::vector > m_ExploratorySelection; uint64_t m_LastExploratorySelectionUpdateTime; // in monotonic seconds diff --git a/libi2pd/Profiling.cpp b/libi2pd/Profiling.cpp index 59d60c6d..a48f2112 100644 --- a/libi2pd/Profiling.cpp +++ b/libi2pd/Profiling.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 * @@ -27,7 +27,9 @@ namespace data static i2p::fs::HashedStorage g_ProfilesStorage("peerProfiles", "p", "profile-", "txt"); static std::unordered_map > g_Profiles; static std::mutex g_ProfilesMutex; - + static std::list)> > > g_PostponedUpdates; + static std::mutex g_PostponedUpdatesMutex; + RouterProfile::RouterProfile (): m_IsUpdated (false), m_LastDeclineTime (0), m_LastUnreachableTime (0), m_LastUpdateTime (i2p::util::GetSecondsSinceEpoch ()), @@ -259,14 +261,14 @@ namespace data } auto profile = netdb.NewRouterProfile (); profile->Load (identHash); // if possible - std::unique_lock l(g_ProfilesMutex); + std::lock_guard l(g_ProfilesMutex); g_Profiles.emplace (identHash, profile); return profile; } bool IsRouterBanned (const IdentHash& identHash) { - std::unique_lock l(g_ProfilesMutex); + std::lock_guard l(g_ProfilesMutex); auto it = g_Profiles.find (identHash); if (it != g_Profiles.end ()) return it->second->IsUnreachable (); @@ -278,7 +280,7 @@ namespace data g_ProfilesStorage.SetPlace(i2p::fs::GetDataDir()); g_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64); } - + static void SaveProfilesToDisk (std::list > >&& profiles) { for (auto& it: profiles) @@ -290,7 +292,7 @@ namespace data auto ts = i2p::util::GetSecondsSinceEpoch (); std::list > > tmp; { - std::unique_lock l(g_ProfilesMutex); + std::lock_guard l(g_ProfilesMutex); for (auto it = g_Profiles.begin (); it != g_Profiles.end ();) { if (ts - it->second->GetLastUpdateTime () > PEER_PROFILE_PERSIST_INTERVAL) @@ -312,7 +314,7 @@ namespace data { std::unordered_map > tmp; { - std::unique_lock l(g_ProfilesMutex); + std::lock_guard l(g_ProfilesMutex); std::swap (tmp, g_Profiles); } auto ts = i2p::util::GetSecondsSinceEpoch (); @@ -347,7 +349,7 @@ namespace data { { auto ts = i2p::util::GetSecondsSinceEpoch (); - std::unique_lock l(g_ProfilesMutex); + std::lock_guard l(g_ProfilesMutex); for (auto it = g_Profiles.begin (); it != g_Profiles.end ();) { if (ts - it->second->GetLastUpdateTime () >= PEER_PROFILE_EXPIRATION_TIMEOUT) @@ -359,5 +361,47 @@ namespace data return std::async (std::launch::async, DeleteFilesFromDisk); } + + bool UpdateRouterProfile (const IdentHash& identHash, std::function)> update) + { + if (!update) return true; + std::shared_ptr profile; + { + std::lock_guard l(g_ProfilesMutex); + auto it = g_Profiles.find (identHash); + if (it != g_Profiles.end ()) + profile = it->second; + } + if (profile) + { + update (profile); + return true; + } + // postpone + std::lock_guard l(g_PostponedUpdatesMutex); + g_PostponedUpdates.emplace_back (identHash, update); + return false; + } + + static void ApplyPostponedUpdates (std::list)> > >&& updates) + { + for (const auto& [ident, update] : updates) + { + auto profile = GetRouterProfile (ident); + update (profile); + } + } + + std::future FlushPostponedRouterProfileUpdates () + { + if (g_PostponedUpdates.empty ()) return std::future(); + + std::list)> > > updates; + { + std::lock_guard l(g_PostponedUpdatesMutex); + g_PostponedUpdates.swap (updates); + } + return std::async (std::launch::async, ApplyPostponedUpdates, std::move (updates)); + } } } diff --git a/libi2pd/Profiling.h b/libi2pd/Profiling.h index 5d85cec3..998f9d19 100644 --- a/libi2pd/Profiling.h +++ b/libi2pd/Profiling.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 * @@ -11,6 +11,7 @@ #include #include +#include #include #include "Identity.h" @@ -44,6 +45,8 @@ namespace data const int PEER_PROFILE_UNREACHABLE_INTERVAL = 480; // in seconds (8 minutes) const int PEER_PROFILE_USEFUL_THRESHOLD = 3; const int PEER_PROFILE_ALWAYS_DECLINING_NUM = 5; // num declines in row to consider always declined + const int PEER_PROFILE_APPLY_POSTPONED_TIMEOUT = 2100; // in milliseconds + const int PEER_PROFILE_APPLY_POSTPONED_TIMEOUT_VARIANCE = 500; // in milliseconds class RouterProfile { @@ -108,6 +111,8 @@ namespace data std::future DeleteObsoleteProfiles (); void SaveProfiles (); std::future PersistProfiles (); + bool UpdateRouterProfile (const IdentHash& identHash, std::function)> update); // return true if updated immediately, and false if postponed + std::future FlushPostponedRouterProfileUpdates (); } } diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 15147985..fd877a9b 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1206,7 +1206,16 @@ namespace transport return false; } if (!m_Address->published) - ri->GetProfile ()->SetLastEndpoint (m_RemoteEndpoint); + { + if (ri->HasProfile ()) + ri->GetProfile ()->SetLastEndpoint (m_RemoteEndpoint); + else + i2p::data::UpdateRouterProfile (ri->GetIdentHash (), + [ep = m_RemoteEndpoint](std::shared_ptr profile) + { + if (profile) profile->SetLastEndpoint (ep); + }); + } SetRemoteIdentity (ri->GetRouterIdentity ()); AdjustMaxPayloadSize (); m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now From 4edde333add248c6db279043c7f744f56d64bd56 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 19 Jan 2025 11:47:32 -0500 Subject: [PATCH 328/527] don't drop router buffer if connected or being updated --- libi2pd/NetDb.cpp | 36 +++++++++++++++++------------------- libi2pd/NetDb.hpp | 2 +- libi2pd/RouterInfo.cpp | 4 ++-- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index eb029f59..0fdbac9d 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -120,8 +120,8 @@ namespace data uint64_t lastManage = 0; uint64_t lastProfilesCleanup = i2p::util::GetMonotonicMilliseconds (), - lastObsoleteProfilesCleanup = lastProfilesCleanup, lastApplingProfileUpdates = lastProfilesCleanup; - int16_t profilesCleanupVariance = 0, obsoleteProfilesCleanVariance = 0, applingProfileUpdatesVariance = 0; + lastObsoleteProfilesCleanup = lastProfilesCleanup, lastApplyingProfileUpdates = lastProfilesCleanup; + int16_t profilesCleanupVariance = 0, obsoleteProfilesCleanVariance = 0, applyingProfileUpdatesVariance = 0; std::list > msgs; while (m_IsRunning) @@ -200,18 +200,18 @@ namespace data lastObsoleteProfilesCleanup = mts; obsoleteProfilesCleanVariance = rand () % i2p::data::PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE; } - if (mts >= lastApplingProfileUpdates + i2p::data::PEER_PROFILE_APPLY_POSTPONED_TIMEOUT + applingProfileUpdatesVariance) + if (mts >= lastApplyingProfileUpdates + i2p::data::PEER_PROFILE_APPLY_POSTPONED_TIMEOUT + applyingProfileUpdatesVariance) { - bool isAppling = m_ApplingProfileUpdates.valid (); - if (isAppling && m_ApplingProfileUpdates.wait_for(std::chrono::seconds(0)) == std::future_status::ready) // still active? + bool isApplying = m_ApplyingProfileUpdates.valid (); + if (isApplying && m_ApplyingProfileUpdates.wait_for(std::chrono::seconds(0)) == std::future_status::ready) // still active? { - m_ApplingProfileUpdates.get (); - isAppling = false; + m_ApplyingProfileUpdates.get (); + isApplying = false; } - if (!isAppling) - m_ApplingProfileUpdates = i2p::data::FlushPostponedRouterProfileUpdates (); - lastApplingProfileUpdates = mts; - applingProfileUpdatesVariance = rand () % i2p::data::PEER_PROFILE_APPLY_POSTPONED_TIMEOUT_VARIANCE; + if (!isApplying) + m_ApplyingProfileUpdates = i2p::data::FlushPostponedRouterProfileUpdates (); + lastApplyingProfileUpdates = mts; + applyingProfileUpdatesVariance = rand () % i2p::data::PEER_PROFILE_APPLY_POSTPONED_TIMEOUT_VARIANCE; } } catch (std::exception& ex) @@ -674,10 +674,11 @@ namespace data { std::lock_guard l(m_RouterInfosMutex); // possible collision between DeleteBuffer and Update buffer = r->CopyBuffer (); - r->ScheduleBufferToDelete (); } + if (!i2p::transport::transports.IsConnected (ident)) + r->ScheduleBufferToDelete (); if (buffer) - saveToDisk.push_back(std::make_pair(ident.ToBase64 (), buffer)); + saveToDisk.emplace_back(ident.ToBase64 (), buffer); } r->SetUpdated (false); updatedCount++; @@ -710,18 +711,15 @@ namespace data r->SetUnreachable (true); } } - // make router reachable back and don't delete buffer if connected now - if ((r->IsUnreachable () || r->IsBufferScheduledToDelete ()) && i2p::transport::transports.IsConnected (ident)) - { + // make router reachable back if connected now + if (r->IsUnreachable () && i2p::transport::transports.IsConnected (ident)) r->SetUnreachable (false); - r->CancelBufferToDelete (); - } if (r->IsUnreachable ()) { if (r->IsFloodfill ()) deletedFloodfillsCount++; // delete RI file - removeFromDisk.push_back (ident.ToBase64()); + removeFromDisk.emplace_back (ident.ToBase64()); deletedCount++; if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false; } diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 700941b8..68a221b6 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -185,7 +185,7 @@ namespace data std::shared_ptr m_Requests; bool m_PersistProfiles; - std::future m_SavingProfiles, m_DeletingProfiles, m_ApplingProfileUpdates, m_PersistingRouters; + std::future m_SavingProfiles, m_DeletingProfiles, m_ApplyingProfileUpdates, m_PersistingRouters; std::vector > m_ExploratorySelection; uint64_t m_LastExploratorySelectionUpdateTime; // in monotonic seconds diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 3c074031..63961bca 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.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 * @@ -1136,12 +1136,12 @@ namespace data void RouterInfo::UpdateBuffer (const uint8_t * buf, size_t len) { + m_IsBufferScheduledToDelete = false; if (!m_Buffer) m_Buffer = NewBuffer (); if (len > m_Buffer->size ()) len = m_Buffer->size (); memcpy (m_Buffer->data (), buf, len); m_Buffer->SetBufferLen (len); - m_IsBufferScheduledToDelete = false; } std::shared_ptr RouterInfo::CopyBuffer () const From 5e301937f233f33dca2f59a6e83ce40702bf0de4 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 19 Jan 2025 15:22:46 -0500 Subject: [PATCH 329/527] use pointer to whole struct instead publicKey for buffer --- libi2pd/Identity.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 89bf71d4..b58d18b6 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -27,18 +27,15 @@ namespace data size_t Identity::FromBuffer (const uint8_t * buf, size_t len) { - if ( len < DEFAULT_IDENTITY_SIZE ) { - // buffer too small, don't overflow - return 0; - } - memcpy (publicKey, buf, DEFAULT_IDENTITY_SIZE); + if (len < DEFAULT_IDENTITY_SIZE) return 0; // buffer too small, don't overflow + memcpy (this, buf, DEFAULT_IDENTITY_SIZE); return DEFAULT_IDENTITY_SIZE; } IdentHash Identity::Hash () const { IdentHash hash; - SHA256(publicKey, DEFAULT_IDENTITY_SIZE, hash); + SHA256((const uint8_t *)this, DEFAULT_IDENTITY_SIZE, hash); return hash; } From 57986bd3480ed5f443bed2de3d5a6e6ea6ca5ce4 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 19 Jan 2025 19:16:34 -0500 Subject: [PATCH 330/527] postpone updating router profile after tunnel build. Check profiles only in memory --- libi2pd/Tunnel.cpp | 21 ++++++++++++--------- libi2pd/TunnelPool.cpp | 6 +++--- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index e7443b6c..0d3f67db 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.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 * @@ -179,9 +179,12 @@ namespace tunnel { uint8_t ret = hop->GetRetCode (msg + 1); LogPrint (eLogDebug, "Tunnel: Build response ret code=", (int)ret); - auto profile = i2p::data::netdb.FindRouterProfile (hop->ident->GetIdentHash ()); - if (profile) - profile->TunnelBuildResponse (ret); + if (hop->ident) + i2p::data::UpdateRouterProfile (hop->ident->GetIdentHash (), + [ret](std::shared_ptr profile) + { + if (profile) profile->TunnelBuildResponse (ret); + }); if (ret) // if any of participants declined the tunnel is not established established = false; @@ -743,11 +746,11 @@ namespace tunnel while (hop) { if (hop->ident) - { - auto profile = i2p::data::netdb.FindRouterProfile (hop->ident->GetIdentHash ()); - if (profile) - profile->TunnelNonReplied (); - } + i2p::data::UpdateRouterProfile (hop->ident->GetIdentHash (), + [](std::shared_ptr profile) + { + if (profile) profile->TunnelNonReplied (); + }); hop = hop->next; } } diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 3d50738c..f20c491c 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.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 * @@ -560,7 +560,7 @@ namespace tunnel i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint, false); if (hop) { - if (!hop->GetProfile ()->IsBad ()) + if (!hop->HasProfile () || !hop->GetProfile ()->IsBad ()) break; } else if (tryClient) @@ -588,7 +588,7 @@ namespace tunnel (inbound && i2p::transport::transports.GetNumPeers () > 25)) { auto r = i2p::transport::transports.GetRandomPeer (m_IsHighBandwidth && !i2p::context.IsLimitedConnectivity ()); - if (r && r->IsECIES () && !r->GetProfile ()->IsBad () && + if (r && r->IsECIES () && (!r->HasProfile () || !r->GetProfile ()->IsBad ()) && (numHops > 1 || (r->IsV4 () && (!inbound || r->IsPublished (true))))) // first inbound must be published ipv4 { prevHop = r; From 39e07ac265e13d5d22f23b9cd8b8f8cfaec7b41a Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 20 Jan 2025 11:58:33 -0500 Subject: [PATCH 331/527] don't load router profile in NTCP2 or SSU2 thread when check for duplicates --- libi2pd/NTCP2.cpp | 25 +++++++++++++++++-------- libi2pd/SSU2Session.cpp | 21 +++++++++++++++------ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f0545ae7..870fcc19 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.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 * @@ -819,15 +819,20 @@ namespace transport Terminate (); return; } - std::shared_ptr profile; // not null if older + + bool isOlder = false; if (ri.GetTimestamp () + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri1->GetTimestamp ()) { // received RouterInfo is older than one in netdb - profile = i2p::data::GetRouterProfile (ri1->GetIdentHash ()); // retrieve profile - if (profile && profile->IsDuplicated ()) + isOlder = true; + if (ri1->HasProfile ()) { - SendTerminationAndTerminate (eNTCP2Banned); - return; + auto profile = i2p::data::GetRouterProfile (ri1->GetIdentHash ()); // retrieve profile + if (profile && profile->IsDuplicated ()) + { + SendTerminationAndTerminate (eNTCP2Banned); + return; + } } } @@ -844,8 +849,12 @@ namespace transport memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data () + 1, addr->host.to_v6 ().to_bytes ().data () + 1, 7) : // from the same yggdrasil subnet memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), addr->host.to_v6 ().to_bytes ().data (), 8)))) // temporary address { - if (profile) // older router? - profile->Duplicated (); // mark router as duplicated in profile + if (isOlder) // older router? + i2p::data::UpdateRouterProfile (ri1->GetIdentHash (), + [](std::shared_ptr profile) + { + if (profile) profile->Duplicated (); // mark router as duplicated in profile + }); else LogPrint (eLogInfo, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ()); SendTerminationAndTerminate (eNTCP2Banned); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index fd877a9b..bb2641f4 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1178,13 +1178,18 @@ namespace transport LogPrint (eLogError, "SSU2: Couldn't update RouterInfo from SessionConfirmed in netdb"); return false; } - std::shared_ptr profile; // not null if older + + bool isOlder = false; if (ri->GetTimestamp () + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri1->GetTimestamp ()) { // received RouterInfo is older than one in netdb - profile = i2p::data::GetRouterProfile (ri->GetIdentHash ()); // retrieve profile - if (profile && profile->IsDuplicated ()) - return false; + isOlder = true; + if (ri->HasProfile ()) + { + auto profile = i2p::data::GetRouterProfile (ri->GetIdentHash ()); // retrieve profile + if (profile && profile->IsDuplicated ()) + return false; + } } ri = ri1; @@ -1198,8 +1203,12 @@ namespace transport (!m_RemoteEndpoint.address ().is_v6 () || memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), m_Address->host.to_v6 ().to_bytes ().data (), 8))) // temporary address { - if (profile) // older router? - profile->Duplicated (); // mark router as duplicated in profile + if (isOlder) // older router? + i2p::data::UpdateRouterProfile (ri->GetIdentHash (), + [](std::shared_ptr profile) + { + if (profile) profile->Duplicated (); // mark router as duplicated in profile + }); else LogPrint (eLogInfo, "SSU2: Host mismatch between published address ", m_Address->host, " and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ())); From 29a5effabbc90d05dc2ba5483da3396ace5fd739 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 20 Jan 2025 13:27:40 -0500 Subject: [PATCH 332/527] use std::mt19937 for random numbers in netdb --- libi2pd/NetDb.cpp | 13 ++++++------- libi2pd/NetDb.hpp | 2 ++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 0fdbac9d..2e29961e 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -40,7 +39,7 @@ namespace data NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true), - m_LastExploratorySelectionUpdateTime (0) + m_LastExploratorySelectionUpdateTime (0), m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL) { } @@ -182,7 +181,7 @@ namespace data LogPrint (eLogWarning, "NetDb: Can't persist profiles. Profiles are being saved to disk"); } lastProfilesCleanup = mts; - profilesCleanupVariance = rand () % i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE; + profilesCleanupVariance = m_Rng () % i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE; } if (mts >= lastObsoleteProfilesCleanup + (uint64_t)(i2p::data::PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_TIMEOUT + obsoleteProfilesCleanVariance)*1000) @@ -198,7 +197,7 @@ namespace data else LogPrint (eLogWarning, "NetDb: Can't delete profiles. Profiles are being deleted from disk"); lastObsoleteProfilesCleanup = mts; - obsoleteProfilesCleanVariance = rand () % i2p::data::PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE; + obsoleteProfilesCleanVariance = m_Rng () % i2p::data::PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE; } if (mts >= lastApplyingProfileUpdates + i2p::data::PEER_PROFILE_APPLY_POSTPONED_TIMEOUT + applyingProfileUpdatesVariance) { @@ -211,7 +210,7 @@ namespace data if (!isApplying) m_ApplyingProfileUpdates = i2p::data::FlushPostponedRouterProfileUpdates (); lastApplyingProfileUpdates = mts; - applyingProfileUpdatesVariance = rand () % i2p::data::PEER_PROFILE_APPLY_POSTPONED_TIMEOUT_VARIANCE; + applyingProfileUpdatesVariance = m_Rng () % i2p::data::PEER_PROFILE_APPLY_POSTPONED_TIMEOUT_VARIANCE; } } catch (std::exception& ex) @@ -571,7 +570,7 @@ namespace data while(n > 0) { std::lock_guard lock(m_RouterInfosMutex); - uint32_t idx = rand () % m_RouterInfos.size (); + uint32_t idx = m_Rng () % m_RouterInfos.size (); uint32_t i = 0; for (const auto & it : m_RouterInfos) { if(i >= idx) // are we at the random start point? @@ -1346,7 +1345,7 @@ namespace data if (eligible.size () > NETDB_MAX_EXPLORATORY_SELECTION_SIZE) { std::sample (eligible.begin(), eligible.end(), std::back_inserter(m_ExploratorySelection), - NETDB_MAX_EXPLORATORY_SELECTION_SIZE, std::mt19937(ts)); + NETDB_MAX_EXPLORATORY_SELECTION_SIZE, m_Rng); } else std::swap (m_ExploratorySelection, eligible); diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 68a221b6..75169862 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "Base.h" #include "Gzip.h" @@ -189,6 +190,7 @@ namespace data std::vector > m_ExploratorySelection; uint64_t m_LastExploratorySelectionUpdateTime; // in monotonic seconds + std::mt19937 m_Rng; i2p::util::MemoryPoolMt m_RouterInfoBuffersPool; i2p::util::MemoryPoolMt m_RouterInfoAddressesPool; From cba7e5350dd7d865b560fde48dc9afea504c3a09 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 20 Jan 2025 18:17:41 -0500 Subject: [PATCH 333/527] drop router's buffer after a while without updates --- libi2pd/NetDb.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 2e29961e..e5d3fc09 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -683,6 +683,10 @@ namespace data updatedCount++; continue; } + else if (r->GetBuffer () && ts > r->GetTimestamp () + NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) + // since update was long time ago we assume that router is not connected anymore + r->ScheduleBufferToDelete (); + if (r->GetProfile ()->IsUnreachable ()) r->SetUnreachable (true); // make router reachable back if too few routers or floodfills From 2857a163e92fb07a6f20b450373df849ce15216d Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2025 15:03:25 -0500 Subject: [PATCH 334/527] check last endpoint only if profile is in memory. postpone profile update when connected --- libi2pd/SSU2.cpp | 2 +- libi2pd/Transports.cpp | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index e6d62801..8625eaa4 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -890,7 +890,7 @@ namespace transport } auto session = std::make_shared (*this, router, address); - if (!isValidEndpoint && router->GetProfile ()->HasLastEndpoint (address->IsV4 ())) + if (!isValidEndpoint && router->HasProfile () && router->GetProfile ()->HasLastEndpoint (address->IsV4 ())) { // router doesn't publish endpoint, but we connected before and hole punch might be alive auto ep = router->GetProfile ()->GetLastEndpoint (); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index f3f9e5e4..edf864ca 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.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 * @@ -701,7 +701,8 @@ namespace transport // try recently connected SSU2 if any auto supportedTransports = context.GetRouterInfo ().GetCompatibleTransports (false) & peer->router->GetCompatibleTransports (false); - if (supportedTransports & (i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6)) + if ((supportedTransports & (i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6)) && + peer->router->HasProfile ()) { auto ep = peer->router->GetProfile ()->GetLastEndpoint (); if (!ep.address ().is_unspecified () && ep.port ()) @@ -886,7 +887,11 @@ namespace transport auto transport = peer->priority[peer->numAttempts-1]; if (transport == i2p::data::RouterInfo::eNTCP2V4 || transport == i2p::data::RouterInfo::eNTCP2V6 || transport == i2p::data::RouterInfo::eNTCP2V6Mesh) - peer->router->GetProfile ()->Connected (); // outgoing NTCP2 connection if always real + i2p::data::UpdateRouterProfile (ident, + [](std::shared_ptr profile) + { + if (profile) profile->Connected (); // outgoing NTCP2 connection if always real + }); i2p::data::netdb.SetUnreachable (ident, false); // clear unreachable } peer->numAttempts = 0; @@ -921,7 +926,11 @@ namespace transport session->SendI2NPMessages (msgs); // send DatabaseStore } auto r = i2p::data::netdb.FindRouter (ident); // router should be in netdb after SessionConfirmed - if (r) r->GetProfile ()->Connected (); + i2p::data::UpdateRouterProfile (ident, + [](std::shared_ptr profile) + { + if (profile) profile->Connected (); + }); auto ts = i2p::util::GetSecondsSinceEpoch (); auto peer = std::make_shared(r, ts); peer->sessions.push_back (session); From b3d09513b85a36cd2b170f22ab4fb1f27cfa9c9d Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2025 19:38:07 -0500 Subject: [PATCH 335/527] fixed race condition --- libi2pd/TransitTunnel.cpp | 14 +++++++++++--- libi2pd/TransitTunnel.h | 5 +++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index ba505ae3..2b9b2a85 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.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 * @@ -101,13 +101,13 @@ namespace tunnel TunnelMessageBlock block; block.deliveryType = eDeliveryTypeLocal; block.data = msg; - std::unique_lock l(m_SendMutex); + std::lock_guard l(m_SendMutex); m_Gateway.PutTunnelDataMsg (block); } void TransitTunnelGateway::FlushTunnelDataMsgs () { - std::unique_lock l(m_SendMutex); + std::lock_guard l(m_SendMutex); m_Gateway.SendBuffer (); } @@ -130,14 +130,22 @@ namespace tunnel EncryptTunnelMsg (tunnelMsg, newMsg); LogPrint (eLogDebug, "TransitTunnel: handle msg for endpoint ", GetTunnelID ()); + std::lock_guard l(m_HandleMutex); m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg); } void TransitTunnelEndpoint::FlushTunnelDataMsgs () { + std::lock_guard l(m_HandleMutex); m_Endpoint.FlushI2NPMsgs (); } + void TransitTunnelEndpoint::Cleanup () + { + std::lock_guard l(m_HandleMutex); + m_Endpoint.Cleanup (); + } + std::string TransitTunnelEndpoint::GetNextPeerName () const { auto hash = m_Endpoint.GetCurrentHash (); diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index c0f9c276..efdd2bc6 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.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 * @@ -100,7 +100,7 @@ namespace tunnel TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey), m_Endpoint (false) {}; // transit endpoint is always outbound - void Cleanup () override { m_Endpoint.Cleanup (); } + void Cleanup () override; void HandleTunnelDataMsg (std::shared_ptr&& tunnelMsg) override; void FlushTunnelDataMsgs () override; @@ -109,6 +109,7 @@ namespace tunnel private: + std::mutex m_HandleMutex; TunnelEndpoint m_Endpoint; }; From ca0818af7ed19dae7c39fe46fcca5358f50b254a Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2025 12:00:37 -0500 Subject: [PATCH 336/527] drop buffer upon peer disconnect --- libi2pd/Transports.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index edf864ca..b9971a77 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -964,8 +964,13 @@ namespace transport } else { - std::lock_guard l(m_PeersMutex); - m_Peers.erase (it); + { + std::lock_guard l(m_PeersMutex); + m_Peers.erase (it); + } + // delete buffer of just disconnected router + auto r = i2p::data::netdb.FindRouter (ident); + if (r && !r->IsUpdated ()) r->ScheduleBufferToDelete (); } } } From 1e7254dfaa157979655cda19b295cccb4517d35d Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2025 13:25:11 -0500 Subject: [PATCH 337/527] don't delete router's buffer if an update received or connecting --- libi2pd/NetDb.cpp | 1 + libi2pd/Transports.cpp | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index e5d3fc09..ac786a29 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -294,6 +294,7 @@ namespace data } else { + r->CancelBufferToDelete (); // since an update received if (CheckLogLevel (eLogDebug)) LogPrint (eLogDebug, "NetDb: RouterInfo is older: ", ident.ToBase64()); updated = false; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index b9971a77..22646d94 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -560,7 +560,14 @@ namespace transport bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr peer) { if (!peer->router) // reconnect - peer->SetRouter (netdb.FindRouter (ident)); // try to get new one from netdb + { + auto r = netdb.FindRouter (ident); // try to get new one from netdb + if (r) + { + peer->SetRouter (r); + r->CancelBufferToDelete (); + } + } if (peer->router) // we have RI already { if (peer->priority.empty ()) From 4fa5cec0dcfda4511bc77b6a607020b5c917492a Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 23 Jan 2025 14:12:52 -0500 Subject: [PATCH 338/527] fixed termination deadlock if SAM session is active --- libi2pd_client/SAM.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index c124be9b..13992efa 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.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 * @@ -1350,12 +1350,14 @@ namespace client LogPrint (eLogError, "SAM: Runtime exception: ", ex.what ()); } + decltype(m_Sessions) sessions; { std::unique_lock l(m_SessionsMutex); - for (auto& it: m_Sessions) - it.second->Close (); - m_Sessions.clear (); - } + m_Sessions.swap (sessions); + } + for (auto& it: sessions) + it.second->Close (); + StopIOService (); } From 1bb5ad22af8463e2e82b1173a2b9c77deecc4a0b Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 23 Jan 2025 19:20:20 -0500 Subject: [PATCH 339/527] use std::mt19937 for random. Peer test interval variance --- libi2pd/Transports.cpp | 23 ++++++++++++----------- libi2pd/Transports.h | 11 +++++++---- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 22646d94..8f632759 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -160,7 +160,8 @@ namespace transport m_TotalSentBytes (0), m_TotalReceivedBytes (0), m_TotalTransitTransmittedBytes (0), m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth (0), m_InBandwidth15s (0), m_OutBandwidth15s (0), m_TransitBandwidth15s (0), - m_InBandwidth5m (0), m_OutBandwidth5m (0), m_TransitBandwidth5m (0) + m_InBandwidth5m (0), m_OutBandwidth5m (0), m_TransitBandwidth5m (0), + m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL) { } @@ -338,7 +339,7 @@ namespace transport if (m_IsNAT) { - m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL)); + m_PeerTestTimer->expires_from_now (boost::posix_time::seconds(PEER_TEST_INTERVAL + m_Rng() % PEER_TEST_INTERVAL_VARIANCE)); m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1)); } } @@ -654,7 +655,7 @@ namespace transport return true; } - void Transports::SetPriority (std::shared_ptr peer) const + void Transports::SetPriority (std::shared_ptr peer) { static const std::vector ntcp2Priority = @@ -680,7 +681,7 @@ namespace transport peer->numAttempts = 0; peer->priority.clear (); bool isReal = peer->router->GetProfile ()->IsReal (); - bool ssu2 = isReal ? (rand () & 1) : false; // try NTCP2 if router is not confirmed real + bool ssu2 = isReal ? (m_Rng () & 1) : false; // try NTCP2 if router is not confirmed real const auto& priority = ssu2 ? ssu2Priority : ntcp2Priority; if (directTransports) { @@ -799,7 +800,7 @@ namespace transport } else { - testDelay += PEER_TEST_DELAY_INTERVAL + rand() % PEER_TEST_DELAY_INTERVAL_VARIANCE; + testDelay += PEER_TEST_DELAY_INTERVAL + m_Rng() % PEER_TEST_DELAY_INTERVAL_VARIANCE; if (m_Service) { auto delayTimer = std::make_shared(*m_Service); @@ -837,7 +838,7 @@ namespace transport } else { - testDelay += PEER_TEST_DELAY_INTERVAL + rand() % PEER_TEST_DELAY_INTERVAL_VARIANCE; + testDelay += PEER_TEST_DELAY_INTERVAL + m_Rng() % PEER_TEST_DELAY_INTERVAL_VARIANCE; if (m_Service) { auto delayTimer = std::make_shared(*m_Service); @@ -1027,7 +1028,7 @@ namespace transport if (session) session->SendLocalRouterInfo (true); it->second->nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL + - rand () % PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE; + m_Rng() % PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE; } ++it; } @@ -1051,7 +1052,7 @@ namespace transport if (ecode != boost::asio::error::operation_aborted) { PeerTest (); - m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL)); + m_PeerTestTimer->expires_from_now (boost::posix_time::seconds(PEER_TEST_INTERVAL + m_Rng() % PEER_TEST_INTERVAL_VARIANCE)); m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1)); } } @@ -1198,7 +1199,7 @@ namespace transport } /** XXX: if routes are not restricted this dies */ - std::shared_ptr Transports::GetRestrictedPeer() const + std::shared_ptr Transports::GetRestrictedPeer() { { std::lock_guard l(m_FamilyMutex); @@ -1207,7 +1208,7 @@ namespace transport if(sz > 1) { auto it = m_TrustedFamilies.begin (); - std::advance(it, rand() % sz); + std::advance(it, m_Rng() % sz); fam = *it; } else if (sz == 1) @@ -1225,7 +1226,7 @@ namespace transport if(sz == 1) return i2p::data::netdb.FindRouter(m_TrustedRouters[0]); auto it = m_TrustedRouters.begin(); - std::advance(it, rand() % sz); + std::advance(it, m_Rng() % sz); return i2p::data::netdb.FindRouter(*it); } } diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index c1acbb2e..6f856697 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.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 * @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "TransportSession.h" #include "SSU2.h" @@ -106,7 +107,8 @@ namespace transport }; const uint64_t SESSION_CREATION_TIMEOUT = 15; // in seconds - const int PEER_TEST_INTERVAL = 71; // in minutes + const int PEER_TEST_INTERVAL = 68*60; // in seconds + const int PEER_TEST_INTERVAL_VARIANCE = 3*60; // in seconds const int PEER_TEST_DELAY_INTERVAL = 20; // in milliseconds const int PEER_TEST_DELAY_INTERVAL_VARIANCE = 30; // in milliseconds const int MAX_NUM_DELAYED_MESSAGES = 150; @@ -168,7 +170,7 @@ namespace transport std::shared_ptr GetRandomPeer (bool isHighBandwidth) const; /** get a trusted first hop for restricted routes */ - std::shared_ptr GetRestrictedPeer() const; + std::shared_ptr GetRestrictedPeer(); /** do we want to use restricted routes? */ bool RoutesRestricted() const; /** restrict routes to use only these router families for first hops */ @@ -191,7 +193,7 @@ namespace transport void HandleRequestComplete (std::shared_ptr r, i2p::data::IdentHash ident); std::shared_ptr PostMessages (const i2p::data::IdentHash& ident, std::list >& msgs); bool ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr peer); - void SetPriority (std::shared_ptr peer) const; + void SetPriority (std::shared_ptr peer); void HandlePeerCleanupTimer (const boost::system::error_code& ecode); void HandlePeerTestTimer (const boost::system::error_code& ecode); void HandleUpdateBandwidthTimer (const boost::system::error_code& ecode); @@ -239,6 +241,7 @@ namespace transport mutable std::mutex m_TrustedRoutersMutex; i2p::I2NPMessagesHandler m_LoopbackHandler; + std::mt19937 m_Rng; public: From b9c9988ff4b8467e99467af9447c3ff7fc2f6b0e Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 24 Jan 2025 13:56:33 -0500 Subject: [PATCH 340/527] smaller request timeout if sent directly --- libi2pd/NetDbRequests.cpp | 13 +++++++++---- libi2pd/NetDbRequests.h | 6 ++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index 14e5ff19..f8c5037c 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.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 * @@ -20,8 +20,10 @@ namespace i2p namespace data { RequestedDestination::RequestedDestination (const IdentHash& destination, bool isExploratory, bool direct): - m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), m_IsActive (true), - m_CreationTime (i2p::util::GetMillisecondsSinceEpoch ()), m_LastRequestTime (0), m_NumAttempts (0) + m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), + m_IsActive (true), m_IsSentDirectly (false), + m_CreationTime (i2p::util::GetMillisecondsSinceEpoch ()), + m_LastRequestTime (0), m_NumAttempts (0) { if (i2p::context.IsFloodfill ()) m_ExcludedPeers.insert (i2p::context.GetIdentHash ()); // exclude self if floodfill @@ -46,6 +48,7 @@ namespace data m_ExcludedPeers.insert (router->GetIdentHash ()); m_LastRequestTime = i2p::util::GetMillisecondsSinceEpoch (); m_NumAttempts++; + m_IsSentDirectly = false; return msg; } @@ -56,6 +59,7 @@ namespace data m_ExcludedPeers.insert (floodfill); m_NumAttempts++; m_LastRequestTime = i2p::util::GetMillisecondsSinceEpoch (); + m_IsSentDirectly = true; return msg; } @@ -222,7 +226,8 @@ namespace data bool done = false; if (ts < dest->GetCreationTime () + MAX_REQUEST_TIME) { - if (ts > dest->GetLastRequestTime () + MIN_REQUEST_TIME) // try next floodfill if no response after min interval + if (ts > dest->GetLastRequestTime () + (dest->IsSentDirectly () ? MIN_DIRECT_REQUEST_TIME : MIN_REQUEST_TIME)) + // try next floodfill if no response after min interval done = !SendNextRequest (dest); } else // request is expired diff --git a/libi2pd/NetDbRequests.h b/libi2pd/NetDbRequests.h index 86fdb2dd..53af2c6a 100644 --- a/libi2pd/NetDbRequests.h +++ b/libi2pd/NetDbRequests.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 * @@ -28,6 +28,7 @@ namespace data const uint64_t MANAGE_REQUESTS_INTERVAL_VARIANCE = 300; // in milliseconds const uint64_t MIN_REQUEST_TIME = 1200; // in milliseconds const uint64_t MAX_REQUEST_TIME = MAX_NUM_REQUEST_ATTEMPTS * (MIN_REQUEST_TIME + MANAGE_REQUESTS_INTERVAL + MANAGE_REQUESTS_INTERVAL_VARIANCE); + const uint64_t MIN_DIRECT_REQUEST_TIME = 600; // in milliseconds const uint64_t EXPLORATORY_REQUEST_INTERVAL = 55; // in seconds const uint64_t EXPLORATORY_REQUEST_INTERVAL_VARIANCE = 170; // in seconds const uint64_t DISCOVERED_REQUEST_INTERVAL = 360; // in milliseconds @@ -52,6 +53,7 @@ namespace data bool IsExploratory () const { return m_IsExploratory; }; bool IsDirect () const { return m_IsDirect; }; bool IsActive () const { return m_IsActive; }; + bool IsSentDirectly () const { return m_IsSentDirectly; }; bool IsExcluded (const IdentHash& ident) const; uint64_t GetCreationTime () const { return m_CreationTime; }; uint64_t GetLastRequestTime () const { return m_LastRequestTime; }; @@ -70,7 +72,7 @@ namespace data private: IdentHash m_Destination; - bool m_IsExploratory, m_IsDirect, m_IsActive; + bool m_IsExploratory, m_IsDirect, m_IsActive, m_IsSentDirectly; std::unordered_set m_ExcludedPeers; uint64_t m_CreationTime, m_LastRequestTime; // in milliseconds std::list m_RequestComplete; From 72ff0b9fbba4a26148ce5cc93173174460777d21 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 25 Jan 2025 09:02:18 -0500 Subject: [PATCH 341/527] shorter ack request interval --- libi2pd_client/I2CP.cpp | 13 +++++++------ libi2pd_client/I2CP.h | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 6bbf58dd..88465143 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -764,6 +764,7 @@ namespace client void I2CPSession::AddRoutingSession (const i2p::data::IdentHash& signingKey, std::shared_ptr remoteSession) { if (!remoteSession) return; + remoteSession->SetAckRequestInterval (I2CP_SESSION_ACK_REQUEST_INTERVAL); std::lock_guard l(m_RoutingSessionsMutex); m_RoutingSessions[signingKey] = remoteSession; } @@ -1110,12 +1111,12 @@ namespace client void I2CPServer::Stop () { m_Acceptor.cancel (); - { - auto sessions = m_Sessions; - for (auto& it: sessions) - it.second->Stop (); - } - m_Sessions.clear (); + + decltype(m_Sessions) sessions; + m_Sessions.swap (sessions); + for (auto& it: sessions) + it.second->Stop (); + StopIOService (); } diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index d974ebba..d5ac648e 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -31,6 +31,7 @@ namespace client const size_t I2CP_MAX_MESSAGE_LENGTH = 65535; const size_t I2CP_MAX_SEND_QUEUE_SIZE = 1024*1024; // in bytes, 1M const int I2CP_LEASESET_CREATION_TIMEOUT = 10; // in seconds + const int I2CP_SESSION_ACK_REQUEST_INTERVAL = 12100; // in milliseconds const size_t I2CP_HEADER_LENGTH_OFFSET = 0; const size_t I2CP_HEADER_TYPE_OFFSET = I2CP_HEADER_LENGTH_OFFSET + 4; From bf85a69a2f216f4486b66010a86af950bc0d2f86 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 26 Jan 2025 17:49:24 -0500 Subject: [PATCH 342/527] min peer test version 0.9.62 --- libi2pd/NetDb.hpp | 1 + libi2pd/RouterInfo.cpp | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 75169862..f2a7019b 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -53,6 +53,7 @@ namespace data const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 58); // 0.9.58 const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 59); // 0.9.59 const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51 + const int NETDB_MIN_PEER_TEST_VERSION = MAKE_VERSION_NUMBER(0, 9, 62); // 0.9.62 const size_t NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES = 16; const size_t NETDB_MAX_EXPLORATORY_SELECTION_SIZE = 500; const int NETDB_EXPLORATORY_SELECTION_UPDATE_INTERVAL = 82; // in seconds. for floodfill diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 63961bca..9cad82ab 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -486,6 +486,15 @@ namespace data } ch++; } + if (m_Version < NETDB_MIN_PEER_TEST_VERSION && (m_SupportedTransports & (eSSU2V4 | eSSU2V6))) + { + auto addresses = GetAddresses (); + if (addresses) + { + if ((*addresses)[eSSU2V4Idx]) (*addresses)[eSSU2V4Idx]->caps &= ~eSSUTesting; + if ((*addresses)[eSSU2V6Idx]) (*addresses)[eSSU2V6Idx]->caps &= ~eSSUTesting; + } + } } // check netId else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID)) From c3fa0ae8ccce0ba0e429372c4f6456c69de7eacd Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 27 Jan 2025 13:24:37 -0500 Subject: [PATCH 343/527] cache full addresses in memory when requested or received --- libi2pd_client/AddressBook.cpp | 63 +++++++++++++++++++++------------- libi2pd_client/AddressBook.h | 4 +-- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index b5c08d3a..30af20d0 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include @@ -49,7 +49,7 @@ namespace client if (m_IsPersist) i2p::config::GetOption("addressbook.hostsfile", m_HostsFile); } - std::shared_ptr GetAddress (const i2p::data::IdentHash& ident) const override; + std::shared_ptr GetAddress (const i2p::data::IdentHash& ident) override; void AddAddress (std::shared_ptr address) override; void RemoveAddress (const i2p::data::IdentHash& ident) override; @@ -72,6 +72,7 @@ namespace client std::string etagsPath, indexPath, localPath; bool m_IsPersist; std::string m_HostsFile; // file to dump hosts.txt, empty if not used + std::unordered_map > m_FullAddressesCache; // ident hash -> full ident buffer }; bool AddressBookFilesystemStorage::Init() @@ -92,8 +93,12 @@ namespace client return false; } - std::shared_ptr AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const + std::shared_ptr AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) { + auto it = m_FullAddressesCache.find (ident); + if (it != m_FullAddressesCache.end ()) + return std::make_shared(it->second.data (), it->second.size ()); + if (!m_IsPersist) { LogPrint(eLogDebug, "Addressbook: Persistence is disabled"); @@ -101,43 +106,55 @@ namespace client } std::string filename = storage.Path(ident.ToBase32()); std::ifstream f(filename, std::ifstream::binary); - if (!f.is_open ()) { + if (!f.is_open ()) + { LogPrint(eLogDebug, "Addressbook: Requested, but not found: ", filename); return nullptr; } f.seekg (0,std::ios::end); size_t len = f.tellg (); - if (len < i2p::data::DEFAULT_IDENTITY_SIZE) { + if (len < i2p::data::DEFAULT_IDENTITY_SIZE) + { LogPrint (eLogError, "Addressbook: File ", filename, " is too short: ", len); return nullptr; } f.seekg(0, std::ios::beg); - uint8_t * buf = new uint8_t[len]; - f.read((char *)buf, len); - auto address = std::make_shared(buf, len); - delete[] buf; - return address; + std::vector buf(len); + f.read((char *)buf.data (), len); + if (!f) + { + LogPrint (eLogError, "Addressbook: Couldn't read ", filename); + return nullptr; + } + m_FullAddressesCache.try_emplace (ident, buf); + return std::make_shared(buf.data (), len); } void AddressBookFilesystemStorage::AddAddress (std::shared_ptr address) { - if (!m_IsPersist) return; - std::string path = storage.Path( address->GetIdentHash().ToBase32() ); - std::ofstream f (path, std::ofstream::binary | std::ofstream::out); - if (!f.is_open ()) { - LogPrint (eLogError, "Addressbook: Can't open file ", path); - return; - } + if (!address) return; size_t len = address->GetFullLen (); - uint8_t * buf = new uint8_t[len]; - address->ToBuffer (buf, len); - f.write ((char *)buf, len); - delete[] buf; + if (!len) return; // invalid address + auto [it, inserted] = m_FullAddressesCache.try_emplace (address->GetIdentHash(), len); + if (inserted) + { + address->ToBuffer (it->second.data (), len); + if (!m_IsPersist) return; + std::string path = storage.Path( address->GetIdentHash().ToBase32() ); + std::ofstream f (path, std::ofstream::binary | std::ofstream::out); + if (!f.is_open ()) + { + LogPrint (eLogError, "Addressbook: Can't open file ", path); + return; + } + f.write ((const char *)it->second.data (), len); + } } void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident) { + m_FullAddressesCache.erase (ident); if (!m_IsPersist) return; storage.Remove( ident.ToBase32() ); } @@ -341,7 +358,7 @@ namespace client StopSubscriptions (); if (m_SubscriptionsUpdateTimer) { - delete m_SubscriptionsUpdateTimer; + m_SubscriptionsUpdateTimer->cancel (); m_SubscriptionsUpdateTimer = nullptr; } bool isDownloading = m_Downloading.valid (); @@ -682,7 +699,7 @@ namespace client auto dest = i2p::client::context.GetSharedLocalDestination (); if (dest) { - m_SubscriptionsUpdateTimer = new boost::asio::deadline_timer (dest->GetService ()); + m_SubscriptionsUpdateTimer = std::make_unique(dest->GetService ()); m_SubscriptionsUpdateTimer->expires_from_now (boost::posix_time::minutes(INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT)); m_SubscriptionsUpdateTimer->async_wait (std::bind (&AddressBook::HandleSubscriptionsUpdateTimer, this, std::placeholders::_1)); diff --git a/libi2pd_client/AddressBook.h b/libi2pd_client/AddressBook.h index 40946a5c..70c567d7 100644 --- a/libi2pd_client/AddressBook.h +++ b/libi2pd_client/AddressBook.h @@ -62,7 +62,7 @@ namespace client typedef std::map, std::less<> > Addresses; virtual ~AddressBookStorage () {}; - virtual std::shared_ptr GetAddress (const i2p::data::IdentHash& ident) const = 0; + virtual std::shared_ptr GetAddress (const i2p::data::IdentHash& ident) = 0; virtual void AddAddress (std::shared_ptr address) = 0; virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0; @@ -133,7 +133,7 @@ namespace client int m_NumRetries; std::vector > m_Subscriptions; std::shared_ptr m_DefaultSubscription; // in case if we don't know any addresses yet - boost::asio::deadline_timer * m_SubscriptionsUpdateTimer; + std::unique_ptr m_SubscriptionsUpdateTimer; bool m_IsEnabled; }; From 588855c6a7b1655ca45c2317912a46233f62fee1 Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Mon, 27 Jan 2025 23:04:23 +0200 Subject: [PATCH 344/527] fix typo --- build/cmake_modules/GetGitRevisionDescription.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/cmake_modules/GetGitRevisionDescription.cmake b/build/cmake_modules/GetGitRevisionDescription.cmake index 4fbd90db..a08895c6 100644 --- a/build/cmake_modules/GetGitRevisionDescription.cmake +++ b/build/cmake_modules/GetGitRevisionDescription.cmake @@ -59,7 +59,7 @@ get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) # function returns an empty string via _git_dir_var. # # Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and -# neither foo nor bar contain a file/directory .git. This wil return +# neither foo nor bar contain a file/directory .git. This will return # C:/bla/.git # function(_git_find_closest_git_dir _start_dir _git_dir_var) From 45bab06f37482b4f41a1b96a3d55656367257c64 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 27 Jan 2025 18:30:22 -0500 Subject: [PATCH 345/527] cleanup cached addresses --- libi2pd_client/AddressBook.cpp | 92 ++++++++++++++++++++++++++++------ libi2pd_client/AddressBook.h | 9 +++- 2 files changed, 85 insertions(+), 16 deletions(-) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index 30af20d0..216916a2 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -17,6 +17,7 @@ #include #include "Base.h" #include "util.h" +#include "Timestamp.h" #include "Identity.h" #include "FS.h" #include "Log.h" @@ -52,6 +53,7 @@ namespace client std::shared_ptr GetAddress (const i2p::data::IdentHash& ident) override; void AddAddress (std::shared_ptr address) override; void RemoveAddress (const i2p::data::IdentHash& ident) override; + void CleanUpCache () override; bool Init () override; int Load (Addresses& addresses) override; @@ -61,7 +63,7 @@ namespace client void SaveEtag (const i2p::data::IdentHash& subsciption, const std::string& etag, const std::string& lastModified) override; bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified) override; void ResetEtags () override; - + private: int LoadFromFile (const std::string& filename, Addresses& addresses); // returns -1 if can't open file, otherwise number of records @@ -72,7 +74,8 @@ namespace client std::string etagsPath, indexPath, localPath; bool m_IsPersist; std::string m_HostsFile; // file to dump hosts.txt, empty if not used - std::unordered_map > m_FullAddressesCache; // ident hash -> full ident buffer + std::unordered_map, uint64_t> > m_FullAddressCache; // ident hash -> (full ident buffer, last access timestamp) + std::mutex m_FullAddressCacheMutex; }; bool AddressBookFilesystemStorage::Init() @@ -95,9 +98,16 @@ namespace client std::shared_ptr AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) { - auto it = m_FullAddressesCache.find (ident); - if (it != m_FullAddressesCache.end ()) - return std::make_shared(it->second.data (), it->second.size ()); + auto ts = i2p::util::GetMonotonicSeconds (); + { + std::lock_guard l(m_FullAddressCacheMutex); + auto it = m_FullAddressCache.find (ident); + if (it != m_FullAddressCache.end ()) + { + it->second.second = ts; + return std::make_shared(it->second.first.data (), it->second.first.size ()); + } + } if (!m_IsPersist) { @@ -127,7 +137,10 @@ namespace client LogPrint (eLogError, "Addressbook: Couldn't read ", filename); return nullptr; } - m_FullAddressesCache.try_emplace (ident, buf); + { + std::lock_guard l(m_FullAddressCacheMutex); + m_FullAddressCache.try_emplace (ident, buf, ts); + } return std::make_shared(buf.data (), len); } @@ -135,26 +148,35 @@ namespace client { if (!address) return; size_t len = address->GetFullLen (); + std::vector buf; if (!len) return; // invalid address - auto [it, inserted] = m_FullAddressesCache.try_emplace (address->GetIdentHash(), len); - if (inserted) - { - address->ToBuffer (it->second.data (), len); - if (!m_IsPersist) return; - std::string path = storage.Path( address->GetIdentHash().ToBase32() ); + { + std::lock_guard l(m_FullAddressCacheMutex); + auto [it, inserted] = m_FullAddressCache.try_emplace (address->GetIdentHash(), len, i2p::util::GetMonotonicSeconds ()); + if (inserted) + address->ToBuffer (it->second.first.data (), len); + if (m_IsPersist) + buf = it->second.first; + } + if (m_IsPersist && !buf.empty ()) + { + std::string path = storage.Path(address->GetIdentHash().ToBase32()); std::ofstream f (path, std::ofstream::binary | std::ofstream::out); if (!f.is_open ()) { LogPrint (eLogError, "Addressbook: Can't open file ", path); return; } - f.write ((const char *)it->second.data (), len); + f.write ((const char *)buf.data (), len); } } void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident) { - m_FullAddressesCache.erase (ident); + { + std::lock_guard l(m_FullAddressCacheMutex); + m_FullAddressCache.erase (ident); + } if (!m_IsPersist) return; storage.Remove( ident.ToBase32() ); } @@ -298,6 +320,19 @@ namespace client } } + void AddressBookFilesystemStorage::CleanUpCache () + { + auto ts = i2p::util::GetMonotonicSeconds (); + std::lock_guard l(m_FullAddressCacheMutex); + for (auto it = m_FullAddressCache.begin (); it != m_FullAddressCache.end ();) + { + if (ts > it->second.second + ADDRESS_CACHE_EXPIRATION_TIMEOUT) + it = m_FullAddressCache.erase (it); + else + it++; + } + } + //--------------------------------------------------------------------- Address::Address (std::string_view b32): @@ -344,6 +379,7 @@ namespace client LoadHosts (); /* try storage, then hosts.txt, then download */ StartSubscriptions (); StartLookups (); + ScheduleCacheUpdate (); } } @@ -361,6 +397,11 @@ namespace client m_SubscriptionsUpdateTimer->cancel (); m_SubscriptionsUpdateTimer = nullptr; } + if (m_AddressCacheUpdateTimer) + { + m_AddressCacheUpdateTimer->cancel (); + m_AddressCacheUpdateTimer = nullptr; + } bool isDownloading = m_Downloading.valid (); if (isDownloading) { @@ -850,6 +891,29 @@ namespace client } } + void AddressBook::ScheduleCacheUpdate () + { + if (!m_AddressCacheUpdateTimer) + { + auto dest = i2p::client::context.GetSharedLocalDestination (); + if(dest) + m_AddressCacheUpdateTimer = std::make_unique(dest->GetService ()); + } + if (m_AddressCacheUpdateTimer) + { + m_AddressCacheUpdateTimer->expires_from_now (boost::posix_time::seconds(ADDRESS_CACHE_UPDATE_INTERVAL )); + m_SubscriptionsUpdateTimer->async_wait ( + [this](const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + if (m_Storage) m_Storage->CleanUpCache (); + ScheduleCacheUpdate (); + } + }); + } + } + AddressBookSubscription::AddressBookSubscription (AddressBook& book, std::string_view link): m_Book (book), m_Link (link) { diff --git a/libi2pd_client/AddressBook.h b/libi2pd_client/AddressBook.h index 70c567d7..8b32aa93 100644 --- a/libi2pd_client/AddressBook.h +++ b/libi2pd_client/AddressBook.h @@ -34,7 +34,9 @@ namespace client const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours) const int CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT = 5; // in minutes const int CONTINIOUS_SUBSCRIPTION_MAX_NUM_RETRIES = 10; // then update timeout - const int SUBSCRIPTION_REQUEST_TIMEOUT = 120; //in second + const int SUBSCRIPTION_REQUEST_TIMEOUT = 120; //in seconds + const int ADDRESS_CACHE_EXPIRATION_TIMEOUT = 710; // in seconds + const int ADDRESS_CACHE_UPDATE_INTERVAL = 76; // in seconds const uint16_t ADDRESS_RESOLVER_DATAGRAM_PORT = 53; const uint16_t ADDRESS_RESPONSE_DATAGRAM_PORT = 54; @@ -65,6 +67,7 @@ namespace client virtual std::shared_ptr GetAddress (const i2p::data::IdentHash& ident) = 0; virtual void AddAddress (std::shared_ptr address) = 0; virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0; + virtual void CleanUpCache () = 0; virtual bool Init () = 0; virtual int Load (Addresses& addresses) = 0; @@ -120,6 +123,8 @@ namespace client void StopLookups (); void HandleLookupResponse (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + void ScheduleCacheUpdate (); + private: std::mutex m_AddressBookMutex; @@ -133,7 +138,7 @@ namespace client int m_NumRetries; std::vector > m_Subscriptions; std::shared_ptr m_DefaultSubscription; // in case if we don't know any addresses yet - std::unique_ptr m_SubscriptionsUpdateTimer; + std::unique_ptr m_SubscriptionsUpdateTimer, m_AddressCacheUpdateTimer; bool m_IsEnabled; }; From 35f7bd51276e17a16f49e062cfb24c22b3f2dfe2 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 28 Jan 2025 14:09:25 -0500 Subject: [PATCH 346/527] don't delete actively use profile. Last persist time --- libi2pd/Profiling.cpp | 22 ++++++++++++++-------- libi2pd/Profiling.h | 8 +++++++- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/libi2pd/Profiling.cpp b/libi2pd/Profiling.cpp index a48f2112..ec9540c0 100644 --- a/libi2pd/Profiling.cpp +++ b/libi2pd/Profiling.cpp @@ -32,10 +32,10 @@ namespace data RouterProfile::RouterProfile (): m_IsUpdated (false), m_LastDeclineTime (0), m_LastUnreachableTime (0), - m_LastUpdateTime (i2p::util::GetSecondsSinceEpoch ()), - m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0), - m_NumTimesTaken (0), m_NumTimesRejected (0), m_HasConnected (false), - m_IsDuplicated (false) + m_LastUpdateTime (i2p::util::GetSecondsSinceEpoch ()), m_LastAccessTime (0), + m_LastPersistTime (0), m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), + m_NumTunnelsNonReplied (0),m_NumTimesTaken (0), m_NumTimesRejected (0), + m_HasConnected (false), m_IsDuplicated (false) { } @@ -80,6 +80,7 @@ namespace data void RouterProfile::Load (const IdentHash& identHash) { + m_IsUpdated = false; std::string ident = identHash.ToBase64 (); std::string path = g_ProfilesStorage.Path(ident); boost::property_tree::ptree pt; @@ -257,7 +258,10 @@ namespace data std::unique_lock l(g_ProfilesMutex); auto it = g_Profiles.find (identHash); if (it != g_Profiles.end ()) + { + it->second->SetLastAccessTime (i2p::util::GetSecondsSinceEpoch ()); return it->second; + } } auto profile = netdb.NewRouterProfile (); profile->Load (identHash); // if possible @@ -295,12 +299,14 @@ namespace data std::lock_guard l(g_ProfilesMutex); for (auto it = g_Profiles.begin (); it != g_Profiles.end ();) { - if (ts - it->second->GetLastUpdateTime () > PEER_PROFILE_PERSIST_INTERVAL) + if (it->second->IsUpdated () && ts > it->second->GetLastPersistTime () + PEER_PROFILE_PERSIST_INTERVAL) { - if (it->second->IsUpdated ()) - tmp.push_back (std::make_pair (it->first, it->second)); + tmp.push_back (std::make_pair (it->first, it->second)); + it->second->SetLastPersistTime (ts); + it->second->SetUpdated (false); + } + if (!it->second->IsUpdated () && ts > std::max (it->second->GetLastUpdateTime (), it->second->GetLastAccessTime ()) + PEER_PROFILE_PERSIST_INTERVAL) it = g_Profiles.erase (it); - } else it++; } diff --git a/libi2pd/Profiling.h b/libi2pd/Profiling.h index 998f9d19..014d3dea 100644 --- a/libi2pd/Profiling.h +++ b/libi2pd/Profiling.h @@ -70,6 +70,11 @@ namespace data uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; }; bool IsUpdated () const { return m_IsUpdated; }; + void SetUpdated (bool updated) { m_IsUpdated = updated; } + uint64_t GetLastAccessTime () const { return m_LastAccessTime; }; + void SetLastAccessTime (uint64_t ts) { m_LastAccessTime = ts; }; + uint64_t GetLastPersistTime () const { return m_LastPersistTime; }; + void SetLastPersistTime (uint64_t ts) { m_LastPersistTime = ts; }; bool IsUseful() const; bool IsDuplicated () const { return m_IsDuplicated; }; @@ -91,7 +96,8 @@ namespace data private: bool m_IsUpdated; - uint64_t m_LastDeclineTime, m_LastUnreachableTime, m_LastUpdateTime; // in seconds + uint64_t m_LastDeclineTime, m_LastUnreachableTime, m_LastUpdateTime, + m_LastAccessTime, m_LastPersistTime; // in seconds // participation uint32_t m_NumTunnelsAgreed; uint32_t m_NumTunnelsDeclined; From 5d7a062f1b5f2183dee21918a5e3c8878047ea75 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 28 Jan 2025 14:47:22 -0500 Subject: [PATCH 347/527] std::mt19937 for random. Congestion update timer variance --- libi2pd/RouterContext.cpp | 10 ++++++---- libi2pd/RouterContext.h | 5 ++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 7dfb97e4..030dc162 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -33,13 +33,14 @@ namespace i2p m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown), m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_Testing (false), m_TestingV6 (false), m_NetID (I2PD_NET_ID), - m_PublishReplyToken (0), m_IsHiddenMode (false) + m_PublishReplyToken (0), m_IsHiddenMode (false), + m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL) { } void RouterContext::Init () { - srand (i2p::util::GetMillisecondsSinceEpoch () % 1000); + srand (m_Rng () % 1000); m_StartupTime = i2p::util::GetMonotonicSeconds (); if (!Load ()) @@ -1359,7 +1360,7 @@ namespace i2p { m_PublishTimer->cancel (); m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_PUBLISH_INTERVAL + - rand () % ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE)); + m_Rng () % ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE)); m_PublishTimer->async_wait (std::bind (&RouterContext::HandlePublishTimer, this, std::placeholders::_1)); } @@ -1471,7 +1472,8 @@ namespace i2p if (m_CongestionUpdateTimer) { m_CongestionUpdateTimer->cancel (); - m_CongestionUpdateTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CONGESTION_UPDATE_INTERVAL)); + m_CongestionUpdateTimer->expires_from_now (boost::posix_time::seconds( + ROUTER_INFO_CONGESTION_UPDATE_INTERVAL + m_Rng () % ROUTER_INFO_CONGESTION_UPDATE_INTERVAL_VARIANCE)); m_CongestionUpdateTimer->async_wait (std::bind (&RouterContext::HandleCongestionUpdateTimer, this, std::placeholders::_1)); } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 6fb06fc1..ae62ebf3 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "Identity.h" @@ -36,7 +37,8 @@ namespace garlic const int ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE = 105;// in seconds const int ROUTER_INFO_CONFIRMATION_TIMEOUT = 1600; // in milliseconds const int ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15; - const int ROUTER_INFO_CONGESTION_UPDATE_INTERVAL = 12*60; // in seconds + const int ROUTER_INFO_CONGESTION_UPDATE_INTERVAL = 11*60; // in seconds + const int ROUTER_INFO_CONGESTION_UPDATE_INTERVAL_VARIANCE = 130; // in seconds const int ROUTER_INFO_CLEANUP_INTERVAL = 102; // in seconds enum RouterStatus @@ -263,6 +265,7 @@ namespace garlic uint32_t m_PublishReplyToken; bool m_IsHiddenMode; // not publish mutable std::mutex m_RouterInfoMutex; + std::mt19937 m_Rng; }; extern RouterContext context; From daeb177579b6759530a107f693c2559290a546c9 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 28 Jan 2025 20:49:36 -0500 Subject: [PATCH 348/527] save updated local RouterInfo in separate thread --- libi2pd/RouterContext.cpp | 19 +++++++++++++++++-- libi2pd/RouterContext.h | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 030dc162..0c22ba45 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -77,7 +77,9 @@ namespace i2p m_CongestionUpdateTimer->cancel (); m_Service->Stop (); CleanUp (); // GarlicDestination - } + } + if (m_SavingRouterInfo.valid ()) + m_SavingRouterInfo.wait (); } std::shared_ptr RouterContext::CopyRouterInfoBuffer () const @@ -254,12 +256,25 @@ namespace i2p void RouterContext::UpdateRouterInfo () { + std::shared_ptr buffer; { std::lock_guard l(m_RouterInfoMutex); m_RouterInfo.CreateBuffer (m_Keys); + buffer = m_RouterInfo.CopyBuffer (); } - m_RouterInfo.SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO)); m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch (); + // defer saving buffer to disk + if (m_SavingRouterInfo.valid ()) + { + // wait until previous update complete + m_SavingRouterInfo.wait (); + m_SavingRouterInfo.get (); + } + m_SavingRouterInfo = std::async (std::launch::async, + [buffer = std::move(buffer)]() + { + i2p::data::RouterInfo::SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO), buffer); + }); } void RouterContext::NewNTCP2Keys () diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index ae62ebf3..29af6dac 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include "Identity.h" @@ -266,6 +267,7 @@ namespace garlic bool m_IsHiddenMode; // not publish mutable std::mutex m_RouterInfoMutex; std::mt19937 m_Rng; + std::future m_SavingRouterInfo; }; extern RouterContext context; From 1bff42042dfe14eb1c87e837cec29fd430fdd0f1 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 28 Jan 2025 21:22:36 -0500 Subject: [PATCH 349/527] check if saving if complete --- libi2pd/RouterContext.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 0c22ba45..2cc2becd 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -78,7 +78,7 @@ namespace i2p m_Service->Stop (); CleanUp (); // GarlicDestination } - if (m_SavingRouterInfo.valid ()) + if (m_SavingRouterInfo.valid () && m_SavingRouterInfo.wait_for(std::chrono::seconds(0)) != std::future_status::ready) m_SavingRouterInfo.wait (); } @@ -266,8 +266,9 @@ namespace i2p // defer saving buffer to disk if (m_SavingRouterInfo.valid ()) { - // wait until previous update complete - m_SavingRouterInfo.wait (); + if (m_SavingRouterInfo.wait_for(std::chrono::seconds(0)) != std::future_status::ready) + // wait until previous update complete + m_SavingRouterInfo.wait (); m_SavingRouterInfo.get (); } m_SavingRouterInfo = std::async (std::launch::async, From 774c606b09d6a9f7c22bd315881b00dfbe5190a0 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 28 Jan 2025 21:30:48 -0500 Subject: [PATCH 350/527] don't wait for completion explicitly --- libi2pd/RouterContext.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 2cc2becd..aab5de8f 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -78,8 +78,8 @@ namespace i2p m_Service->Stop (); CleanUp (); // GarlicDestination } - if (m_SavingRouterInfo.valid () && m_SavingRouterInfo.wait_for(std::chrono::seconds(0)) != std::future_status::ready) - m_SavingRouterInfo.wait (); + if (m_SavingRouterInfo.valid ()) + m_SavingRouterInfo.get (); } std::shared_ptr RouterContext::CopyRouterInfoBuffer () const @@ -265,12 +265,7 @@ namespace i2p m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch (); // defer saving buffer to disk if (m_SavingRouterInfo.valid ()) - { - if (m_SavingRouterInfo.wait_for(std::chrono::seconds(0)) != std::future_status::ready) - // wait until previous update complete - m_SavingRouterInfo.wait (); m_SavingRouterInfo.get (); - } m_SavingRouterInfo = std::async (std::launch::async, [buffer = std::move(buffer)]() { From 93ec5ac5c46be4e7e665a5e813dff855dfc484e5 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 28 Jan 2025 21:45:26 -0500 Subject: [PATCH 351/527] rollback --- libi2pd/RouterContext.cpp | 13 +------------ libi2pd/RouterContext.h | 2 -- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index aab5de8f..53244b6c 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -78,8 +78,6 @@ namespace i2p m_Service->Stop (); CleanUp (); // GarlicDestination } - if (m_SavingRouterInfo.valid ()) - m_SavingRouterInfo.get (); } std::shared_ptr RouterContext::CopyRouterInfoBuffer () const @@ -256,21 +254,12 @@ namespace i2p void RouterContext::UpdateRouterInfo () { - std::shared_ptr buffer; { std::lock_guard l(m_RouterInfoMutex); m_RouterInfo.CreateBuffer (m_Keys); - buffer = m_RouterInfo.CopyBuffer (); } + m_RouterInfo.SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO)); m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch (); - // defer saving buffer to disk - if (m_SavingRouterInfo.valid ()) - m_SavingRouterInfo.get (); - m_SavingRouterInfo = std::async (std::launch::async, - [buffer = std::move(buffer)]() - { - i2p::data::RouterInfo::SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO), buffer); - }); } void RouterContext::NewNTCP2Keys () diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 29af6dac..ae62ebf3 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include "Identity.h" @@ -267,7 +266,6 @@ namespace garlic bool m_IsHiddenMode; // not publish mutable std::mutex m_RouterInfoMutex; std::mt19937 m_Rng; - std::future m_SavingRouterInfo; }; extern RouterContext context; From e4ba07a5404c093c1755779a7034d40262a30ca6 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2025 13:22:15 -0500 Subject: [PATCH 352/527] persist local RouterInfo in separate thread using seperate buffer --- libi2pd/RouterContext.cpp | 35 ++++++++++++++++++++++++++++++++++- libi2pd/RouterContext.h | 4 ++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 53244b6c..ebc3546f 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -78,6 +78,12 @@ namespace i2p m_Service->Stop (); CleanUp (); // GarlicDestination } + if (m_SavingRouterInfo.valid ()) + { + m_SaveBuffer = nullptr; + m_SavingRouterInfo.get (); + } + } std::shared_ptr RouterContext::CopyRouterInfoBuffer () const @@ -254,11 +260,38 @@ namespace i2p void RouterContext::UpdateRouterInfo () { + std::shared_ptr buffer; { std::lock_guard l(m_RouterInfoMutex); m_RouterInfo.CreateBuffer (m_Keys); + buffer = m_RouterInfo.CopyBuffer (); } - m_RouterInfo.SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO)); + { + // update save buffer to latest + std::lock_guard l(m_SaveBufferMutex); + m_SaveBuffer = buffer; + } + bool isSaving = m_SavingRouterInfo.valid (); + if (isSaving && m_SavingRouterInfo.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + { + m_SavingRouterInfo.get (); + isSaving = false; + } + if (!isSaving) // try to save only if not being saved + m_SavingRouterInfo = std::async (std::launch::async, [this]() + { + std::shared_ptr buffer; + while (m_SaveBuffer) + { + { + std::lock_guard l(m_SaveBufferMutex); + buffer = m_SaveBuffer; + m_SaveBuffer = nullptr; + } + if (buffer) + i2p::data::RouterInfo::SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO), buffer); + } + }); m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch (); } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index ae62ebf3..1c724617 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include "Identity.h" @@ -266,6 +267,9 @@ namespace garlic bool m_IsHiddenMode; // not publish mutable std::mutex m_RouterInfoMutex; std::mt19937 m_Rng; + std::future m_SavingRouterInfo; + std::shared_ptr m_SaveBuffer; + std::mutex m_SaveBufferMutex; // TODO: make m_SaveBuffer atomic }; extern RouterContext context; From adc230acde54c6d9168a3051c56ee2b139f8b7ed Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2025 16:02:31 -0500 Subject: [PATCH 353/527] use m_IsSaving flag for saving RouterInfo --- libi2pd/RouterContext.cpp | 22 +++++++--------------- libi2pd/RouterContext.h | 3 +-- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index ebc3546f..8d2dd922 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -34,7 +34,7 @@ namespace i2p m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_Testing (false), m_TestingV6 (false), m_NetID (I2PD_NET_ID), m_PublishReplyToken (0), m_IsHiddenMode (false), - m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL) + m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL), m_IsSaving (false) { } @@ -78,12 +78,6 @@ namespace i2p m_Service->Stop (); CleanUp (); // GarlicDestination } - if (m_SavingRouterInfo.valid ()) - { - m_SaveBuffer = nullptr; - m_SavingRouterInfo.get (); - } - } std::shared_ptr RouterContext::CopyRouterInfoBuffer () const @@ -271,14 +265,10 @@ namespace i2p std::lock_guard l(m_SaveBufferMutex); m_SaveBuffer = buffer; } - bool isSaving = m_SavingRouterInfo.valid (); - if (isSaving && m_SavingRouterInfo.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - { - m_SavingRouterInfo.get (); - isSaving = false; - } - if (!isSaving) // try to save only if not being saved - m_SavingRouterInfo = std::async (std::launch::async, [this]() + bool isSaving = false; + if (m_IsSaving.compare_exchange_strong (isSaving, true)) // try to save only if not being saved + { + auto savingRouterInfo = std::async (std::launch::async, [this]() { std::shared_ptr buffer; while (m_SaveBuffer) @@ -291,7 +281,9 @@ namespace i2p if (buffer) i2p::data::RouterInfo::SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO), buffer); } + m_IsSaving = false; }); + } m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch (); } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 1c724617..c3336336 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include "Identity.h" @@ -267,9 +266,9 @@ namespace garlic bool m_IsHiddenMode; // not publish mutable std::mutex m_RouterInfoMutex; std::mt19937 m_Rng; - std::future m_SavingRouterInfo; std::shared_ptr m_SaveBuffer; std::mutex m_SaveBufferMutex; // TODO: make m_SaveBuffer atomic + std::atomic m_IsSaving; }; extern RouterContext context; From 60d3e4d963830b56484de837d750c17c6fa01ae0 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2025 19:15:12 -0500 Subject: [PATCH 354/527] set ack requested flag after second resend attempt --- libi2pd/SSU2Session.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index bb2641f4..41c5bb11 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -623,7 +623,8 @@ namespace transport } else { - uint32_t packetNum = SendData (it->second->payload, it->second->payloadSize); + uint32_t packetNum = SendData (it->second->payload, it->second->payloadSize, + it->second->numResends > 1 ? SSU2_FLAG_IMMEDIATE_ACK_REQUESTED : 0); it->second->numResends++; it->second->sendTime = ts; resentPackets.emplace (packetNum, it->second); From ff0b6a6a6a650fb16c52522b1045d104c32cb909 Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Thu, 30 Jan 2025 13:36:53 +0200 Subject: [PATCH 355/527] fix uninitialized variable block.tunnelID --- libi2pd/Tunnel.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 0d3f67db..ec1569f2 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -300,22 +300,28 @@ namespace tunnel void OutboundTunnel::SendTunnelDataMsgTo (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr msg) { TunnelMessageBlock block; + block.tunnelID = 0; // Initialize tunnelID to a default value + if (gwHash) { block.hash = gwHash; if (gwTunnel) { block.deliveryType = eDeliveryTypeTunnel; - block.tunnelID = gwTunnel; + block.tunnelID = gwTunnel; // Set tunnelID only if gwTunnel is non-zero } else + { block.deliveryType = eDeliveryTypeRouter; + } } else + { block.deliveryType = eDeliveryTypeLocal; + } + block.data = msg; - - SendTunnelDataMsgs ({block}); + SendTunnelDataMsgs({block}); } void OutboundTunnel::SendTunnelDataMsgs (const std::vector& msgs) From da7d3c55b095be388edb6e9cda1f6750fbeabfc5 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 30 Jan 2025 08:21:01 -0500 Subject: [PATCH 356/527] replaced banana.incognet.io reseed by coconut.incognet.io --- libi2pd/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index cd5b0200..3da74da0 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -238,7 +238,7 @@ namespace config { "https://reseed.onion.im/," "https://i2pseed.creativecowpat.net:8443/," "https://reseed.i2pgit.org/," - "https://banana.incognet.io/," + "https://coconut.incognet.io/," "https://reseed-pl.i2pd.xyz/," "https://www2.mk16.de/," "https://i2p.ghativega.in/," From eadeea76e75325fec0b5bbbba488f62ee10aa5dc Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 30 Jan 2025 15:35:04 -0500 Subject: [PATCH 357/527] check congestion and random reject short tunnel build requests --- libi2pd/TransitTunnel.cpp | 23 ++++++++++++++++++++--- libi2pd/TransitTunnel.h | 1 + libi2pd/Tunnel.h | 4 +--- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index 2b9b2a85..e8ac7f5b 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -188,7 +188,7 @@ namespace tunnel } TransitTunnels::TransitTunnels (): - m_IsRunning (false) + m_IsRunning (false), m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL) { } @@ -328,8 +328,25 @@ namespace tunnel // check if we accept this tunnel std::shared_ptr transitTunnel; uint8_t retCode = 0; - if (!i2p::context.AcceptsTunnels () || i2p::context.GetCongestionLevel (false) >= CONGESTION_LEVEL_FULL) + if (i2p::context.AcceptsTunnels ()) + { + auto congestionLevel = i2p::context.GetCongestionLevel (false); + if (congestionLevel < CONGESTION_LEVEL_FULL) + { + if (congestionLevel >= CONGESTION_LEVEL_MEDIUM) + { + // random reject depending on congestion level + int level = m_Rng () % (CONGESTION_LEVEL_FULL - CONGESTION_LEVEL_MEDIUM) + CONGESTION_LEVEL_MEDIUM; + if (congestionLevel > level) + retCode = 30; + } + } + else + retCode = 30; + } + else retCode = 30; + if (!retCode) { // create new transit tunnel @@ -452,7 +469,7 @@ namespace tunnel if (congestionLevel < CONGESTION_LEVEL_FULL) { // random reject depending on congestion level - int level = i2p::tunnel::tunnels.GetRng ()() % (CONGESTION_LEVEL_FULL - CONGESTION_LEVEL_MEDIUM) + CONGESTION_LEVEL_MEDIUM; + int level = m_Rng () % (CONGESTION_LEVEL_FULL - CONGESTION_LEVEL_MEDIUM) + CONGESTION_LEVEL_MEDIUM; if (congestionLevel > level) accept = false; } diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index efdd2bc6..46d09b1a 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.h @@ -152,6 +152,7 @@ namespace tunnel std::unique_ptr m_Thread; std::list > m_TransitTunnels; i2p::util::Queue > m_TunnelBuildMsgQueue; + std::mt19937 m_Rng; public: diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 5b72cc97..0cb87ace 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.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 * @@ -245,8 +245,6 @@ namespace tunnel void SetMaxNumTransitTunnels (uint32_t maxNumTransitTunnels); uint32_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; }; int GetCongestionLevel() const { return m_MaxNumTransitTunnels ? CONGESTION_LEVEL_FULL * m_TransitTunnels.GetNumTransitTunnels () / m_MaxNumTransitTunnels : CONGESTION_LEVEL_FULL; } - - std::mt19937& GetRng () { return m_Rng; }; private: From 972b66f9a503de1e5a0c6bb19a5810227abbda13 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 31 Jan 2025 11:20:39 -0500 Subject: [PATCH 358/527] decline transit tunnel to duplicated router --- libi2pd/Profiling.cpp | 9 +++++++ libi2pd/Profiling.h | 1 + libi2pd/TransitTunnel.cpp | 55 +++++++++++++++++++++++++-------------- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/libi2pd/Profiling.cpp b/libi2pd/Profiling.cpp index ec9540c0..bb40ae41 100644 --- a/libi2pd/Profiling.cpp +++ b/libi2pd/Profiling.cpp @@ -278,6 +278,15 @@ namespace data return it->second->IsUnreachable (); return false; } + + bool IsRouterDuplicated (const IdentHash& identHash) + { + std::lock_guard l(g_ProfilesMutex); + auto it = g_Profiles.find (identHash); + if (it != g_Profiles.end ()) + return it->second->IsDuplicated (); + return false; + } void InitProfilesStorage () { diff --git a/libi2pd/Profiling.h b/libi2pd/Profiling.h index 014d3dea..32d760a6 100644 --- a/libi2pd/Profiling.h +++ b/libi2pd/Profiling.h @@ -113,6 +113,7 @@ namespace data std::shared_ptr GetRouterProfile (const IdentHash& identHash); bool IsRouterBanned (const IdentHash& identHash); // check only existing profiles + bool IsRouterDuplicated (const IdentHash& identHash); // check only existing profiles void InitProfilesStorage (); std::future DeleteObsoleteProfiles (); void SaveProfiles (); diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index e8ac7f5b..57fd8513 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -349,15 +349,23 @@ namespace tunnel if (!retCode) { - // create new transit tunnel - transitTunnel = i2p::tunnel::CreateTransitTunnel ( - bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), - clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, - bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), - layerKey, ivKey, - clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, - clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); - if (!AddTransitTunnel (transitTunnel)) + i2p::data::IdentHash nextIdent(clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET); + bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG; + if (isEndpoint || !i2p::data::IsRouterDuplicated (nextIdent)) + { + // create new transit tunnel + transitTunnel = CreateTransitTunnel ( + bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), + nextIdent, + bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + layerKey, ivKey, + clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, + isEndpoint); + if (!AddTransitTunnel (transitTunnel)) + retCode = 30; + } + else + // decline tunnel going to duplicated router retCode = 30; } @@ -477,23 +485,32 @@ namespace tunnel accept = false; } } - // replace record to reply + if (accept) { - auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( - bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), - clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, - bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), - clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, - clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET, - clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, - clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); - if (!AddTransitTunnel (transitTunnel)) + i2p::data::IdentHash nextIdent(clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET); + bool isEndpoint = clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG; + if (isEndpoint || !i2p::data::IsRouterDuplicated (nextIdent)) + { + auto transitTunnel = CreateTransitTunnel ( + bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), + nextIdent, + bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, + clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET, + clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, + isEndpoint); + if (!AddTransitTunnel (transitTunnel)) + retCode = 30; + } + else + // decline tunnel going to duplicated router retCode = 30; } else retCode = 30; // always reject with bandwidth reason (30) + // replace record to reply memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode; // encrypt reply From 57aa8b3de865cdd6290ef8ab375d0037c1263e10 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 31 Jan 2025 12:55:09 -0500 Subject: [PATCH 359/527] 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 216916a2..98528868 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -902,7 +902,7 @@ namespace client if (m_AddressCacheUpdateTimer) { m_AddressCacheUpdateTimer->expires_from_now (boost::posix_time::seconds(ADDRESS_CACHE_UPDATE_INTERVAL )); - m_SubscriptionsUpdateTimer->async_wait ( + m_AddressCacheUpdateTimer->async_wait ( [this](const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) From e8f5efd15639bd1f8f2df08cc23aac6ec4d656e4 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Feb 2025 09:42:44 -0500 Subject: [PATCH 360/527] peers cleanup time variance --- libi2pd/Transports.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 8f632759..db2af5da 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -1042,7 +1042,7 @@ namespace transport // if still testing or unknown, repeat peer test if (ipv4Testing || ipv6Testing) PeerTest (ipv4Testing, ipv6Testing); - m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(3 * SESSION_CREATION_TIMEOUT)); + m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(2 * SESSION_CREATION_TIMEOUT + m_Rng() % SESSION_CREATION_TIMEOUT)); m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); } } From b8d74dab477e712b4c64c376f08147414d7b3d69 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 2 Feb 2025 16:49:37 -0500 Subject: [PATCH 361/527] recreate tunnels in random order --- libi2pd/Tunnel.cpp | 59 ++++++++++++++++++++++++++++++++++++---------- libi2pd/Tunnel.h | 7 ++++-- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 0d3f67db..f8be27ec 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -281,6 +281,21 @@ namespace tunnel m_Endpoint.HandleDecryptedTunnelDataMsg (msg); } + bool InboundTunnel::Recreate () + { + if (!IsRecreated ()) + { + auto pool = GetTunnelPool (); + if (pool) + { + SetRecreated (true); + pool->RecreateInboundTunnel (std::static_pointer_cast(shared_from_this ())); + return true; + } + } + return false; + } + ZeroHopsInboundTunnel::ZeroHopsInboundTunnel (): InboundTunnel (std::make_shared ()), m_NumReceivedBytes (0) @@ -331,6 +346,21 @@ namespace tunnel LogPrint (eLogError, "Tunnel: Incoming message for outbound tunnel ", GetTunnelID ()); } + bool OutboundTunnel::Recreate () + { + if (!IsRecreated ()) + { + auto pool = GetTunnelPool (); + if (pool) + { + SetRecreated (true); + pool->RecreateOutboundTunnel (std::static_pointer_cast(shared_from_this ())); + return true; + } + } + return false; + } + ZeroHopsOutboundTunnel::ZeroHopsOutboundTunnel (): OutboundTunnel (std::make_shared ()), m_NumSentBytes (0) @@ -437,7 +467,7 @@ namespace tunnel std::shared_ptr Tunnels::GetNextOutboundTunnel () { if (m_OutboundTunnels.empty ()) return nullptr; - uint32_t ind = rand () % m_OutboundTunnels.size (), i = 0; + uint32_t ind = m_Rng () % m_OutboundTunnels.size (), i = 0; std::shared_ptr tunnel; for (const auto& it: m_OutboundTunnels) { @@ -714,8 +744,17 @@ namespace tunnel void Tunnels::ManageTunnels (uint64_t ts) { ManagePendingTunnels (ts); - ManageInboundTunnels (ts); - ManageOutboundTunnels (ts); + std::vector > tunnelsToRecreate; + ManageInboundTunnels (ts, tunnelsToRecreate); + ManageOutboundTunnels (ts, tunnelsToRecreate); + // rec-create in random order + if (!tunnelsToRecreate.empty ()) + { + if (tunnelsToRecreate.size () > 1) + std::shuffle (tunnelsToRecreate.begin(), tunnelsToRecreate.end(), m_Rng); + for (auto& it: tunnelsToRecreate) + it->Recreate (); + } } void Tunnels::ManagePendingTunnels (uint64_t ts) @@ -778,7 +817,7 @@ namespace tunnel } } - void Tunnels::ManageOutboundTunnels (uint64_t ts) + void Tunnels::ManageOutboundTunnels (uint64_t ts, std::vector >& toRecreate) { for (auto it = m_OutboundTunnels.begin (); it != m_OutboundTunnels.end ();) { @@ -802,10 +841,7 @@ namespace tunnel auto pool = tunnel->GetTunnelPool (); // let it die if the tunnel pool has been reconfigured and this is old if (pool && tunnel->GetNumHops() == pool->GetNumOutboundHops()) - { - tunnel->SetRecreated (true); - pool->RecreateOutboundTunnel (tunnel); - } + toRecreate.push_back (tunnel); } if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) tunnel->SetState (eTunnelStateExpiring); @@ -830,7 +866,7 @@ namespace tunnel } } - void Tunnels::ManageInboundTunnels (uint64_t ts) + void Tunnels::ManageInboundTunnels (uint64_t ts, std::vector >& toRecreate) { for (auto it = m_InboundTunnels.begin (); it != m_InboundTunnels.end ();) { @@ -854,10 +890,7 @@ namespace tunnel auto pool = tunnel->GetTunnelPool (); // let it die if the tunnel pool was reconfigured and has different number of hops if (pool && tunnel->GetNumHops() == pool->GetNumInboundHops()) - { - tunnel->SetRecreated (true); - pool->RecreateInboundTunnel (tunnel); - } + toRecreate.push_back (tunnel); } if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 0cb87ace..5d21cd8b 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -99,6 +99,7 @@ namespace tunnel void SetRecreated (bool recreated) { m_IsRecreated = recreated; }; int GetNumHops () const { return m_Hops.size (); }; virtual bool IsInbound() const = 0; + virtual bool Recreate () = 0; std::shared_ptr GetTunnelPool () const { return m_Pool; }; void SetTunnelPool (std::shared_ptr pool) { m_Pool = pool; }; @@ -150,6 +151,7 @@ namespace tunnel void HandleTunnelDataMsg (std::shared_ptr&& tunnelMsg) override; bool IsInbound() const override { return false; } + bool Recreate () override; private: @@ -166,6 +168,7 @@ namespace tunnel void HandleTunnelDataMsg (std::shared_ptr&& msg) override; virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; bool IsInbound() const override { return true; } + bool Recreate () override; // override TunnelBase void Cleanup () override { m_Endpoint.Cleanup (); }; @@ -262,8 +265,8 @@ namespace tunnel void Run (); void ManageTunnels (uint64_t ts); - void ManageOutboundTunnels (uint64_t ts); - void ManageInboundTunnels (uint64_t ts); + void ManageOutboundTunnels (uint64_t ts, std::vector >& toRecreate); + void ManageInboundTunnels (uint64_t ts, std::vector >& toRecreate); void ManagePendingTunnels (uint64_t ts); template void ManagePendingTunnels (PendingTunnels& pendingTunnels, uint64_t ts); From 2ce31451957fbd80456be726e274e76dd8542e67 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 2 Feb 2025 18:05:46 -0500 Subject: [PATCH 362/527] Build IRC tunnel through low bandwidth routers --- contrib/tunnels.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/tunnels.conf b/contrib/tunnels.conf index 55723c43..fc455e79 100644 --- a/contrib/tunnels.conf +++ b/contrib/tunnels.conf @@ -5,6 +5,7 @@ port = 6668 destination = irc.ilita.i2p destinationport = 6667 keys = irc-keys.dat +i2p.streaming.profile=2 #[IRC-IRC2P] #type = client From ef19a85fc099277eef1e0f36e5a25df0c665b547 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 3 Feb 2025 20:41:51 -0500 Subject: [PATCH 363/527] use correct OBEP inbound tunnel build --- libi2pd/Tunnel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index f8be27ec..9e04fc0a 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -103,7 +103,7 @@ namespace tunnel if (m_Config->IsShort ()) { auto ident = m_Config->GetFirstHop () ? m_Config->GetFirstHop ()->ident : nullptr; - if (ident && ident->GetIdentHash () != outboundTunnel->GetNextIdentHash ()) // don't encrypt if IBGW = OBEP + if (ident && ident->GetIdentHash () != outboundTunnel->GetEndpointIdentHash ()) // don't encrypt if IBGW = OBEP { auto msg1 = i2p::garlic::WrapECIESX25519MessageForRouter (msg, ident->GetEncryptionPublicKey ()); if (msg1) msg = msg1; From 5ff52e6c93ccd917134b3b61f98355ff291897b8 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 8 Feb 2025 07:45:04 -0500 Subject: [PATCH 364/527] Removed rus.i2p from subscriptions --- contrib/i2pd.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 1d71b180..c26f8af0 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -243,7 +243,7 @@ verify = true ## Default: reg.i2p at "mainline" I2P Network # defaulturl = http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt ## Optional subscriptions URLs, separated by comma -# subscriptions = http://reg.i2p/hosts.txt,http://identiguy.i2p/hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt,http://rus.i2p/hosts.txt +# subscriptions = http://reg.i2p/hosts.txt,http://identiguy.i2p/hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt [limits] ## Maximum active transit sessions (default: 5000) From 8aa18add4b8e7f9442af14e878d48821e274481b Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 8 Feb 2025 15:51:13 -0500 Subject: [PATCH 365/527] 2.56.0 --- ChangeLog | 23 +++++++++++++++++++++++ contrib/rpm/i2pd-git.spec | 5 ++++- contrib/rpm/i2pd.spec | 5 ++++- debian/changelog | 6 ++++++ libi2pd/version.h | 4 ++-- 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index e638a919..e4d24958 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,29 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.56.0] - 2025-02-10 +### Added +- Config params for shared local destination +- AddressBook full addresses cache +- Decline transit tunnel to duplicated router +- Recreate tunnels in random order +### Changed +- Exclude disk operations from SSU2 and NTCP2 threads +- Set minimal version for peer test to 0.9.62 +- Send ack requested flag after second SSU2 resend attempt +- Shorter ECIESx25519 ack request interval for datagram and I2CP sessions +- Don't change datagram routing path too often if unidirectional data stream +- Reduce LeaseSet and local RouterInfo publishing confimation intervals +- Don't delete buffer of connected routers or if an update received +- Smaller RouterInfo request timeout if sent directly +- Persist local RouterInfo in separate thread +- Don't recalculate and process ranges for every SSU2 Ack block +- Reseeds list +### Fixed +- Termination deadlock if SAM session is active +- Race condition at tunnel endpoint +- Inbound tunnel build encryption + ## [2.55.0] - 2024-12-30 ### Added - Support boost 1.87 diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index fb5dfb52..9e081eab 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -1,7 +1,7 @@ %define git_hash %(git rev-parse HEAD | cut -c -7) Name: i2pd-git -Version: 2.55.0 +Version: 2.56.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -148,6 +148,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Sun Feb 09 2025 orignal - 2.56.0 +- update to 2.56.0 + * Mon Dec 30 2024 orignal - 2.55.0 - update to 2.55.0 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index ed85a079..c6f0f9f0 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.55.0 +Version: 2.56.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git @@ -146,6 +146,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Sun Feb 09 2025 orignal - 2.56.0 +- update to 2.56.0 + * Mon Dec 30 2024 orignal - 2.55.0 - update to 2.55.0 diff --git a/debian/changelog b/debian/changelog index d84ae445..7a5d72e8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.56.0-1) unstable; urgency=medium + + * updated to version 2.56.0/0.9.65 + + -- orignal Sun, 09 Feb 2025 16:00:00 +0000 + i2pd (2.55.0-1) unstable; urgency=medium * updated to version 2.55.0 diff --git a/libi2pd/version.h b/libi2pd/version.h index 09209c1c..1e63ae08 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -18,7 +18,7 @@ #define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 55 +#define I2PD_VERSION_MINOR 56 #define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #ifdef GITVER @@ -33,7 +33,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 64 +#define I2P_VERSION_MICRO 65 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) #define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) From 8a7c4040b6bbab5b6349595ebbf67fc715ffbd6f Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Sat, 8 Feb 2025 22:58:51 +0200 Subject: [PATCH 366/527] fix typo --- libi2pd/TunnelEndpoint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/TunnelEndpoint.h b/libi2pd/TunnelEndpoint.h index 79393efe..1e81c445 100644 --- a/libi2pd/TunnelEndpoint.h +++ b/libi2pd/TunnelEndpoint.h @@ -49,7 +49,7 @@ namespace tunnel void HandleDecryptedTunnelDataMsg (std::shared_ptr msg); void FlushI2NPMsgs (); - const i2p::data::IdentHash * GetCurrentHash () const; // return null if not avaiable + const i2p::data::IdentHash * GetCurrentHash () const; // return null if not available const std::unique_ptr& GetSender () const { return m_Sender; }; private: From 58a86fa2dc156978055d564cefe651de50016ecf Mon Sep 17 00:00:00 2001 From: r4sas Date: Mon, 10 Feb 2025 22:10:06 +0000 Subject: [PATCH 367/527] [build] OpenSSL linking reorder (#2156) Signed-off-by: r4sas --- Makefile.bsd | 2 +- Makefile.haiku | 2 +- Makefile.homebrew | 2 +- Makefile.linux | 2 +- Makefile.osx | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile.bsd b/Makefile.bsd index 4cf8f80a..1c911802 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -3,7 +3,7 @@ CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misl DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1 INCFLAGS = -I/usr/include/ -I/usr/local/include/ LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib -LDLIBS = -lcrypto -lssl -lz -lpthread -lboost_system -lboost_program_options +LDLIBS = -lssl -lcrypto -lz -lpthread -lboost_system -lboost_program_options ## NOTE: NEEDED_CXXFLAGS is here so that custom CXXFLAGS can be specified at build time ## **without** overwriting the CXXFLAGS which we need in order to build. diff --git a/Makefile.haiku b/Makefile.haiku index d0824d73..bc3094f6 100644 --- a/Makefile.haiku +++ b/Makefile.haiku @@ -2,7 +2,7 @@ CXX = g++ CXXFLAGS := -Wall -std=c++17 INCFLAGS = -I/system/develop/headers DEFINES = -D_DEFAULT_SOURCE -D_GNU_SOURCE -LDLIBS = -lbe -lbsd -lnetwork -lz -lcrypto -lssl -lboost_system -lboost_program_options -lpthread +LDLIBS = -lbe -lbsd -lnetwork -lz -lssl -lcrypto -lboost_system -lboost_program_options -lpthread ifeq ($(USE_UPNP),yes) DEFINES += -DUSE_UPNP diff --git a/Makefile.homebrew b/Makefile.homebrew index ced8c117..706f9811 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -18,7 +18,7 @@ endif LDLIBS += -lpthread -ldl else LDFLAGS += -L${SSLROOT}/lib -L${BOOSTROOT}/lib - LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_filesystem -lboost_program_options -lpthread + LDLIBS = -lz -lssl -lcrypto -lboost_system -lboost_filesystem -lboost_program_options -lpthread ifeq ($(USE_UPNP),yes) LDFLAGS += -L${UPNPROOT}/lib LDLIBS += -lminiupnpc diff --git a/Makefile.linux b/Makefile.linux index 5dfed6a8..4ea39e22 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -40,7 +40,7 @@ ifeq ($(USE_UPNP),yes) endif LDLIBS += -lpthread -ldl else - LDLIBS += -lcrypto -lssl -lz -lboost_program_options -lpthread -latomic + LDLIBS += -lssl -lcrypto -lz -lboost_program_options -lpthread -latomic ifeq ($(USE_UPNP),yes) LDLIBS += -lminiupnpc endif diff --git a/Makefile.osx b/Makefile.osx index c509ea7c..52282307 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -7,9 +7,9 @@ LDFLAGS += -Wl,-dead_strip LDFLAGS += -Wl,-dead_strip_dylibs ifeq ($(USE_STATIC),yes) - LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread + LDLIBS = -lz /usr/local/lib/libssl.a /usr/local/lib/libcrypto.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread else - LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_filesystem -lboost_program_options -lpthread + LDLIBS = -lz -lssl -lcrypto -lboost_system -lboost_filesystem -lboost_program_options -lpthread endif ifeq ($(USE_UPNP),yes) From fb90b01f6c2f71831f854b3f43fc79fde246ee33 Mon Sep 17 00:00:00 2001 From: r4sas Date: Tue, 11 Feb 2025 22:15:11 +0300 Subject: [PATCH 368/527] 2.56.0 Signed-off-by: r4sas --- ChangeLog | 10 +++++----- contrib/rpm/i2pd-git.spec | 2 +- contrib/rpm/i2pd.spec | 2 +- debian/changelog | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index e4d24958..23864c0e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog -## [2.56.0] - 2025-02-10 +## [2.56.0] - 2025-02-11 ### Added - Config params for shared local destination - AddressBook full addresses cache @@ -12,8 +12,8 @@ - Set minimal version for peer test to 0.9.62 - Send ack requested flag after second SSU2 resend attempt - Shorter ECIESx25519 ack request interval for datagram and I2CP sessions -- Don't change datagram routing path too often if unidirectional data stream -- Reduce LeaseSet and local RouterInfo publishing confimation intervals +- Don't change datagram routing path too often if unidirectional data stream +- Reduce LeaseSet and local RouterInfo publishing confirmation intervals - Don't delete buffer of connected routers or if an update received - Smaller RouterInfo request timeout if sent directly - Persist local RouterInfo in separate thread @@ -85,12 +85,12 @@ - Handle i2cp.inboundlimit and i2cp.outboundlimit params in I2CP - Publish LeaseSet with new timestamp update if tunnel was replaced in the same second - Increase max number of generated tags to 800 per tagset -- Routing path expiration by time instead num attempts +- Routing path expiration by time instead num attempts - Save timestamp from epoch instead local time to profiles - Update introducer's iTag if session to introducer was replaced to new one - RTT, window size and number of NACKs calculation for streaming - Don't select same peer for tunnel too often -- Use WinApi for data path UTF-8 conversion for Windows +- Use WinApi for data path UTF-8 conversion for Windows ### Fixed - Jump link crash if address book is disabled - Race condition if connect through an introducer diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 9e081eab..2083ba18 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -148,7 +148,7 @@ getent passwd i2pd >/dev/null || \ %changelog -* Sun Feb 09 2025 orignal - 2.56.0 +* Tue Feb 11 2025 orignal - 2.56.0 - update to 2.56.0 * Mon Dec 30 2024 orignal - 2.55.0 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index c6f0f9f0..4eb558ba 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -146,7 +146,7 @@ getent passwd i2pd >/dev/null || \ %changelog -* Sun Feb 09 2025 orignal - 2.56.0 +* Tue Feb 11 2025 orignal - 2.56.0 - update to 2.56.0 * Mon Dec 30 2024 orignal - 2.55.0 diff --git a/debian/changelog b/debian/changelog index 7a5d72e8..d170f534 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,7 +2,7 @@ i2pd (2.56.0-1) unstable; urgency=medium * updated to version 2.56.0/0.9.65 - -- orignal Sun, 09 Feb 2025 16:00:00 +0000 + -- orignal Tue, 11 Feb 2025 16:00:00 +0000 i2pd (2.55.0-1) unstable; urgency=medium From 78a37cc00f028a51b4d04de688aa93caf60611e6 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 12 Feb 2025 15:56:22 -0500 Subject: [PATCH 369/527] changed some log levels --- libi2pd_client/ClientContext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 570df9b0..f103636e 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -297,7 +297,7 @@ namespace client } else { - LogPrint (eLogCritical, "Clients: Can't open file ", fullPath, " Creating new one with signature type ", sigType, " crypto type ", cryptoType); + LogPrint (eLogInfo, "Clients: Can't open file ", fullPath, " Creating new one with signature type ", sigType, " crypto type ", cryptoType); keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true); std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out); size_t len = keys.GetFullLen (); @@ -871,7 +871,7 @@ namespace client } else - LogPrint (eLogWarning, "Clients: Unknown section type = ", type, " of ", name, " in ", tunConf); + LogPrint (eLogError, "Clients: Unknown section type = ", type, " of ", name, " in ", tunConf); } catch (std::exception& ex) { From 05881164898a0a717400d2f1267a6ec2815a7b29 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 14 Feb 2025 13:08:22 -0500 Subject: [PATCH 370/527] make token always non-zero --- libi2pd/SSU2.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 8625eaa4..fc2355a5 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1251,18 +1251,21 @@ namespace transport } uint64_t token; RAND_bytes ((uint8_t *)&token, 8); - m_IncomingTokens.emplace (ep, std::make_pair (token, uint32_t(ts + SSU2_TOKEN_EXPIRATION_TIMEOUT))); + if (!token) token = 1; // token can't be zero + m_IncomingTokens.try_emplace (ep, token, uint32_t(ts + SSU2_TOKEN_EXPIRATION_TIMEOUT)); return token; } std::pair SSU2Server::NewIncomingToken (const boost::asio::ip::udp::endpoint& ep) { - m_IncomingTokens.erase (ep); // drop previous uint64_t token; RAND_bytes ((uint8_t *)&token, 8); - auto ret = std::make_pair (token, uint32_t(i2p::util::GetSecondsSinceEpoch () + SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT)); - m_IncomingTokens.emplace (ep, ret); - return ret; + if (!token) token = 1; // token can't be zero + uint32_t expires = i2p::util::GetSecondsSinceEpoch () + SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT; + auto [it, inserted] = m_IncomingTokens.try_emplace (ep, token, expires); + if (!inserted) + it->second = { token, expires }; // override + return it->second; } std::vector > SSU2Server::FindIntroducers (int maxNumIntroducers, From 4bb86b6a86dabe0c3754149f3dd16db2b75dc01b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 14 Feb 2025 18:18:28 -0500 Subject: [PATCH 371/527] don't request LeaseSet until destination if ready --- libi2pd_client/I2CP.cpp | 18 ++++++++++++++++-- libi2pd_client/I2CP.h | 3 ++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 88465143..ccbdee4b 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -29,13 +29,15 @@ namespace client const std::map& params): LeaseSetDestination (service, isPublic, ¶ms), m_Owner (owner), m_Identity (identity), m_EncryptionKeyType (m_Identity->GetCryptoKeyType ()), - m_IsCreatingLeaseSet (false), m_IsSameThread (isSameThread), m_LeaseSetCreationTimer (service) + m_IsCreatingLeaseSet (false), m_IsSameThread (isSameThread), + m_LeaseSetCreationTimer (service), m_ReadinessCheckTimer (service) { } void I2CPDestination::Stop () { m_LeaseSetCreationTimer.cancel (); + m_ReadinessCheckTimer.cancel (); LeaseSetDestination::Stop (); m_Owner = nullptr; } @@ -88,7 +90,7 @@ namespace client void I2CPDestination::CreateNewLeaseSet (const std::vector >& tunnels) { - boost::asio::post (GetService (), std::bind (&I2CPDestination::PostCreateNewLeaseSet, this, tunnels)); + boost::asio::post (GetService (), std::bind (&I2CPDestination::PostCreateNewLeaseSet, GetSharedFromThis (), tunnels)); } void I2CPDestination::PostCreateNewLeaseSet (std::vector > tunnels) @@ -98,6 +100,18 @@ namespace client LogPrint (eLogInfo, "I2CP: LeaseSet is being created"); return; } + m_ReadinessCheckTimer.cancel (); + if (!IsReady ()) + { + // try again later + m_ReadinessCheckTimer.expires_from_now (boost::posix_time::seconds(I2CP_DESTINATION_READINESS_CHECK_INTERVAL)); + m_ReadinessCheckTimer.async_wait( + [s=GetSharedFromThis (), tunnels=std::move(tunnels)](const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + s->PostCreateNewLeaseSet (tunnels); + }); + } uint8_t priv[256] = {0}; i2p::data::LocalLeaseSet ls (m_Identity, priv, tunnels); // we don't care about encryption key, we need leases only m_LeaseSetExpirationTime = ls.GetExpirationTime (); diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index d5ac648e..50b668d3 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -31,6 +31,7 @@ namespace client const size_t I2CP_MAX_MESSAGE_LENGTH = 65535; const size_t I2CP_MAX_SEND_QUEUE_SIZE = 1024*1024; // in bytes, 1M const int I2CP_LEASESET_CREATION_TIMEOUT = 10; // in seconds + const int I2CP_DESTINATION_READINESS_CHECK_INTERVAL = 5; // in seconds const int I2CP_SESSION_ACK_REQUEST_INTERVAL = 12100; // in milliseconds const size_t I2CP_HEADER_LENGTH_OFFSET = 0; @@ -131,7 +132,7 @@ namespace client uint8_t m_ECIESx25519PrivateKey[32]; uint64_t m_LeaseSetExpirationTime; bool m_IsCreatingLeaseSet, m_IsSameThread; - boost::asio::deadline_timer m_LeaseSetCreationTimer; + boost::asio::deadline_timer m_LeaseSetCreationTimer, m_ReadinessCheckTimer; i2p::util::MemoryPoolMt > m_I2NPMsgsPool; }; From 48aaecaccebaa3a4b646971b825849aeb07554a5 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 14 Feb 2025 21:53:38 -0500 Subject: [PATCH 372/527] check outbound tunnels only for LeaseSet request --- libi2pd_client/I2CP.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index ccbdee4b..f6494a51 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -101,7 +101,8 @@ namespace client return; } m_ReadinessCheckTimer.cancel (); - if (!IsReady ()) + auto pool = GetTunnelPool (); + if (!pool || pool->GetOutboundTunnels ().empty ()) { // try again later m_ReadinessCheckTimer.expires_from_now (boost::posix_time::seconds(I2CP_DESTINATION_READINESS_CHECK_INTERVAL)); @@ -111,6 +112,7 @@ namespace client if (ecode != boost::asio::error::operation_aborted) s->PostCreateNewLeaseSet (tunnels); }); + return; } uint8_t priv[256] = {0}; i2p::data::LocalLeaseSet ls (m_Identity, priv, tunnels); // we don't care about encryption key, we need leases only From 3d19fa12f6abb3e14e59ed27a3b7409c1ccd4d1f Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 15 Feb 2025 15:27:14 -0500 Subject: [PATCH 373/527] create new tunnel immediately if last one failed --- libi2pd/TunnelPool.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index f20c491c..26367aa6 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -351,10 +351,13 @@ namespace tunnel { it.second.first->SetState (eTunnelStateFailed); std::unique_lock l(m_OutboundTunnelsMutex); - if (m_OutboundTunnels.size () > 1 || m_NumOutboundTunnels <= 1) // don't fail last tunnel + if (m_OutboundTunnels.size () > 1) // don't fail last tunnel m_OutboundTunnels.erase (it.second.first); else + { it.second.first->SetState (eTunnelStateTestFailed); + CreateOutboundTunnel (); // create new tunnel immediately because last one failed + } } else if (it.second.first->GetState () != eTunnelStateExpiring) it.second.first->SetState (eTunnelStateTestFailed); @@ -368,13 +371,16 @@ namespace tunnel bool failed = false; { std::unique_lock l(m_InboundTunnelsMutex); - if (m_InboundTunnels.size () > 1 || m_NumInboundTunnels <= 1) // don't fail last tunnel + if (m_InboundTunnels.size () > 1) // don't fail last tunnel { m_InboundTunnels.erase (it.second.second); failed = true; } else + { it.second.second->SetState (eTunnelStateTestFailed); + CreateInboundTunnel (); // create new tunnel immediately because last one failed + } } if (failed && m_LocalDestination) m_LocalDestination->SetLeaseSetUpdated (true); From fa2178ca3e4c619cce5ef778a870a62c9f2a48f9 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 17 Feb 2025 15:08:22 -0500 Subject: [PATCH 374/527] set max padding size to 32 bytes --- libi2pd/SSU2Session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 41c5bb11..b12222f2 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2762,7 +2762,7 @@ namespace transport size_t SSU2Session::CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize) { if (len < 3 || len < minSize) return 0; - size_t paddingSize = m_Server.GetRng ()() & 0x0F; // 0 - 15 + size_t paddingSize = m_Server.GetRng ()() & 0x1F; // 0 - 31 if (paddingSize + 3 > len) paddingSize = len - 3; else if (paddingSize + 3 < minSize) paddingSize = minSize - 3; buf[0] = eSSU2BlkPadding; From 251605e2b86c25b854b7981e1db7775f05cdc3b0 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 18 Feb 2025 20:22:18 -0500 Subject: [PATCH 375/527] Fix the calculation of the window drop size --- libi2pd/Streaming.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index b5e520b9..dfe2ff6a 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1297,7 +1297,7 @@ namespace stream m_NumPacketsToSend = 1; m_PacingTimeRem = 0; } m_IsSendTime = true; - if (m_WindowIncCounter && (m_WindowSize < MAX_WINDOW_SIZE || m_WindowDropTargetSize) && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) + if (m_WindowIncCounter && (m_WindowSize < MAX_WINDOW_SIZE || m_WindowDropTargetSize) && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime && m_RTT <= m_SlowRTT) { for (int i = 0; i < m_NumPacketsToSend; i++) { @@ -1307,7 +1307,7 @@ namespace stream { if (m_LastWindowDropSize && (m_LastWindowDropSize >= m_WindowDropTargetSize)) m_WindowDropTargetSize += 1 - (1 / ((m_LastWindowDropSize + PREV_SPEED_KEEP_TIME_COEFF) / m_WindowDropTargetSize)); // some magic here - else if (m_LastWindowDropSize && (m_LastWindowDropSize < m_WindowSize)) + else if (m_LastWindowDropSize && (m_LastWindowDropSize < m_WindowDropTargetSize)) m_WindowDropTargetSize += (m_WindowDropTargetSize - (m_LastWindowDropSize - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowDropTargetSize; // some magic here else m_WindowDropTargetSize += (m_WindowDropTargetSize - (1 - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowDropTargetSize; @@ -1646,14 +1646,22 @@ namespace stream void Stream::ProcessWindowDrop () { - if (m_WindowSize > m_LastWindowDropSize) - { - m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize + m_WindowSizeTail) / 2; - if (m_LastWindowDropSize > MAX_WINDOW_SIZE) m_LastWindowDropSize = MAX_WINDOW_SIZE; - } + if (m_WindowDropTargetSize) + m_WindowDropTargetSize = (m_WindowDropTargetSize / 2) * 0.75; // congestion window size and -25% to drain queue else - m_LastWindowDropSize = m_WindowSize; - m_WindowDropTargetSize = m_LastWindowDropSize - (m_LastWindowDropSize / 4); // -25%; + { + if (m_WindowSize < m_LastWindowDropSize) + { + m_LastWindowDropSize = m_WindowSize - (m_LastWindowDropSize - m_WindowSize); + if (m_LastWindowDropSize < MIN_WINDOW_SIZE) m_LastWindowDropSize = MIN_WINDOW_SIZE; + } + else + { + m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize + m_WindowSizeTail) / 2; + if (m_LastWindowDropSize > MAX_WINDOW_SIZE) m_LastWindowDropSize = MAX_WINDOW_SIZE; + } + m_WindowDropTargetSize = m_LastWindowDropSize * 0.75; // -25% to drain queue + } if (m_WindowDropTargetSize < MIN_WINDOW_SIZE) m_WindowDropTargetSize = MIN_WINDOW_SIZE; m_WindowIncCounter = 0; // disable window growth From ef72ba3f349e0b6888e98625d553229ff0c51bde Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 18 Feb 2025 21:11:59 -0500 Subject: [PATCH 376/527] parse RouterInfo from buffer --- libi2pd/RouterInfo.cpp | 205 ++++++++++++++++++++++------------------- libi2pd/RouterInfo.h | 13 ++- 2 files changed, 117 insertions(+), 101 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 9cad82ab..13ce0c20 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -11,6 +11,7 @@ #include "I2PEndian.h" #include #include +#include #include #include // for boost::to_lower #ifndef __cpp_lib_atomic_shared_ptr @@ -106,8 +107,7 @@ namespace data // skip identity size_t identityLen = m_RouterIdentity->GetFullLen (); // read new RI - std::stringstream str (std::string ((char *)buf + identityLen, len - identityLen)); - ReadFromStream (str); + ReadFromBuffer (buf + identityLen, len - identityLen); if (!m_IsUnreachable) UpdateBuffer (buf, len); // save buffer // don't delete buffer until saved to the file @@ -195,39 +195,33 @@ namespace data } } // parse RI - std::stringstream str; - str.write ((const char *)m_Buffer->data () + identityLen, bufferLen - identityLen); - ReadFromStream (str); - if (!str) + if (!ReadFromBuffer (m_Buffer->data () + identityLen, bufferLen - identityLen)) { LogPrint (eLogError, "RouterInfo: Malformed message"); m_IsUnreachable = true; - } + } } - void RouterInfo::ReadFromStream (std::istream& s) + bool RouterInfo::ReadFromBuffer (const uint8_t * buf, size_t len) { - if (!s) return; + if (len < 9) return false; m_Caps = 0; m_Congestion = eLowCongestion; - s.read ((char *)&m_Timestamp, sizeof (m_Timestamp)); - m_Timestamp = be64toh (m_Timestamp); + m_Timestamp = bufbe64toh (buf); + size_t offset = 8; // timestamp // read addresses auto addresses = NewAddresses (); - uint8_t numAddresses; - s.read ((char *)&numAddresses, sizeof (numAddresses)); + uint8_t numAddresses = buf[offset]; offset++; for (int i = 0; i < numAddresses; i++) { uint8_t supportedTransports = 0; auto address = NewAddress (); - uint8_t cost; // ignore - s.read ((char *)&cost, sizeof (cost)); - s.read ((char *)&address->date, sizeof (address->date)); + offset++; // cost, ignore + address->date = bufbe64toh (buf + offset); offset += 8; // date bool isHost = false, isStaticKey = false, isV2 = false, isIntroKey = false; - char transportStyle[6]; - ReadString (transportStyle, 6, s); - if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2 + auto transportStyle = ExtractString (buf + offset, len - offset); offset += transportStyle.length () + 1; + if (!transportStyle.compare (0, 4, "NTCP")) // NTCP or NTCP2 address->transportStyle = eTransportNTCP2; - else if (!strncmp (transportStyle, "SSU", 3)) // SSU or SSU2 + else if (!transportStyle.compare (0, 3, "SSU")) // SSU or SSU2 { address->transportStyle = eTransportSSU2; address->ssu.reset (new SSUExt ()); @@ -237,24 +231,21 @@ namespace data address->transportStyle = eTransportUnknown; address->caps = 0; address->port = 0; - uint16_t size, r = 0; - s.read ((char *)&size, sizeof (size)); if (!s) return; - size = be16toh (size); + uint16_t size = bufbe16toh (buf + offset); offset += 2; // size + if (offset + size >= len) return false; if (address->transportStyle == eTransportUnknown) { // skip unknown address - s.seekg (size, std::ios_base::cur); - if (s) continue; else return; + offset += size; + continue; } + size_t r = 0; while (r < size) { - char key[255], value[255]; - r += ReadString (key, 255, s); - s.seekg (1, std::ios_base::cur); r++; // = - r += ReadString (value, 255, s); - s.seekg (1, std::ios_base::cur); r++; // ; - if (!s) return; - if (!strcmp (key, "host")) + auto [key, value, sz] = ExtractParam (buf + offset, len - offset); + r += sz; offset += sz; + if (key.empty ()) continue; + if (key == "host") { boost::system::error_code ecode; address->host = boost::asio::ip::make_address (value, ecode); @@ -268,7 +259,7 @@ namespace data address->transportStyle = eTransportUnknown; } } - else if (!strcmp (key, "port")) + else if (key == "port") { try { @@ -279,7 +270,7 @@ namespace data LogPrint (eLogWarning, "RouterInfo: 'port' exception ", ex.what ()); } } - else if (!strcmp (key, "mtu")) + else if (key == "mtu") { if (address->ssu) { @@ -295,36 +286,36 @@ namespace data else LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP2"); } - else if (!strcmp (key, "caps")) + else if (key == "caps") address->caps = ExtractAddressCaps (value); - else if (!strcmp (key, "s")) // ntcp2 or ssu2 static key + else if (key == "s") // ntcp2 or ssu2 static key { - if (Base64ToByteStream (value, strlen (value), address->s, 32) == 32 && + if (Base64ToByteStream (value.data (), value.length (), address->s, 32) == 32 && !(address->s[31] & 0x80)) // check if x25519 public key isStaticKey = true; else address->transportStyle = eTransportUnknown; // invalid address } - else if (!strcmp (key, "i")) // ntcp2 iv or ssu2 intro + else if (key == "i") // ntcp2 iv or ssu2 intro { if (address->IsNTCP2 ()) { - if (Base64ToByteStream (value, strlen (value), address->i, 16) == 16) + if (Base64ToByteStream (value.data (), value.length (), address->i, 16) == 16) address->published = true; // presence of "i" means "published" NTCP2 else address->transportStyle = eTransportUnknown; // invalid address } else if (address->IsSSU2 ()) { - if (Base64ToByteStream (value, strlen (value), address->i, 32) == 32) + if (Base64ToByteStream (value.data (), value.length (), address->i, 32) == 32) isIntroKey = true; else address->transportStyle = eTransportUnknown; // invalid address } } - else if (!strcmp (key, "v")) + else if (key == "v") { - if (!strcmp (value, "2")) + if (value == "2") isV2 = true; else { @@ -340,13 +331,11 @@ namespace data LogPrint (eLogError, "RouterInfo: Introducer is presented for non-SSU address. Skipped"); continue; } - size_t l = strlen(key); - unsigned char index = key[l-1] - '0'; // TODO: - key[l-1] = 0; + unsigned char index = key[key.length () - 1] - '0'; // TODO: if (index > 9) { LogPrint (eLogError, "RouterInfo: Unexpected introducer's index ", index, " skipped"); - if (s) continue; else return; + continue; } if (index >= address->ssu->introducers.size ()) { @@ -355,7 +344,8 @@ namespace data address->ssu->introducers.resize (index + 1); } Introducer& introducer = address->ssu->introducers.at (index); - if (!strcmp (key, "itag")) + auto key1 = key.substr(0, key.length () - 1); + if (key1 == "itag") { try { @@ -366,9 +356,9 @@ namespace data LogPrint (eLogWarning, "RouterInfo: 'itag' exception ", ex.what ()); } } - else if (!strcmp (key, "ih")) - Base64ToByteStream (value, strlen (value), introducer.iH, 32); - else if (!strcmp (key, "iexp")) + else if (key1 == "ih") + Base64ToByteStream (value.data (), value.length (), introducer.iH, 32); + else if (key1 == "iexp") { try { @@ -380,9 +370,7 @@ namespace data } } } - if (!s) return; - } - + } if (address->transportStyle == eTransportNTCP2) { if (isStaticKey) @@ -446,45 +434,40 @@ namespace data boost::atomic_store (&m_Addresses, addresses); #endif // read peers - uint8_t numPeers; - s.read ((char *)&numPeers, sizeof (numPeers)); if (!s) return; - s.seekg (numPeers*32, std::ios_base::cur); // TODO: read peers + uint8_t numPeers = buf[offset]; offset++; // num peers + offset += numPeers*32; // TODO: read peers + if (offset >= len) return false; // read properties m_Version = 0; bool isNetId = false; std::string family; - uint16_t size, r = 0; - s.read ((char *)&size, sizeof (size)); if (!s) return; - size = be16toh (size); + uint16_t size = bufbe16toh (buf + offset); offset += 2; // size + if (offset + size > len) return false; + size_t r = 0; while (r < size) { - char key[255], value[255]; - r += ReadString (key, 255, s); - s.seekg (1, std::ios_base::cur); r++; // = - r += ReadString (value, 255, s); - s.seekg (1, std::ios_base::cur); r++; // ; - if (!s) return; + auto [key, value, sz] = ExtractParam (buf + offset, len - offset); + r += sz; offset += sz; + if (key.empty ()) continue; SetProperty (key, value); // extract caps - if (!strcmp (key, "caps")) + if (key == "caps") { ExtractCaps (value); m_IsFloodfill = IsDeclaredFloodfill (); } // extract version - else if (!strcmp (key, ROUTER_INFO_PROPERTY_VERSION)) + else if (key == ROUTER_INFO_PROPERTY_VERSION) { m_Version = 0; - char * ch = value; - while (*ch) + for (auto ch: value) { - if (*ch >= '0' && *ch <= '9') + if (ch >= '0' && ch <= '9') { m_Version *= 10; - m_Version += (*ch - '0'); + m_Version += (ch - '0'); } - ch++; } if (m_Version < NETDB_MIN_PEER_TEST_VERSION && (m_SupportedTransports & (eSSU2V4 | eSSU2V6))) { @@ -497,24 +480,26 @@ namespace data } } // check netId - else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID)) + else if (key == ROUTER_INFO_PROPERTY_NETID) { isNetId = true; - if (atoi (value) != i2p::context.GetNetID ()) + int netID; + auto res = std::from_chars(value.data(), value.data() + value.size(), netID); + if (res.ec != std::errc() || netID != i2p::context.GetNetID ()) { LogPrint (eLogError, "RouterInfo: Unexpected ", ROUTER_INFO_PROPERTY_NETID, "=", value); m_IsUnreachable = true; } } // family - else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY)) + else if (key == ROUTER_INFO_PROPERTY_FAMILY) { family = value; boost::to_lower (family); } - else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY_SIG)) + else if (key == ROUTER_INFO_PROPERTY_FAMILY_SIG) { - if (netdb.GetFamilies ().VerifyFamily (family, GetIdentHash (), value)) + if (netdb.GetFamilies ().VerifyFamily (family, GetIdentHash (), std::string(value).c_str ())) // TODO m_FamilyID = netdb.GetFamilies ().GetFamilyID (family); else { @@ -522,14 +507,14 @@ namespace data SetUnreachable (true); } } - - if (!s) return; } if (!m_SupportedTransports || !isNetId || !m_Version) SetUnreachable (true); - } - + + return true; + } + bool RouterInfo::IsFamily (FamilyID famid) const { return m_FamilyID == famid; @@ -584,6 +569,11 @@ namespace data } } + void RouterInfo::ExtractCaps (std::string_view value) + { + ExtractCaps (std::string (value).c_str ()); // TODO + } + uint8_t RouterInfo::ExtractAddressCaps (const char * value) const { uint8_t caps = 0; @@ -611,6 +601,11 @@ namespace data return caps; } + uint8_t RouterInfo::ExtractAddressCaps (std::string_view value) const + { + return ExtractAddressCaps (std::string (value).c_str ()); // TODO: + } + void RouterInfo::UpdateIntroducers (std::shared_ptr
    address, uint64_t ts) { if (!address || !address->ssu) return; @@ -670,25 +665,41 @@ namespace data return SaveToFile (fullPath, m_Buffer); } - size_t RouterInfo::ReadString (char * str, size_t len, std::istream& s) const + std::string_view RouterInfo::ExtractString (const uint8_t * buf, size_t len) const { - uint8_t l; - s.read ((char *)&l, 1); - if (l < len) - { - s.read (str, l); - if (!s) l = 0; // failed, return empty string - str[l] = 0; - } - else + uint8_t l = buf[0]; + if (l > len) { LogPrint (eLogWarning, "RouterInfo: String length ", (int)l, " exceeds buffer size ", len); - s.seekg (l, std::ios::cur); // skip - str[0] = 0; - } - return l+1; + l = len; + } + return { (const char *)(buf + 1), l }; } + std::tuple RouterInfo::ExtractParam (const uint8_t * buf, size_t len) const + { + auto key = ExtractString (buf, len); + size_t offset = key.length () + 1; + if (offset >= len) return { std::string_view(), std::string_view(), len }; + if (buf[offset] != '=') + { + LogPrint (eLogWarning, "RouterInfo: Unexpected character ", buf[offset], " instead '=' after ", key); + key = std::string_view(); + } + offset++; + if (offset >= len) return { key, std::string_view(), len }; + auto value = ExtractString (buf + offset, len - offset); + offset += value.length () + 1; + if (offset >= len) return { key, std::string_view(), len }; + if (buf[offset] != ';') + { + LogPrint (eLogWarning, "RouterInfo: Unexpected character ", buf[offset], " instead ';' after ", value); + value = std::string_view(); + } + offset++; + return { key, value, offset }; + } + void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,int port, uint8_t caps) { auto addr = std::make_shared
    (); @@ -1485,9 +1496,9 @@ namespace data s.write (properties.str ().c_str (), properties.str ().size ()); } - void LocalRouterInfo::SetProperty (const std::string& key, const std::string& value) + void LocalRouterInfo::SetProperty (std::string_view key, std::string_view value) { - m_Properties[key] = value; + m_Properties.emplace (key, value); } void LocalRouterInfo::DeleteProperty (const std::string& key) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 3a4f4fc8..8134059a 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include #include @@ -219,7 +221,7 @@ namespace data std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); }; uint64_t GetTimestamp () const { return m_Timestamp; }; int GetVersion () const { return m_Version; }; - virtual void SetProperty (const std::string& key, const std::string& value) {}; + virtual void SetProperty (std::string_view key, std::string_view value) {}; virtual void ClearProperties () {}; AddressesPtr GetAddresses () const; // should be called for local RI only, otherwise must return shared_ptr std::shared_ptr GetNTCP2V4Address () const; @@ -333,11 +335,14 @@ namespace data bool LoadFile (const std::string& fullPath); void ReadFromFile (const std::string& fullPath); - void ReadFromStream (std::istream& s); + bool ReadFromBuffer (const uint8_t * buf, size_t len); // return false if malformed void ReadFromBuffer (bool verifySignature); - size_t ReadString (char* str, size_t len, std::istream& s) const; + std::string_view ExtractString (const uint8_t * buf, size_t len) const; + std::tuple ExtractParam (const uint8_t * buf, size_t len) const; void ExtractCaps (const char * value); + void ExtractCaps (std::string_view value); uint8_t ExtractAddressCaps (const char * value) const; + uint8_t ExtractAddressCaps (std::string_view value) const; void UpdateIntroducers (std::shared_ptr
    address, uint64_t ts); template std::shared_ptr GetAddress (Filter filter) const; @@ -379,7 +384,7 @@ namespace data void UpdateCaps (uint8_t caps); bool UpdateCongestion (Congestion c); // returns true if updated - void SetProperty (const std::string& key, const std::string& value) override; + void SetProperty (std::string_view key, std::string_view value) override; void DeleteProperty (const std::string& key); std::string GetProperty (const std::string& key) const; void ClearProperties () override { m_Properties.clear (); }; From 70f99ccc213542a0b9c3573d73e1c326d65217fe Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 18 Feb 2025 21:49:07 -0500 Subject: [PATCH 377/527] update router caps --- libi2pd/RouterInfo.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 13ce0c20..9fc898d7 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1498,7 +1498,9 @@ namespace data void LocalRouterInfo::SetProperty (std::string_view key, std::string_view value) { - m_Properties.emplace (key, value); + auto [it, inserted] = m_Properties.emplace (key, value); + if (!inserted) + it->second = value; } void LocalRouterInfo::DeleteProperty (const std::string& key) From d09367d68658a06d3d3370cb8106253284858882 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 19 Feb 2025 11:08:47 -0500 Subject: [PATCH 378/527] always pass RouterInfo param values as string_view --- libi2pd/Family.cpp | 8 ++++---- libi2pd/Family.h | 5 +++-- libi2pd/RouterInfo.cpp | 39 ++++++++++++++------------------------- libi2pd/RouterInfo.h | 2 -- 4 files changed, 21 insertions(+), 33 deletions(-) diff --git a/libi2pd/Family.cpp b/libi2pd/Family.cpp index 89e825f1..f8cf9c0a 100644 --- a/libi2pd/Family.cpp +++ b/libi2pd/Family.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 * @@ -90,10 +90,10 @@ namespace data } bool Families::VerifyFamily (const std::string& family, const IdentHash& ident, - const char * signature, const char * key) const + std::string_view signature, const char * key) const { uint8_t buf[100], signatureBuf[64]; - size_t len = family.length (), signatureLen = strlen (signature); + size_t len = family.length (); if (len + 32 > 100) { LogPrint (eLogError, "Family: ", family, " is too long"); @@ -105,7 +105,7 @@ namespace data memcpy (buf, family.c_str (), len); memcpy (buf + len, (const uint8_t *)ident, 32); len += 32; - auto signatureBufLen = Base64ToByteStream (signature, signatureLen, signatureBuf, 64); + auto signatureBufLen = Base64ToByteStream (signature.data (), signature.length (), signatureBuf, 64); if (signatureBufLen) { EVP_MD_CTX * ctx = EVP_MD_CTX_create (); diff --git a/libi2pd/Family.h b/libi2pd/Family.h index a82e3042..fcf61082 100644 --- a/libi2pd/Family.h +++ b/libi2pd/Family.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 * @@ -11,6 +11,7 @@ #include #include +#include #include #include #include "Identity.h" @@ -28,7 +29,7 @@ namespace data ~Families (); void LoadCertificates (); bool VerifyFamily (const std::string& family, const IdentHash& ident, - const char * signature, const char * key = nullptr) const; + std::string_view signature, const char * key = nullptr) const; FamilyID GetFamilyID (const std::string& family) const; private: diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 9fc898d7..b741134e 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -213,6 +213,7 @@ namespace data uint8_t numAddresses = buf[offset]; offset++; for (int i = 0; i < numAddresses; i++) { + if (offset + 9 > len) return false; // 1 byte cost + 8 bytes date uint8_t supportedTransports = 0; auto address = NewAddress (); offset++; // cost, ignore @@ -231,6 +232,7 @@ namespace data address->transportStyle = eTransportUnknown; address->caps = 0; address->port = 0; + if (offset + 2 > len) return false; uint16_t size = bufbe16toh (buf + offset); offset += 2; // size if (offset + size >= len) return false; if (address->transportStyle == eTransportUnknown) @@ -434,10 +436,11 @@ namespace data boost::atomic_store (&m_Addresses, addresses); #endif // read peers + if (offset + 1 > len) return false; uint8_t numPeers = buf[offset]; offset++; // num peers offset += numPeers*32; // TODO: read peers - if (offset >= len) return false; // read properties + if (offset + 2 > len) return false; m_Version = 0; bool isNetId = false; std::string family; @@ -499,7 +502,7 @@ namespace data } else if (key == ROUTER_INFO_PROPERTY_FAMILY_SIG) { - if (netdb.GetFamilies ().VerifyFamily (family, GetIdentHash (), std::string(value).c_str ())) // TODO + if (netdb.GetFamilies ().VerifyFamily (family, GetIdentHash (), value)) // TODO m_FamilyID = netdb.GetFamilies ().GetFamilyID (family); else { @@ -520,12 +523,11 @@ namespace data return m_FamilyID == famid; } - void RouterInfo::ExtractCaps (const char * value) + void RouterInfo::ExtractCaps (std::string_view value) { - const char * cap = value; - while (*cap) + for (auto cap: value) { - switch (*cap) + switch (cap) { case CAPS_FLAG_FLOODFILL: m_Caps |= Caps::eFloodfill; @@ -534,16 +536,16 @@ namespace data case CAPS_FLAG_LOW_BANDWIDTH2: case CAPS_FLAG_LOW_BANDWIDTH3: case CAPS_FLAG_LOW_BANDWIDTH4: - m_BandwidthCap = *cap; + m_BandwidthCap = cap; break; case CAPS_FLAG_HIGH_BANDWIDTH: m_Caps |= Caps::eHighBandwidth; - m_BandwidthCap = *cap; + m_BandwidthCap = cap; break; case CAPS_FLAG_EXTRA_BANDWIDTH1: case CAPS_FLAG_EXTRA_BANDWIDTH2: m_Caps |= Caps::eExtraBandwidth | Caps::eHighBandwidth; - m_BandwidthCap = *cap; + m_BandwidthCap = cap; break; case CAPS_FLAG_HIDDEN: m_Caps |= Caps::eHidden; @@ -565,22 +567,15 @@ namespace data break; default: ; } - cap++; } - } - - void RouterInfo::ExtractCaps (std::string_view value) - { - ExtractCaps (std::string (value).c_str ()); // TODO } - uint8_t RouterInfo::ExtractAddressCaps (const char * value) const + uint8_t RouterInfo::ExtractAddressCaps (std::string_view value) const { uint8_t caps = 0; - const char * cap = value; - while (*cap) + for (auto cap: value) { - switch (*cap) + switch (cap) { case CAPS_FLAG_V4: caps |= AddressCaps::eV4; @@ -596,14 +591,8 @@ namespace data break; default: ; } - cap++; } return caps; - } - - uint8_t RouterInfo::ExtractAddressCaps (std::string_view value) const - { - return ExtractAddressCaps (std::string (value).c_str ()); // TODO: } void RouterInfo::UpdateIntroducers (std::shared_ptr
    address, uint64_t ts) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 8134059a..387906ad 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -339,9 +339,7 @@ namespace data void ReadFromBuffer (bool verifySignature); std::string_view ExtractString (const uint8_t * buf, size_t len) const; std::tuple ExtractParam (const uint8_t * buf, size_t len) const; - void ExtractCaps (const char * value); void ExtractCaps (std::string_view value); - uint8_t ExtractAddressCaps (const char * value) const; uint8_t ExtractAddressCaps (std::string_view value) const; void UpdateIntroducers (std::shared_ptr
    address, uint64_t ts); template From aedf59d11ae73f71b9b263e176cb4c1108012f4e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 19 Feb 2025 13:38:47 -0500 Subject: [PATCH 379/527] fixed typo --- libi2pd/SSU2OutOfSession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index c4a6f9e4..88ee3e4d 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -257,7 +257,7 @@ namespace transport { // we are Charlie uint64_t destConnID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id - uint32_t sourceConnID = ~destConnID; + uint64_t sourceConnID = ~destConnID; SetSourceConnID (sourceConnID); SetDestConnID (destConnID); SetState (eSSU2SessionStateHolePunch); From b97f09cc9594959164ff97e59f9064a396f12db6 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 19 Feb 2025 18:51:54 -0500 Subject: [PATCH 380/527] const ExtractString and ExtractMapping --- libi2pd_client/I2CP.cpp | 4 ++-- libi2pd_client/I2CP.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index f6494a51..df93082b 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -571,7 +571,7 @@ namespace client m_IsSending = false; } - std::string_view I2CPSession::ExtractString (const uint8_t * buf, size_t len) + std::string_view I2CPSession::ExtractString (const uint8_t * buf, size_t len) const { uint8_t l = buf[0]; if (l > len) l = len; @@ -588,7 +588,7 @@ namespace client return l + 1; } - void I2CPSession::ExtractMapping (const uint8_t * buf, size_t len, std::map& mapping) + void I2CPSession::ExtractMapping (const uint8_t * buf, size_t len, std::map& mapping) const // TODO: move to Base.cpp { size_t offset = 0; diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 50b668d3..d3949eaa 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -194,9 +194,9 @@ namespace client void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); - std::string_view ExtractString (const uint8_t * buf, size_t len); + std::string_view ExtractString (const uint8_t * buf, size_t len) const; size_t PutString (uint8_t * buf, size_t len, std::string_view str); - void ExtractMapping (const uint8_t * buf, size_t len, std::map& mapping); + void ExtractMapping (const uint8_t * buf, size_t len, std::map& mapping) const; void SendSessionStatusMessage (I2CPSessionStatus status); void SendHostReplyMessage (uint32_t requestID, std::shared_ptr identity); From 7791b3952e4821cba9179879b0b92fc0c4d1816b Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 20 Feb 2025 16:53:49 -0500 Subject: [PATCH 381/527] check RelayRequest, RelayIntro, RelayResponse buffer size. Use assign instead memcpy --- libi2pd/SSU2OutOfSession.cpp | 10 --------- libi2pd/SSU2Session.cpp | 41 ++++++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index 88ee3e4d..3760e329 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -191,12 +191,7 @@ namespace transport void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, bool delayed) { -#if __cplusplus >= 202002L // C++20 m_SignedData.assign (signedData, signedData + signedDataLen); -#else - m_SignedData.resize (signedDataLen); - memcpy (m_SignedData.data (), signedData, signedDataLen); -#endif if (!delayed) SendPeerTest (msg); // schedule resend for msgs 5 or 6 @@ -313,12 +308,7 @@ namespace transport void SSU2HolePunchSession::SendHolePunch (const uint8_t * relayResponseBlock, size_t relayResponseBlockLen) { -#if __cplusplus >= 202002L // C++20 m_RelayResponseBlock.assign (relayResponseBlock, relayResponseBlock + relayResponseBlockLen); -#else - m_RelayResponseBlock.resize (relayResponseBlockLen); - memcpy (m_RelayResponseBlock.data (), relayResponseBlock, relayResponseBlockLen); -#endif SendHolePunch (); ScheduleResend (); } diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index b12222f2..199d60b0 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1965,6 +1965,7 @@ namespace transport void SSU2Session::HandleRelayRequest (const uint8_t * buf, size_t len) { // we are Bob + if (len < 9) return; auto mts = i2p::util::GetMillisecondsSinceEpoch (); uint32_t nonce = bufbe32toh (buf + 1); // nonce uint32_t relayTag = bufbe32toh (buf + 5); // relay tag @@ -1998,7 +1999,7 @@ namespace transport packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; if (!packet->payloadSize && r) session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); - packet->payloadSize += CreateRelayIntroBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, buf + 1, len -1); + packet->payloadSize += CreateRelayIntroBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, buf + 1, len - 1); if (packet->payloadSize < m_MaxPayloadSize) packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize); @@ -2013,6 +2014,7 @@ namespace transport void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len, int attempts) { // we are Charlie + if (len < 47) return; SSU2RelayResponseCode code = eSSU2RelayResponseCodeAccept; boost::asio::ip::udp::endpoint ep; std::shared_ptr addr; @@ -2025,6 +2027,11 @@ namespace transport s.Insert (i2p::context.GetIdentHash (), 32); // chash s.Insert (buf + 33, 14); // nonce, relay tag, timestamp, ver, asz uint8_t asz = buf[46]; + if (asz + 47 + r->GetIdentity ()->GetSignatureLen () > len) + { + LogPrint (eLogWarning, "SSU2: Malformed RelayIntro len=", len); + return; + } s.Insert (buf + 47, asz); // Alice Port, Alice IP if (s.Verify (r->GetIdentity (), buf + 47 + asz)) { @@ -2113,6 +2120,7 @@ namespace transport void SSU2Session::HandleRelayResponse (const uint8_t * buf, size_t len) { + if (len < 6) return; uint32_t nonce = bufbe32toh (buf + 2); if (m_State == eSSU2SessionStateIntroduced) { @@ -2133,7 +2141,9 @@ namespace transport auto it = m_RelaySessions.find (nonce); if (it != m_RelaySessions.end ()) { - if (it->second.first && it->second.first->IsEstablished ()) + auto relaySession = it->second.first; + m_RelaySessions.erase (it); + if (relaySession && relaySession->IsEstablished ()) { // we are Bob, message from Charlie auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); @@ -2143,12 +2153,12 @@ namespace transport memcpy (payload + 3, buf, len); // forward to Alice as is packet->payloadSize = len + 3; packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); - uint32_t packetNum = it->second.first->SendData (packet->payload, packet->payloadSize); + uint32_t packetNum = relaySession->SendData (packet->payload, packet->payloadSize); if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION) { // sometimes Alice doesn't ack this RelayResponse in older versions packet->sendTime = i2p::util::GetMillisecondsSinceEpoch (); - it->second.first->m_SentPackets.emplace (packetNum, packet); + relaySession->m_SentPackets.emplace (packetNum, packet); } } else @@ -2157,25 +2167,31 @@ namespace transport if (!buf[1]) // status code accepted? { // verify signature - uint8_t csz = buf[11]; + uint8_t csz = (len >= 12) ? buf[11] : 0; + if (csz + 12 + relaySession->GetRemoteIdentity ()->GetSignatureLen () > len) + { + LogPrint (eLogWarning, "SSU2: Malformed RelayResponse len=", len); + relaySession->Done (); + return; + } SignedData s; s.Insert ((const uint8_t *)"RelayAgreementOK", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash s.Insert (buf + 2, 10 + csz); // nonce, timestamp, ver, csz and Charlie's endpoint - if (s.Verify (it->second.first->GetRemoteIdentity (), buf + 12 + csz)) + if (s.Verify (relaySession->GetRemoteIdentity (), buf + 12 + csz)) { - if (it->second.first->m_State == eSSU2SessionStateIntroduced) // HolePunch not received yet + if (relaySession->m_State == eSSU2SessionStateIntroduced) // HolePunch not received yet { // update Charlie's endpoint - if (ExtractEndpoint (buf + 12, csz, it->second.first->m_RemoteEndpoint)) + if (ExtractEndpoint (buf + 12, csz, relaySession->m_RemoteEndpoint)) { // update token uint64_t token; memcpy (&token, buf + len - 8, 8); - m_Server.UpdateOutgoingToken (it->second.first->m_RemoteEndpoint, + m_Server.UpdateOutgoingToken (relaySession->m_RemoteEndpoint, token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT); // connect to Charlie, HolePunch will be ignored - it->second.first->ConnectAfterIntroduction (); + relaySession->ConnectAfterIntroduction (); } else LogPrint (eLogWarning, "SSU2: RelayResponse can't extract endpoint"); @@ -2184,16 +2200,15 @@ namespace transport else { LogPrint (eLogWarning, "SSU2: RelayResponse signature verification failed"); - it->second.first->Done (); + relaySession->Done (); } } else { LogPrint (eLogInfo, "SSU2: RelayResponse status code=", (int)buf[1], " nonce=", bufbe32toh (buf + 2)); - it->second.first->Done (); + relaySession->Done (); } } - m_RelaySessions.erase (it); } else LogPrint (eLogDebug, "SSU2: RelayResponse unknown nonce ", bufbe32toh (buf + 2)); From 9ba016259dbeb07f1a49496f3f8f5ac52e984ed6 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 20 Feb 2025 21:59:24 -0500 Subject: [PATCH 382/527] use plain buffer instead stream for SignedData --- libi2pd/SSU2Session.cpp | 14 +++++++------- libi2pd/TransportSession.h | 28 +++++++++++++++++----------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 199d60b0..0dda5739 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -189,7 +189,7 @@ namespace transport if (!asz) return false; payload[17] = asz; packet->payloadSize = asz + 18; - SignedData s; + SignedData<128> s; s.Insert ((const uint8_t *)"RelayRequestData", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash s.Insert (session->GetRemoteIdentity ()->GetIdentHash (), 32); // chash @@ -2021,7 +2021,7 @@ namespace transport auto r = i2p::data::netdb.FindRouter (buf + 1); // Alice if (r) { - SignedData s; + SignedData<128> s; s.Insert ((const uint8_t *)"RelayRequestData", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash s.Insert (i2p::context.GetIdentHash (), 32); // chash @@ -2174,7 +2174,7 @@ namespace transport relaySession->Done (); return; } - SignedData s; + SignedData<128> s; s.Insert ((const uint8_t *)"RelayAgreementOK", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash s.Insert (buf + 2, 10 + csz); // nonce, timestamp, ver, csz and Charlie's endpoint @@ -2280,7 +2280,7 @@ namespace transport uint8_t asz = buf[offset + 9]; std::vector newSignedData (asz + 10 + i2p::context.GetIdentity ()->GetSignatureLen ()); memcpy (newSignedData.data (), buf + offset, asz + 10); - SignedData s; + SignedData<128> s; s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash s.Insert (buf + 3, 32); // ahash @@ -2391,7 +2391,7 @@ namespace transport if (r) { uint8_t asz = buf[offset + 9]; - SignedData s; + SignedData<128> s; s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash s.Insert (i2p::context.GetIdentity ()->GetIdentHash (), 32); // ahash @@ -2879,7 +2879,7 @@ namespace transport LogPrint (eLogError, "SSU2: Buffer for RelayResponse signature is too small ", len); return 0; } - SignedData s; + SignedData<128> s; s.Insert ((const uint8_t *)"RelayAgreementOK", 16); // prologue if (code == eSSU2RelayResponseCodeAccept || code >= 64) // Charlie s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash @@ -2941,7 +2941,7 @@ namespace transport size_t asz = CreateEndpoint (signedData + 10, 86, boost::asio::ip::udp::endpoint (localAddress->host, localAddress->port)); signedData[9] = asz; // signature - SignedData s; + SignedData<128> s; s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash s.Insert (signedData, 10 + asz); // ver, nonce, ts, asz, Alice's endpoint diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index ef0044c0..b6be2433 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.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 * @@ -10,7 +10,7 @@ #define TRANSPORT_SESSION_H__ #include -#include +#include #include #include #include @@ -28,45 +28,51 @@ namespace transport const size_t IPV6_HEADER_SIZE = 40; const size_t UDP_HEADER_SIZE = 8; + template class SignedData { public: - SignedData () {} + SignedData (): m_Size(0) {} SignedData (const SignedData& other) { - m_Stream << other.m_Stream.rdbuf (); + m_Size = other.Size; + memcpy (m_Buf, other.m_Buf, m_Size); } void Reset () { - m_Stream.str(""); + m_Size = 0; } - void Insert (const uint8_t * buf, size_t len) + size_t Insert (const uint8_t * buf, size_t len) { - m_Stream.write ((char *)buf, len); + if (m_Size + len > sz) len = sz - m_Size; + memcpy (m_Buf + m_Size, buf, len); + m_Size += len; + return len; } template void Insert (T t) { - m_Stream.write ((char *)&t, sizeof (T)); + Insert ((const uint8_t *)&t, sizeof (T)); } bool Verify (std::shared_ptr ident, const uint8_t * signature) const { - return ident->Verify ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature); + return ident->Verify (m_Buf, m_Size, signature); } void Sign (const i2p::data::PrivateKeys& keys, uint8_t * signature) const { - keys.Sign ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature); + keys.Sign (m_Buf, m_Size, signature); } private: - std::stringstream m_Stream; + uint8_t m_Buf[sz]; + size_t m_Size; }; const int64_t TRANSPORT_SESSION_SLOWNESS_THRESHOLD = 500; // in milliseconds From 7e3d9649dea701d1d79b48009a07efba9d25b1a1 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 20 Feb 2025 22:04:58 -0500 Subject: [PATCH 383/527] use plain buffer instead stream for SignedData --- libi2pd/TransportSession.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index b6be2433..2cff0b1f 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -36,7 +36,7 @@ namespace transport SignedData (): m_Size(0) {} SignedData (const SignedData& other) { - m_Size = other.Size; + m_Size = other.m_Size; memcpy (m_Buf, other.m_Buf, m_Size); } From 81dae1997dfba8b594027bfbbeddc47871e2ecd1 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 21 Feb 2025 20:34:53 -0500 Subject: [PATCH 384/527] replace boost::lexical_cast by std::from_chars and std::to_string --- libi2pd/RouterInfo.cpp | 59 ++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index b741134e..f5ed27e6 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include // for boost::to_lower #ifndef __cpp_lib_atomic_shared_ptr #include @@ -263,27 +262,17 @@ namespace data } else if (key == "port") { - try - { - address->port = boost::lexical_cast(value); - } - catch (std::exception& ex) - { - LogPrint (eLogWarning, "RouterInfo: 'port' exception ", ex.what ()); - } + auto res = std::from_chars(value.data(), value.data() + value.size(), address->port); + if (res.ec != std::errc()) + LogPrint (eLogWarning, "RouterInfo: 'port' conversion error: ", std::make_error_code (res.ec).message ()); } else if (key == "mtu") { if (address->ssu) { - try - { - address->ssu->mtu = boost::lexical_cast(value); - } - catch (std::exception& ex) - { - LogPrint (eLogWarning, "RouterInfo: 'mtu' exception ", ex.what ()); - } + auto res = std::from_chars(value.data(), value.data() + value.size(), address->ssu->mtu); + if (res.ec != std::errc()) + LogPrint (eLogWarning, "RouterInfo: 'mtu' conversion error: ", std::make_error_code (res.ec).message ()); } else LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP2"); @@ -349,27 +338,17 @@ namespace data auto key1 = key.substr(0, key.length () - 1); if (key1 == "itag") { - try - { - introducer.iTag = boost::lexical_cast(value); - } - catch (std::exception& ex) - { - LogPrint (eLogWarning, "RouterInfo: 'itag' exception ", ex.what ()); - } + auto res = std::from_chars(value.data(), value.data() + value.size(), introducer.iTag); + if (res.ec != std::errc()) + LogPrint (eLogWarning, "RouterInfo: 'itag' conversion error: ", std::make_error_code (res.ec).message ()); } else if (key1 == "ih") Base64ToByteStream (value.data (), value.length (), introducer.iH, 32); else if (key1 == "iexp") { - try - { - introducer.iExp = boost::lexical_cast(value); - } - catch (std::exception& ex) - { - LogPrint (eLogWarning, "RouterInfo: 'iexp' exception ", ex.what ()); - } + auto res = std::from_chars(value.data(), value.data() + value.size(), introducer.iExp); + if (res.ec != std::errc()) + LogPrint (eLogWarning, "RouterInfo: 'iexp' conversion error: ", std::make_error_code (res.ec).message ()); } } } @@ -1402,9 +1381,9 @@ namespace data if (!introducer.iTag) continue; if (introducer.iExp) // expiration is specified { - WriteString ("iexp" + boost::lexical_cast(i), properties); + WriteString ("iexp" + std::to_string(i), properties); properties << '='; - WriteString (boost::lexical_cast(introducer.iExp), properties); + WriteString (std::to_string(introducer.iExp), properties); properties << ';'; } i++; @@ -1413,7 +1392,7 @@ namespace data for (const auto& introducer: address.ssu->introducers) { if (!introducer.iTag) continue; - WriteString ("ih" + boost::lexical_cast(i), properties); + WriteString ("ih" + std::to_string(i), properties); properties << '='; char value[64]; size_t l = ByteStreamToBase64 (introducer.iH, 32, value, 64); @@ -1426,9 +1405,9 @@ namespace data for (const auto& introducer: address.ssu->introducers) { if (!introducer.iTag) continue; - WriteString ("itag" + boost::lexical_cast(i), properties); + WriteString ("itag" + std::to_string(i), properties); properties << '='; - WriteString (boost::lexical_cast(introducer.iTag), properties); + WriteString (std::to_string(introducer.iTag), properties); properties << ';'; i++; } @@ -1442,7 +1421,7 @@ namespace data { WriteString ("mtu", properties); properties << '='; - WriteString (boost::lexical_cast(address.ssu->mtu), properties); + WriteString (std::to_string(address.ssu->mtu), properties); properties << ';'; } } @@ -1450,7 +1429,7 @@ namespace data { WriteString ("port", properties); properties << '='; - WriteString (boost::lexical_cast(address.port), properties); + WriteString (std::to_string(address.port), properties); properties << ';'; } if (address.IsNTCP2 () || address.IsSSU2 ()) From bf050ac465ab2780f96c1aff3b557ad188b449ec Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 22 Feb 2025 19:01:20 -0500 Subject: [PATCH 385/527] fixed typo --- libi2pd/Streaming.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index dfe2ff6a..2b274e31 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -613,10 +613,8 @@ namespace stream if (wasInitial) ScheduleResend (); } - if (m_IsClientChoked && ackThrough > m_DropWindowDelaySequenceNumber) - { + if (m_IsClientChoked && ackThrough >= m_DropWindowDelaySequenceNumber) m_IsClientChoked = false; - } if (m_IsWinDropped && ackThrough > m_DropWindowDelaySequenceNumber) { m_IsFirstRttSample = true; From 9432202fad37246353611296c433b2a400fe0f36 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 24 Feb 2025 13:58:10 -0500 Subject: [PATCH 386/527] check PeerTest buffer size --- libi2pd/SSU2Session.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 0dda5739..e0a9a48f 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2277,8 +2277,11 @@ namespace transport case 2: // Charlie from Bob { // sign with Charlie's key + if (len < offset + 9) return; uint8_t asz = buf[offset + 9]; - std::vector newSignedData (asz + 10 + i2p::context.GetIdentity ()->GetSignatureLen ()); + size_t l = asz + 10 + i2p::context.GetIdentity ()->GetSignatureLen (); + if (len < offset + l) return; + std::vector newSignedData (l); memcpy (newSignedData.data (), buf + offset, asz + 10); SignedData<128> s; s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue @@ -2388,9 +2391,15 @@ namespace transport if (GetRouterStatus () == eRouterStatusUnknown) SetTestingState (true); auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie - if (r) + if (r && len >= offset + 9) { uint8_t asz = buf[offset + 9]; + if (len < offset + asz + 10 + r->GetIdentity ()->GetSignatureLen ()) + { + LogPrint (eLogWarning, "Malformed PeerTest 4 len=", len); + session->Done (); + return; + } SignedData<128> s; s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash From dcd15cc2449d6320de6351054e61ef2ee7ebee40 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 25 Feb 2025 14:12:10 -0500 Subject: [PATCH 387/527] use common constants for babdwidth limits --- libi2pd/RouterContext.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 8d2dd922..6819a185 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -675,12 +675,12 @@ namespace i2p void RouterContext::SetBandwidth (int limit) { - if (limit > 2000) { SetBandwidth('X'); } - else if (limit > 256) { SetBandwidth('P'); } - else if (limit > 128) { SetBandwidth('O'); } - else if (limit > 64) { SetBandwidth('N'); } - else if (limit > 48) { SetBandwidth('M'); } - else if (limit > 12) { SetBandwidth('L'); } + if (limit > (int)i2p::data::EXTRA_BANDWIDTH_LIMIT) { SetBandwidth('X'); } + else if (limit > (int)i2p::data::HIGH_BANDWIDTH_LIMIT) { SetBandwidth('P'); } + else if (limit > 128) { SetBandwidth('O'); } + else if (limit > 64) { SetBandwidth('N'); } + else if (limit > (int)i2p::data::LOW_BANDWIDTH_LIMIT) { SetBandwidth('M'); } + else if (limit > 12) { SetBandwidth('L'); } else { SetBandwidth('K'); } m_BandwidthLimit = limit; // set precise limit } From 2a4403f1e008228591b7bbdc5ae24dd110e04e17 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 27 Feb 2025 18:00:24 -0500 Subject: [PATCH 388/527] lazy creation of TunnelEnpoint for transit tunnel --- libi2pd/TransitTunnel.cpp | 22 +++++++++++++++------- libi2pd/TransitTunnel.h | 7 +++---- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index 57fd8513..b24c8ac5 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -131,27 +131,35 @@ namespace tunnel LogPrint (eLogDebug, "TransitTunnel: handle msg for endpoint ", GetTunnelID ()); std::lock_guard l(m_HandleMutex); - m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg); + if (!m_Endpoint) m_Endpoint = std::make_unique(false); // transit endpoint is always outbound + m_Endpoint->HandleDecryptedTunnelDataMsg (newMsg); } void TransitTunnelEndpoint::FlushTunnelDataMsgs () { - std::lock_guard l(m_HandleMutex); - m_Endpoint.FlushI2NPMsgs (); + if (m_Endpoint) + { + std::lock_guard l(m_HandleMutex); + m_Endpoint->FlushI2NPMsgs (); + } } void TransitTunnelEndpoint::Cleanup () { - std::lock_guard l(m_HandleMutex); - m_Endpoint.Cleanup (); + if (m_Endpoint) + { + std::lock_guard l(m_HandleMutex); + m_Endpoint->Cleanup (); + } } std::string TransitTunnelEndpoint::GetNextPeerName () const { - auto hash = m_Endpoint.GetCurrentHash (); + if (!m_Endpoint) return ""; + auto hash = m_Endpoint->GetCurrentHash (); if (hash) { - const auto& sender = m_Endpoint.GetSender (); + const auto& sender = m_Endpoint->GetSender (); if (sender) { auto transport = sender->GetCurrentTransport (); diff --git a/libi2pd/TransitTunnel.h b/libi2pd/TransitTunnel.h index 46d09b1a..34bcc79f 100644 --- a/libi2pd/TransitTunnel.h +++ b/libi2pd/TransitTunnel.h @@ -97,20 +97,19 @@ namespace tunnel TransitTunnelEndpoint (uint32_t receiveTunnelID, const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID, const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey): - TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey), - m_Endpoint (false) {}; // transit endpoint is always outbound + TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey) {}; void Cleanup () override; void HandleTunnelDataMsg (std::shared_ptr&& tunnelMsg) override; void FlushTunnelDataMsgs () override; - size_t GetNumTransmittedBytes () const override { return m_Endpoint.GetNumReceivedBytes (); } + size_t GetNumTransmittedBytes () const override { return m_Endpoint ? m_Endpoint->GetNumReceivedBytes () : 0; } std::string GetNextPeerName () const override; private: std::mutex m_HandleMutex; - TunnelEndpoint m_Endpoint; + std::unique_ptr m_Endpoint; }; std::shared_ptr CreateTransitTunnel (uint32_t receiveTunnelID, From 539e7e988e643839bc5bee0754b6fbc8f7b6423e Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 27 Feb 2025 21:35:14 -0500 Subject: [PATCH 389/527] reduce I2PTunnelConnection buffer size --- libi2pd_client/I2PTunnel.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index aa53f0b6..72602007 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.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 * @@ -27,7 +27,7 @@ namespace i2p { namespace client { - const size_t I2P_TUNNEL_CONNECTION_BUFFER_SIZE = 65536; + const size_t I2P_TUNNEL_CONNECTION_BUFFER_SIZE = 16384; const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds // for HTTP tunnels From 5f762845f05dfc0081b94288bc64c9d3c99c2f00 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 28 Feb 2025 22:20:50 -0500 Subject: [PATCH 390/527] move BOB incoming connection logic from I2PTunnelConnection to BOB --- libi2pd_client/BOB.cpp | 22 ++++++++++++++++++++-- libi2pd_client/BOB.h | 19 ++++++++++++++++++- libi2pd_client/I2PTunnel.cpp | 31 +++++++++---------------------- libi2pd_client/I2PTunnel.h | 21 +++++++++++---------- 4 files changed, 58 insertions(+), 35 deletions(-) diff --git a/libi2pd_client/BOB.cpp b/libi2pd_client/BOB.cpp index f2dab223..8d94e94b 100644 --- a/libi2pd_client/BOB.cpp +++ b/libi2pd_client/BOB.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 * @@ -16,6 +16,24 @@ namespace i2p { namespace client { + void BOBI2PTunnelIncomingConnection::Established () + { + if (m_IsQuiet) + StreamReceive (); + else + { + // send destination first like received from I2P + std::string dest = GetStream ()->GetRemoteIdentity ()->ToBase64 (); + dest += "\n"; + if (dest.size() <= I2P_TUNNEL_CONNECTION_BUFFER_SIZE) + memcpy (GetStreamBuffer (), dest.c_str (), dest.size ()); + else + memset (GetStreamBuffer (), 0, I2P_TUNNEL_CONNECTION_BUFFER_SIZE); + HandleStreamReceive (boost::system::error_code (), dest.size ()); + } + Receive (); + } + BOBI2PInboundTunnel::BOBI2PInboundTunnel (const boost::asio::ip::tcp::endpoint& ep, std::shared_ptr localDestination): BOBI2PTunnel (localDestination), m_Acceptor (localDestination->GetService (), ep) { @@ -156,7 +174,7 @@ namespace client { if (stream) { - auto conn = std::make_shared (this, stream, m_Endpoint, m_IsQuiet); + auto conn = std::make_shared (this, stream, m_Endpoint, m_IsQuiet); AddHandler (conn); conn->Connect (); } diff --git a/libi2pd_client/BOB.h b/libi2pd_client/BOB.h index 79066154..f5aefd0a 100644 --- a/libi2pd_client/BOB.h +++ b/libi2pd_client/BOB.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 * @@ -71,6 +71,23 @@ namespace client const char BOB_HELP_STATUS[] = "status - Display status of a nicknamed tunnel."; const char BOB_HELP_HELP [] = "help - Get help on a command."; + class BOBI2PTunnelIncomingConnection: public I2PTunnelConnection + { + public: + + BOBI2PTunnelIncomingConnection (I2PService * owner, std::shared_ptr stream, + const boost::asio::ip::tcp::endpoint& target, bool quiet): + I2PTunnelConnection (owner, stream, target), m_IsQuiet (quiet) {}; + + protected: + + void Established () override; + + private: + + bool m_IsQuiet; // don't send destination + }; + class BOBI2PTunnel: public I2PService { public: diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 3a3c491e..6d45c10c 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.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 * @@ -32,8 +32,7 @@ namespace client I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, std::shared_ptr leaseSet, uint16_t port): - I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()), - m_IsQuiet (true) + I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()) { m_Stream = GetOwner()->GetLocalDestination ()->CreateStream (leaseSet, port); } @@ -41,14 +40,13 @@ namespace client I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, std::shared_ptr stream): I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream), - m_RemoteEndpoint (socket->remote_endpoint ()), m_IsQuiet (true) + m_RemoteEndpoint (socket->remote_endpoint ()) { } I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr stream, - const boost::asio::ip::tcp::endpoint& target, bool quiet, - std::shared_ptr sslCtx): - I2PServiceHandler(owner), m_Stream (stream), m_RemoteEndpoint (target), m_IsQuiet (quiet) + const boost::asio::ip::tcp::endpoint& target,std::shared_ptr sslCtx): + I2PServiceHandler(owner), m_Stream (stream), m_RemoteEndpoint (target) { m_Socket = std::make_shared (owner->GetService ()); if (sslCtx) @@ -292,18 +290,7 @@ namespace client void I2PTunnelConnection::Established () { - if (m_IsQuiet) - StreamReceive (); - else - { - // send destination first like received from I2P - std::string dest = m_Stream->GetRemoteIdentity ()->ToBase64 (); - dest += "\n"; - if(sizeof(m_StreamBuffer) >= dest.size()) { - memcpy (m_StreamBuffer, dest.c_str (), dest.size ()); - } - HandleStreamReceive (boost::system::error_code (), dest.size ()); - } + StreamReceive (); Receive (); } @@ -377,7 +364,7 @@ namespace client I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr stream, const boost::asio::ip::tcp::endpoint& target, const std::string& host, const std::string& XI2P, std::shared_ptr sslCtx): - I2PTunnelConnection (owner, stream, target, true, sslCtx), m_Host (host), m_XI2P (XI2P), + I2PTunnelConnection (owner, stream, target, sslCtx), m_Host (host), m_XI2P (XI2P), m_HeaderSent (false), m_ResponseHeaderSent (false) { if (sslCtx) @@ -528,7 +515,7 @@ namespace client I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr stream, const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass, std::shared_ptr sslCtx): - I2PTunnelConnection (owner, stream, target, true, sslCtx), m_From (stream->GetRemoteIdentity ()), + I2PTunnelConnection (owner, stream, target, sslCtx), m_From (stream->GetRemoteIdentity ()), m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass) { } @@ -857,7 +844,7 @@ namespace client std::shared_ptr I2PServerTunnel::CreateI2PConnection (std::shared_ptr stream) { - return std::make_shared (this, stream, GetEndpoint (), true, m_SSLCtx); + return std::make_shared (this, stream, GetEndpoint (), m_SSLCtx); } diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index 72602007..7d4c3400 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -45,7 +45,7 @@ namespace client I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, std::shared_ptr stream); // to I2P using simplified API I2PTunnelConnection (I2PService * owner, std::shared_ptr stream, - const boost::asio::ip::tcp::endpoint& target, bool quiet = true, + const boost::asio::ip::tcp::endpoint& target, std::shared_ptr sslCtx = nullptr); // from I2P ~I2PTunnelConnection (); void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0); @@ -54,25 +54,27 @@ namespace client protected: + virtual void Established (); void Terminate (); void Receive (); void StreamReceive (); + void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); virtual void Write (const uint8_t * buf, size_t len); // can be overloaded virtual void WriteToStream (const uint8_t * buf, size_t len); // can be overloaded std::shared_ptr GetSocket () const { return m_Socket; }; + std::shared_ptr GetStream () const { return m_Stream; }; std::shared_ptr > GetSSL () const { return m_SSL; }; - + uint8_t * GetStreamBuffer () { return m_StreamBuffer; }; + private: void HandleConnect (const boost::system::error_code& ecode); void HandleHandshake (const boost::system::error_code& ecode); - void Established (); void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleWrite (const boost::system::error_code& ecode); - void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); - + private: uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE]; @@ -80,7 +82,6 @@ namespace client std::shared_ptr > m_SSL; std::shared_ptr m_Stream; boost::asio::ip::tcp::endpoint m_RemoteEndpoint; - bool m_IsQuiet; // don't send destination }; class I2PClientTunnelConnectionHTTP: public I2PTunnelConnection @@ -94,7 +95,7 @@ namespace client protected: - void Write (const uint8_t * buf, size_t len); + void Write (const uint8_t * buf, size_t len) override; private: @@ -112,8 +113,8 @@ namespace client protected: - void Write (const uint8_t * buf, size_t len); - void WriteToStream (const uint8_t * buf, size_t len); + void Write (const uint8_t * buf, size_t len) override; + void WriteToStream (const uint8_t * buf, size_t len) override; private: @@ -132,7 +133,7 @@ namespace client protected: - void Write (const uint8_t * buf, size_t len); + void Write (const uint8_t * buf, size_t len) override; private: From a1794ccd2283c38cb6f87c6576ee03da66c95e62 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 2 Mar 2025 15:00:09 -0500 Subject: [PATCH 391/527] Solaris build added --- Makefile | 3 +++ Makefile.solaris | 9 +++++++++ 2 files changed, 12 insertions(+) create mode 100644 Makefile.solaris diff --git a/Makefile b/Makefile index 016dec97..0d4ca48c 100644 --- a/Makefile +++ b/Makefile @@ -69,6 +69,9 @@ else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS))) else ifneq (, $(findstring haiku, $(SYS))) DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp include Makefile.haiku +else ifneq (, $(findstring solaris, $(SYS))) + DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp + include Makefile.solaris else # not supported $(error Not supported platform) endif diff --git a/Makefile.solaris b/Makefile.solaris new file mode 100644 index 00000000..77d34114 --- /dev/null +++ b/Makefile.solaris @@ -0,0 +1,9 @@ +CXX = g++ +INCFLAGS = -I/usr/openssl/3/include +CXXFLAGS := -Wall -std=c++20 +LDLIBS = -L/usr/openssl/3/lib/64 -lssl -lcrypto -lboost_program_options -lz -lpthread -lsocket + +ifeq ($(USE_UPNP),yes) + DEFINES += -DUSE_UPNP + LDLIBS += -lminiupnpc +endif \ No newline at end of file From 4f82fe24da860d53e0c608c266279dfa2b093fc1 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 4 Mar 2025 18:11:58 -0500 Subject: [PATCH 392/527] replace boost::lexical_cast by std::to_string. std::unique_ptr for thread --- daemon/I2PControl.cpp | 10 ++++------ daemon/I2PControl.h | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 1ea75bbb..6d08404f 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.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,7 +15,6 @@ // Use global placeholders from boost introduced when local_time.hpp is loaded #define BOOST_BIND_GLOBAL_PLACEHOLDERS #include -#include #include "FS.h" #include "Log.h" @@ -30,7 +29,7 @@ namespace i2p namespace client { I2PControlService::I2PControlService (const std::string& address, int port): - m_IsRunning (false), m_Thread (nullptr), + m_IsRunning (false), m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(address), port)), m_SSLContext (boost::asio::ssl::context::sslv23), m_ShutdownTimer (m_Service) @@ -98,7 +97,7 @@ namespace client { Accept (); m_IsRunning = true; - m_Thread = new std::thread (std::bind (&I2PControlService::Run, this)); + m_Thread = std::make_unique(std::bind (&I2PControlService::Run, this)); } } @@ -112,7 +111,6 @@ namespace client if (m_Thread) { m_Thread->join (); - delete m_Thread; m_Thread = nullptr; } } @@ -267,7 +265,7 @@ namespace client std::ostringstream header; header << "HTTP/1.1 200 OK\r\n"; header << "Connection: close\r\n"; - header << "Content-Length: " << boost::lexical_cast(len) << "\r\n"; + header << "Content-Length: " << std::to_string(len) << "\r\n"; header << "Content-Type: application/json\r\n"; header << "Date: "; std::time_t t = std::time (nullptr); diff --git a/daemon/I2PControl.h b/daemon/I2PControl.h index ff32c131..ccb678ef 100644 --- a/daemon/I2PControl.h +++ b/daemon/I2PControl.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 * @@ -86,7 +86,7 @@ namespace client std::string m_Password; bool m_IsRunning; - std::thread * m_Thread; + std::unique_ptr m_Thread; boost::asio::io_context m_Service; boost::asio::ip::tcp::acceptor m_Acceptor; From c816d3e4cc37ca698fd69bb22cfe5dd8d590a575 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 5 Mar 2025 10:38:23 -0500 Subject: [PATCH 393/527] Ed25519ph --- libi2pd/Signature.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++- libi2pd/Signature.h | 34 +++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index 342b6d03..d9fa0248 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2023, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -149,5 +149,56 @@ namespace crypto LogPrint (eLogError, "EdDSA signing key is not set"); } #endif + +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) + static const OSSL_PARAM EDDSA25519phParams[] = + { + OSSL_PARAM_utf8_string ("instance", (char *)"Ed25519ph", 9), + OSSL_PARAM_END + }; + + bool EDDSA25519phVerifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const + { + auto pkey = GetPkey (); + if (pkey) + { + uint8_t digest[64]; + SHA512 (buf, len, digest); + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestVerifyInit_ex (ctx, NULL, NULL, NULL, NULL, pkey, EDDSA25519phParams); + auto ret = EVP_DigestVerify (ctx, signature, 64, digest, 64); + EVP_MD_CTX_destroy (ctx); + return ret; + } + else + LogPrint (eLogError, "EdDSA verification key is not set"); + return false; + } + + EDDSA25519phSigner::EDDSA25519phSigner (const uint8_t * signingPrivateKey): + EDDSA25519Signer (signingPrivateKey) + { + } + + void EDDSA25519phSigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const + { + auto pkey = GetPkey (); + if (pkey) + { + uint8_t digest[64]; + SHA512 (buf, len, digest); + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + size_t l = 64; + uint8_t sig[64]; + EVP_DigestSignInit_ex (ctx, NULL, NULL, NULL, NULL, pkey, EDDSA25519phParams); + if (!EVP_DigestSign (ctx, sig, &l, digest, 64)) + LogPrint (eLogError, "EdDSA signing failed"); + memcpy (signature, sig, 64); + EVP_MD_CTX_destroy (ctx); + } + else + LogPrint (eLogError, "EdDSA signing key is not set"); + } +#endif } } diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index 8bd94357..2a731703 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2023, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -303,14 +303,28 @@ namespace crypto private: -#if OPENSSL_EDDSA +#if OPENSSL_EDDSA + EVP_PKEY * m_Pkey; + + protected: + + EVP_PKEY * GetPkey () const { return m_Pkey; }; #else EDDSAPoint m_PublicKey; uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; #endif }; +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + class EDDSA25519phVerifier: public EDDSA25519Verifier + { + public: + + bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; + }; +#endif + class EDDSA25519SignerCompat: public Signer { public: @@ -339,6 +353,10 @@ namespace crypto void Sign (const uint8_t * buf, int len, uint8_t * signature) const; + protected: + + EVP_PKEY * GetPkey () const { return m_Pkey; }; + private: EVP_PKEY * m_Pkey; @@ -350,6 +368,18 @@ namespace crypto #endif +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + class EDDSA25519phSigner: public EDDSA25519Signer + { + public: + + EDDSA25519phSigner (const uint8_t * signingPrivateKey); + + void Sign (const uint8_t * buf, int len, uint8_t * signature) const; + }; + +#endif + inline void CreateEDDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) { #if OPENSSL_EDDSA From 9c97909e044c4bd3d024d0ade611eb1221328056 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 5 Mar 2025 10:51:21 -0500 Subject: [PATCH 394/527] removed test crypto/signature types --- libi2pd/Identity.cpp | 12 ------------ libi2pd/Identity.h | 6 ++---- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index b58d18b6..285bde54 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -399,12 +399,8 @@ namespace data return std::make_shared(key); break; case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: - case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST: return std::make_shared(key); break; - case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC: - return std::make_shared(key); - break; default: LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)keyType); }; @@ -673,12 +669,8 @@ namespace data return std::make_shared(key); break; case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: - case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST: return std::make_shared(key); break; - case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC: - return std::make_shared(key); - break; default: LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType); }; @@ -753,12 +745,8 @@ namespace data i2p::crypto::GenerateElGamalKeyPair(priv, pub); break; case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: - case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST: i2p::crypto::CreateECIESP256RandomKeys (priv, pub); break; - case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC: - i2p::crypto::CreateECIESGOSTR3410RandomKeys (priv, pub); - break; case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: i2p::crypto::CreateECIESX25519AEADRatchetRandomKeys (priv, pub); break; diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index 73c77675..b5083e7e 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -64,9 +64,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_P256_SHA256_AES256CBC_TEST = 65280; // TODO: remove later - const uint16_t CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC = 65281; // TODO: use GOST R 34.11 instead SHA256 and GOST 28147-89 instead AES - + const uint16_t SIGNING_KEY_TYPE_DSA_SHA1 = 0; const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA256_P256 = 1; const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA384_P384 = 2; @@ -75,7 +73,7 @@ namespace data const uint16_t SIGNING_KEY_TYPE_RSA_SHA384_3072 = 5; const uint16_t SIGNING_KEY_TYPE_RSA_SHA512_4096 = 6; const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 = 7; - const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519ph = 8; // not implemented + const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519ph = 8; // since openssl 3.0.0 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 From c113241ccde1658821a6425b90a47f40ad5e6016 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 5 Mar 2025 14:14:34 -0500 Subject: [PATCH 395/527] support local sockets for I2PControl --- daemon/I2PControl.cpp | 110 ++++++++++++++++++++++++++++-------------- daemon/I2PControl.h | 17 ++++--- 2 files changed, 85 insertions(+), 42 deletions(-) diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 6d08404f..6261a14c 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -29,11 +29,24 @@ namespace i2p namespace client { I2PControlService::I2PControlService (const std::string& address, int port): - m_IsRunning (false), - m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(address), port)), + m_IsRunning (false), m_SSLContext (boost::asio::ssl::context::sslv23), m_ShutdownTimer (m_Service) { + if (port) + m_Acceptor = std::make_unique(m_Service, + boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(address), port)); + else +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + { + std::remove (address.c_str ()); // just in case + m_LocalAcceptor = std::make_unique(m_Service, + boost::asio::local::stream_protocol::endpoint(address)); + } +#else + LogPrint(eLogError, "I2PControl: Local sockets are not supported"); +#endif + i2p::config::GetOption("i2pcontrol.password", m_Password); // certificate / keys @@ -106,7 +119,15 @@ namespace client if (m_IsRunning) { m_IsRunning = false; - m_Acceptor.cancel (); + if (m_Acceptor) m_Acceptor->cancel (); +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + if (m_LocalAcceptor) + { + auto path = m_LocalAcceptor->local_endpoint().path(); + m_LocalAcceptor->cancel (); + std::remove (path.c_str ()); + } +#endif m_Service.stop (); if (m_Thread) { @@ -132,40 +153,60 @@ namespace client void I2PControlService::Accept () { - auto newSocket = std::make_shared (m_Service, m_SSLContext); - m_Acceptor.async_accept (newSocket->lowest_layer(), std::bind (&I2PControlService::HandleAccept, this, - std::placeholders::_1, newSocket)); + if (m_Acceptor) + { + auto newSocket = std::make_shared > (m_Service, m_SSLContext); + m_Acceptor->async_accept (newSocket->lowest_layer(), + [this, newSocket](const boost::system::error_code& ecode) + { + HandleAccepted (ecode, newSocket); + }); + } +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + else if (m_LocalAcceptor) + { + auto newSocket = std::make_shared > (m_Service, m_SSLContext); + m_LocalAcceptor->async_accept (newSocket->lowest_layer(), + [this, newSocket](const boost::system::error_code& ecode) + { + HandleAccepted (ecode, newSocket); + }); + } +#endif } - void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket) + template + void I2PControlService::HandleAccepted (const boost::system::error_code& ecode, + std::shared_ptr newSocket) { if (ecode != boost::asio::error::operation_aborted) Accept (); - if (ecode) { + if (ecode) + { LogPrint (eLogError, "I2PControl: Accept error: ", ecode.message ()); return; } - LogPrint (eLogDebug, "I2PControl: New request from ", socket->lowest_layer ().remote_endpoint ()); - Handshake (socket); - } - + LogPrint (eLogDebug, "I2PControl: New request from ", newSocket->lowest_layer ().remote_endpoint ()); + Handshake (newSocket); + } + + template void I2PControlService::Handshake (std::shared_ptr socket) { socket->async_handshake(boost::asio::ssl::stream_base::server, - std::bind( &I2PControlService::HandleHandshake, this, std::placeholders::_1, socket)); - } - - void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr socket) - { - if (ecode) { - LogPrint (eLogError, "I2PControl: Handshake error: ", ecode.message ()); - return; - } - //std::this_thread::sleep_for (std::chrono::milliseconds(5)); - ReadRequest (socket); + [this, socket](const boost::system::error_code& ecode) + { + if (ecode) + { + LogPrint (eLogError, "I2PControl: Handshake error: ", ecode.message ()); + return; + } + ReadRequest (socket); + }); } + template void I2PControlService::ReadRequest (std::shared_ptr socket) { auto request = std::make_shared(); @@ -175,10 +216,13 @@ namespace client #else boost::asio::buffer (request->data (), request->size ()), #endif - std::bind(&I2PControlService::HandleRequestReceived, this, - std::placeholders::_1, std::placeholders::_2, socket, request)); + [this, socket, request](const boost::system::error_code& ecode, size_t bytes_transferred) + { + HandleRequestReceived (ecode, bytes_transferred, socket, request); + }); } + template void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred, std::shared_ptr socket, std::shared_ptr buf) @@ -256,6 +300,7 @@ namespace client } } + template void I2PControlService::SendResponse (std::shared_ptr socket, std::shared_ptr buf, std::ostringstream& response, bool isHtml) { @@ -278,16 +323,11 @@ namespace client memcpy (buf->data () + offset, response.str ().c_str (), len); boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), offset + len), boost::asio::transfer_all (), - std::bind(&I2PControlService::HandleResponseSent, this, - std::placeholders::_1, std::placeholders::_2, socket, buf)); - } - - void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, - std::shared_ptr socket, std::shared_ptr buf) - { - if (ecode) { - LogPrint (eLogError, "I2PControl: Write error: ", ecode.message ()); - } + [socket, buf](const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) + LogPrint (eLogError, "I2PControl: Write error: ", ecode.message ()); + }); } // handlers diff --git a/daemon/I2PControl.h b/daemon/I2PControl.h index ccb678ef..83dd6549 100644 --- a/daemon/I2PControl.h +++ b/daemon/I2PControl.h @@ -35,8 +35,6 @@ namespace client class I2PControlService: public I2PControlHandlers { - typedef boost::asio::ssl::stream ssl_socket; - public: I2PControlService (const std::string& address, int port); @@ -49,16 +47,18 @@ namespace client void Run (); void Accept (); - void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); + template + void HandleAccepted (const boost::system::error_code& ecode, std::shared_ptr newSocket); + template void Handshake (std::shared_ptr socket); - void HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr socket); + template void ReadRequest (std::shared_ptr socket); + template void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred, std::shared_ptr socket, std::shared_ptr buf); + template void SendResponse (std::shared_ptr socket, std::shared_ptr buf, std::ostringstream& response, bool isHtml); - void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, - std::shared_ptr socket, std::shared_ptr buf); void CreateCertificate (const char *crt_path, const char *key_path); @@ -89,7 +89,10 @@ namespace client std::unique_ptr m_Thread; boost::asio::io_context m_Service; - boost::asio::ip::tcp::acceptor m_Acceptor; + std::unique_ptr m_Acceptor; +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + std::unique_ptr m_LocalAcceptor; +#endif boost::asio::ssl::context m_SSLContext; boost::asio::deadline_timer m_ShutdownTimer; std::set m_Tokens; From 66a52a17c623bc8a0ccf4c9b5992abbc9d3dc6e7 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 6 Mar 2025 16:26:02 -0500 Subject: [PATCH 396/527] load profile for SSU2 priority only --- libi2pd/Transports.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index db2af5da..b21426d1 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -680,8 +680,21 @@ namespace transport auto directTransports = compatibleTransports & peer->router->GetPublishedTransports (); peer->numAttempts = 0; peer->priority.clear (); - bool isReal = peer->router->GetProfile ()->IsReal (); - bool ssu2 = isReal ? (m_Rng () & 1) : false; // try NTCP2 if router is not confirmed real + + std::shared_ptr profile; + if (peer->router->HasProfile ()) profile = peer->router->GetProfile (); // only if in memory + bool ssu2 = false; // NTCP2 by default + bool isReal = profile ? profile->IsReal () : true; + if (isReal) + { + ssu2 = m_Rng () & 1; // 1/2 + if (ssu2 && !profile) + { + profile = peer->router->GetProfile (); // load profile if necessary + isReal = profile->IsReal (); + if (!isReal) ssu2 = false; // try NTCP2 if router is not confirmed real + } + } const auto& priority = ssu2 ? ssu2Priority : ntcp2Priority; if (directTransports) { From fe3e7b1f6e73f9f8bfabd04ebf5e554c06eb460c Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 6 Mar 2025 16:29:14 -0500 Subject: [PATCH 397/527] reduced profile persist interval --- libi2pd/Profiling.cpp | 2 +- libi2pd/Profiling.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/Profiling.cpp b/libi2pd/Profiling.cpp index bb40ae41..fe7f9905 100644 --- a/libi2pd/Profiling.cpp +++ b/libi2pd/Profiling.cpp @@ -310,7 +310,7 @@ namespace data { if (it->second->IsUpdated () && ts > it->second->GetLastPersistTime () + PEER_PROFILE_PERSIST_INTERVAL) { - tmp.push_back (std::make_pair (it->first, it->second)); + tmp.push_back (*it); it->second->SetLastPersistTime (ts); it->second->SetUpdated (false); } diff --git a/libi2pd/Profiling.h b/libi2pd/Profiling.h index 32d760a6..59995b3f 100644 --- a/libi2pd/Profiling.h +++ b/libi2pd/Profiling.h @@ -41,7 +41,7 @@ namespace data const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE = 2400; // in seconds (40 minutes) const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 330; // in seconds (5.5 minutes) const int PEER_PROFILE_MAX_DECLINED_INTERVAL = 4400; // in second (1.5 hours) - const int PEER_PROFILE_PERSIST_INTERVAL = 3300; // in seconds (55 minutes) + const int PEER_PROFILE_PERSIST_INTERVAL = 1320; // in seconds (22 minutes) const int PEER_PROFILE_UNREACHABLE_INTERVAL = 480; // in seconds (8 minutes) const int PEER_PROFILE_USEFUL_THRESHOLD = 3; const int PEER_PROFILE_ALWAYS_DECLINING_NUM = 5; // num declines in row to consider always declined From b500374f745a9a6382650aeb8c51287d79c1fb29 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 7 Mar 2025 13:33:17 -0500 Subject: [PATCH 398/527] recognize keys=shareddest --- libi2pd_client/ClientContext.cpp | 63 +++++++++++++++++++++----------- libi2pd_client/ClientContext.h | 4 +- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index f103636e..aa322296 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -265,11 +265,15 @@ namespace client } } - bool ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, + bool ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, std::string_view filename, i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType) { - static const std::string transient("transient"); +#if __cplusplus >= 202002L // C++20 + if (filename.starts_with ("transient")) +#else + std::string_view transient("transient"); if (!filename.compare (0, transient.length (), transient)) // starts with transient +#endif { keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true); LogPrint (eLogInfo, "Clients: New transient keys address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created"); @@ -599,7 +603,9 @@ namespace client options[I2CP_PARAM_OUTBOUND_NICKNAME] = name; std::shared_ptr localDestination = nullptr; - if (keys.length () > 0) + if (keys == "shareddest") + localDestination = m_SharedLocalDestination; + else if (keys.length () > 0) { auto it = destinations.find (keys); if (it != destinations.end ()) @@ -758,26 +764,31 @@ namespace client options[I2CP_PARAM_INBOUND_NICKNAME] = name; std::shared_ptr localDestination = nullptr; - auto it = destinations.find (keys); - if (it != destinations.end ()) - { - localDestination = it->second; - localDestination->SetPublic (true); - } + if (keys == "shareddest") + localDestination = m_SharedLocalDestination; else - { - i2p::data::PrivateKeys k; - if(!LoadPrivateKeys (k, keys, sigType, cryptoType)) - continue; - localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ()); - if (!localDestination) + { + auto it = destinations.find (keys); + if (it != destinations.end ()) { - localDestination = CreateNewLocalDestination (k, true, &options); - destinations[keys] = localDestination; + localDestination = it->second; + localDestination->SetPublic (true); } else - localDestination->SetPublic (true); - } + { + i2p::data::PrivateKeys k; + if(!LoadPrivateKeys (k, keys, sigType, cryptoType)) + continue; + localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ()); + if (!localDestination) + { + localDestination = CreateNewLocalDestination (k, true, &options); + destinations[keys] = localDestination; + } + else + localDestination->SetPublic (true); + } + } if (type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER) { // udp server tunnel @@ -897,7 +908,12 @@ namespace client i2p::config::GetOption("addressbook.enabled", httpAddresshelper); // addresshelper is not supported without address book i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType); LogPrint(eLogInfo, "Clients: Starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort); - if (httpProxyKeys.length () > 0) + if (httpProxyKeys == "shareddest") + { + localDestination = m_SharedLocalDestination; + localDestination->Acquire (); + } + else if (httpProxyKeys.length () > 0) { i2p::data::PrivateKeys keys; if(LoadPrivateKeys (keys, httpProxyKeys, sigType)) @@ -941,7 +957,12 @@ namespace client uint16_t socksOutProxyPort; i2p::config::GetOption("socksproxy.outproxyport", socksOutProxyPort); i2p::data::SigningKeyType sigType; i2p::config::GetOption("socksproxy.signaturetype", sigType); LogPrint(eLogInfo, "Clients: Starting SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort); - if (httpProxyKeys == socksProxyKeys && m_HttpProxy) + if (socksProxyKeys == "shareddest") + { + localDestination = m_SharedLocalDestination; + localDestination->Acquire (); + } + else if (httpProxyKeys == socksProxyKeys && m_HttpProxy) { localDestination = m_HttpProxy->GetLocalDestination (); localDestination->Acquire (); diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index febd5f16..3f7eaf9a 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.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 * @@ -92,7 +92,7 @@ namespace client const std::string & name, const std::map * params = nullptr); void DeleteLocalDestination (std::shared_ptr destination); std::shared_ptr FindLocalDestination (const i2p::data::IdentHash& destination) const; - bool LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, + bool LoadPrivateKeys (i2p::data::PrivateKeys& keys, std::string_view filename, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL); From 4d9b5e685ddec3d12ab7e43b4eda097e6e88f4e8 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 8 Mar 2025 16:03:36 -0500 Subject: [PATCH 399/527] use ends_with to recognize .i2p addresses --- libi2pd_client/AddressBook.cpp | 45 ++++++++++++++++++-------------- libi2pd_client/ClientContext.cpp | 4 +++ 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index 98528868..c0f440f9 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -443,17 +443,18 @@ namespace client auto addr = std::make_shared(address.substr (0, pos)); return addr->IsValid () ? addr : nullptr; } - else + else +#if __cplusplus >= 202002L // C++20 + if (address.ends_with (".i2p")) +#else + if (address.find (".i2p") != std::string::npos) +#endif { - pos = address.find (".i2p"); - if (pos != std::string::npos) - { - if (!m_IsEnabled) return nullptr; - auto addr = FindAddress (address); - if (!addr) - LookupAddress (address); // TODO: - return addr; - } + if (!m_IsEnabled) return nullptr; + auto addr = FindAddress (address); + if (!addr) + LookupAddress (address); // TODO: + return addr; } // if not .b32 we assume full base64 address i2p::data::IdentityEx dest; @@ -566,29 +567,35 @@ namespace client if (pos != std::string::npos) { - std::string name = s.substr(0, pos++); - std::string addr = s.substr(pos); + std::string_view name = std::string_view(s).substr(0, pos++); + std::string_view addr = std::string_view(s).substr(pos); size_t pos = addr.find('#'); - if (pos != std::string::npos) + if (pos != addr.npos) addr = addr.substr(0, pos); // remove comments - - pos = name.find(".b32.i2p"); - if (pos != std::string::npos) +#if __cplusplus >= 202002L // C++20 + if (name.ends_with (".b32.i2p")) +#else + if (name.find(".b32.i2p") != name.npos) +#endif { LogPrint (eLogError, "Addressbook: Skipped adding of b32 address: ", name); continue; } - pos = name.find(".i2p"); - if (pos == std::string::npos) +#if __cplusplus >= 202002L // C++20 + if (name.ends_with (".i2p")) +#else + if (name.find(".i2p") == name.npos) +#endif { LogPrint (eLogError, "Addressbook: Malformed domain: ", name); continue; } auto ident = std::make_shared (); - if (!ident->FromBase64(addr)) { + if (!ident->FromBase64(addr)) + { LogPrint (eLogError, "Addressbook: Malformed address ", addr, " for ", name); incomplete = f.eof (); continue; diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index aa322296..d26e33ab 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -547,7 +547,11 @@ namespace client { for (auto& it: files) { +#if __cplusplus >= 202002L // C++20 + if (!it.ends_with (".conf")) continue; +#else if (it.substr(it.size() - 5) != ".conf") continue; // skip files which not ends with ".conf" +#endif LogPrint(eLogDebug, "Clients: Tunnels extra config file: ", it); ReadTunnels (it, numClientTunnels, numServerTunnels); } From 4e8b8465fa6ef349416ee9b0369d9515f0446067 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 9 Mar 2025 11:17:19 -0400 Subject: [PATCH 400/527] don't create profile for every single router when save to disk --- libi2pd/NetDb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index ac786a29..097fcb2b 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -688,7 +688,7 @@ namespace data // since update was long time ago we assume that router is not connected anymore r->ScheduleBufferToDelete (); - if (r->GetProfile ()->IsUnreachable ()) + if (r->HasProfile () && r->GetProfile ()->IsUnreachable ()) r->SetUnreachable (true); // make router reachable back if too few routers or floodfills if (r->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate || isOffline || From 4ddfe9c94c128ee506027ffbe68b8dad6f3e72fe Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 9 Mar 2025 21:47:57 -0400 Subject: [PATCH 401/527] don't grow window too fast --- libi2pd/Streaming.cpp | 25 +++++++++++++++++++++---- libi2pd/Streaming.h | 3 ++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 2b274e31..0ed6067c 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -80,7 +80,7 @@ namespace stream m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_WindowSizeTail (0), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0), m_LastWindowIncTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { @@ -107,7 +107,7 @@ namespace stream m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_WindowSizeTail (0), m_Jitter (0), m_MinPacingTime (0), - m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0), + m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0), m_LastWindowIncTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) { @@ -1297,6 +1297,12 @@ namespace stream m_IsSendTime = true; if (m_WindowIncCounter && (m_WindowSize < MAX_WINDOW_SIZE || m_WindowDropTargetSize) && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime && m_RTT <= m_SlowRTT) { + float winSize = m_WindowSize; + if (m_WindowDropTargetSize) + winSize = m_WindowDropTargetSize; + float maxWinSize = MAX_WINDOW_SIZE; + if (m_LastWindowIncTime) + maxWinSize = (ts - m_LastWindowIncTime) / (m_RTT / MAX_WINDOW_SIZE_INC_PER_RTT) + winSize; for (int i = 0; i < m_NumPacketsToSend; i++) { if (m_WindowIncCounter) @@ -1311,6 +1317,11 @@ namespace stream m_WindowDropTargetSize += (m_WindowDropTargetSize - (1 - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowDropTargetSize; if (m_WindowDropTargetSize > MAX_WINDOW_SIZE) m_WindowDropTargetSize = MAX_WINDOW_SIZE; m_WindowIncCounter--; + if (m_WindowDropTargetSize >= maxWinSize) + { + m_WindowDropTargetSize = maxWinSize; + break; + } } else { @@ -1322,11 +1333,17 @@ namespace stream m_WindowSize += (m_WindowSize - (1 - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize; if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; m_WindowIncCounter--; + if (m_WindowSize >= maxWinSize) + { + m_WindowSize = maxWinSize; + break; + } } } else break; } + m_LastWindowIncTime = ts; UpdatePacingTime (); } else if (m_WindowIncCounter && m_WindowSize == MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) @@ -1650,12 +1667,12 @@ namespace stream { if (m_WindowSize < m_LastWindowDropSize) { - m_LastWindowDropSize = m_WindowSize - (m_LastWindowDropSize - m_WindowSize); + m_LastWindowDropSize = std::max ((m_WindowSize - MAX_WINDOW_SIZE_INC_PER_RTT), (m_WindowSize - (m_LastWindowDropSize - m_WindowSize))); if (m_LastWindowDropSize < MIN_WINDOW_SIZE) m_LastWindowDropSize = MIN_WINDOW_SIZE; } else { - m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize + m_WindowSizeTail) / 2; + m_LastWindowDropSize = std::max ((m_WindowSize - MAX_WINDOW_SIZE_INC_PER_RTT), ((m_LastWindowDropSize + m_WindowSize + m_WindowSizeTail) / 2)); if (m_LastWindowDropSize > MAX_WINDOW_SIZE) m_LastWindowDropSize = MAX_WINDOW_SIZE; } m_WindowDropTargetSize = m_LastWindowDropSize * 0.75; // -25% to drain queue diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index a91604c3..d75cb6eb 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -57,6 +57,7 @@ namespace stream const int INITIAL_WINDOW_SIZE = 10; const int MIN_WINDOW_SIZE = 3; const int MAX_WINDOW_SIZE = 512; + const int MAX_WINDOW_SIZE_INC_PER_RTT = 16; const double RTT_EWMA_ALPHA = 0.25; const double SLOWRTT_EWMA_ALPHA = 0.05; const double PREV_SPEED_KEEP_TIME_COEFF = 0.35; // 0.1 - 1 // how long will the window size stay around the previous drop level, less is longer @@ -299,7 +300,7 @@ namespace stream int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample, m_WindowSizeTail; double m_Jitter; uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, // microseconds - m_LastSendTime, m_LastACKRecieveTime, m_ACKRecieveInterval, m_RemoteLeaseChangeTime; // milliseconds + m_LastSendTime, m_LastACKRecieveTime, m_ACKRecieveInterval, m_RemoteLeaseChangeTime, m_LastWindowIncTime; // milliseconds uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed int m_NumResendAttempts, m_NumPacketsToSend; size_t m_MTU; From 972c6854bcf6ab44bf6e219dfb54fc20c74696d1 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 10 Mar 2025 13:43:21 -0400 Subject: [PATCH 402/527] don't delete trusted routers from netdb --- libi2pd/NetDb.cpp | 5 +++-- libi2pd/Transports.cpp | 29 +++++++++++++++++++---------- libi2pd/Transports.h | 6 ++++-- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 097fcb2b..7f6882c4 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -715,8 +715,9 @@ namespace data r->SetUnreachable (true); } } - // make router reachable back if connected now - if (r->IsUnreachable () && i2p::transport::transports.IsConnected (ident)) + // make router reachable back if connected now or trusted router + if (r->IsUnreachable () && (i2p::transport::transports.IsConnected (ident) || + i2p::transport::transports.IsTrustedRouter (ident))) r->SetUnreachable (false); if (r->IsUnreachable ()) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index b21426d1..98dbcd94 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -1195,7 +1195,7 @@ namespace transport std::lock_guard lock(m_TrustedRoutersMutex); m_TrustedRouters.clear(); for (const auto & ri : routers ) - m_TrustedRouters.push_back(ri); + m_TrustedRouters.insert(ri); } bool Transports::RoutesRestricted() const @@ -1236,23 +1236,32 @@ namespace transport auto sz = m_TrustedRouters.size(); if (sz) { - if(sz == 1) - return i2p::data::netdb.FindRouter(m_TrustedRouters[0]); auto it = m_TrustedRouters.begin(); - std::advance(it, m_Rng() % sz); + if(sz > 1) + std::advance(it, m_Rng() % sz); return i2p::data::netdb.FindRouter(*it); } } return nullptr; } - bool Transports::IsRestrictedPeer(const i2p::data::IdentHash & ih) const + bool Transports::IsTrustedRouter (const i2p::data::IdentHash& ih) const { - { - std::lock_guard l(m_TrustedRoutersMutex); - for (const auto & r : m_TrustedRouters ) - if ( r == ih ) return true; - } + if (m_TrustedRouters.empty ()) return false; + std::lock_guard l(m_TrustedRoutersMutex); +#if __cplusplus >= 202002L // C++20 + if (m_TrustedRouters.contains (ih)) +#else + if (m_TrustedRouters.count (ih) > 0) +#endif + return true; + return false; + } + + bool Transports::IsRestrictedPeer(const i2p::data::IdentHash& ih) const + { + if (IsTrustedRouter (ih)) return true; + { std::lock_guard l(m_FamilyMutex); auto ri = i2p::data::netdb.FindRouter(ih); diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 6f856697..fcd2cfc6 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -178,7 +179,8 @@ namespace transport /** restrict routes to use only these routers for first hops */ void RestrictRoutesToRouters(const std::set& routers); - bool IsRestrictedPeer(const i2p::data::IdentHash & ident) const; + bool IsTrustedRouter (const i2p::data::IdentHash& ih) const; + bool IsRestrictedPeer(const i2p::data::IdentHash& ih) const; void PeerTest (bool ipv4 = true, bool ipv6 = true); @@ -237,7 +239,7 @@ namespace transport mutable std::mutex m_FamilyMutex; /** which routers for first hop to trust */ - std::vector m_TrustedRouters; + std::unordered_set m_TrustedRouters; mutable std::mutex m_TrustedRoutersMutex; i2p::I2NPMessagesHandler m_LoopbackHandler; From dd58b2f8672116622713b8736c01e7d7e41250ff Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 12 Mar 2025 15:41:12 -0400 Subject: [PATCH 403/527] Post-Quantum. MLDSA44 verifier --- libi2pd/Crypto.h | 3 +++ libi2pd/Identity.cpp | 26 ++++++++++++++++++++++++++ libi2pd/Identity.h | 7 +++++-- libi2pd/Signature.cpp | 34 ++++++++++++++++++++++++++++++++++ libi2pd/Signature.h | 24 ++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 2 deletions(-) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 051f214f..b2fa0292 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -33,6 +33,9 @@ # if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL # define OPENSSL_SIPHASH 1 # endif +# if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0 +# define OPENSSL_PQ 1 +# endif #endif namespace i2p diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 285bde54..50d5c9c5 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -119,6 +119,16 @@ namespace data memcpy (m_StandardIdentity.signingKey, signingKey, i2p::crypto::GOSTR3410_512_PUBLIC_KEY_LENGTH); break; } +#if OPENSSL_PQ + case SIGNING_KEY_TYPE_MLDSA44: + { + memcpy (m_StandardIdentity, signingKey, 384); + excessLen = i2p::crypto::MLDSA44_PUBLIC_KEY_LENGTH - 384; + excessBuf = new uint8_t[excessLen]; + memcpy (excessBuf, signingKey + 384, excessLen); + break; + } +#endif default: LogPrint (eLogError, "Identity: Signing key type ", (int)type, " is not supported"); } @@ -352,6 +362,10 @@ 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 + case SIGNING_KEY_TYPE_MLDSA44: + return new i2p::crypto::MLDSA44Verifier (); +#endif case SIGNING_KEY_TYPE_RSA_SHA256_2048: case SIGNING_KEY_TYPE_RSA_SHA384_3072: case SIGNING_KEY_TYPE_RSA_SHA512_4096: @@ -373,6 +387,18 @@ namespace data auto keyLen = verifier->GetPublicKeyLen (); if (keyLen <= 128) verifier->SetPublicKey (m_StandardIdentity.signingKey + 128 - keyLen); +#if OPENSSL_PQ + else if (keyLen > 384) + { + // for post-quantum + 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 + verifier->SetPublicKey (signingKey); + delete[] signingKey; + } +#endif else { // for P521 diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index b5083e7e..cf1dbfcd 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -55,6 +55,8 @@ namespace data Identity& operator=(const Keys& keys); size_t FromBuffer (const uint8_t * buf, size_t len); IdentHash Hash () const; + operator uint8_t * () { return reinterpret_cast(this); } + operator const uint8_t * () const { return reinterpret_cast(this); } }; Keys CreateRandomKeys (); @@ -77,7 +79,8 @@ 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; + typedef uint16_t SigningKeyType; typedef uint16_t CryptoKeyType; @@ -132,7 +135,7 @@ namespace data IdentHash m_IdentHash; std::unique_ptr m_Verifier; size_t m_ExtendedLen; - uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE]; + uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE]; // TODO: support PQ keys }; size_t GetIdentityBufferLen (const uint8_t * buf, size_t len); // return actual identity length in buffer diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index d9fa0248..1ad4d2cb 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -199,6 +199,40 @@ namespace crypto else LogPrint (eLogError, "EdDSA signing key is not set"); } +#endif + +#if OPENSSL_PQ + MLDSA44Verifier::MLDSA44Verifier (): + m_Pkey (nullptr) + { + } + + MLDSA44Verifier::~MLDSA44Verifier () + { + EVP_PKEY_free (m_Pkey); + } + + void MLDSA44Verifier::SetPublicKey (const uint8_t * signingKey) + { + if (m_Pkey) EVP_PKEY_free (m_Pkey); + m_Pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ML_DSA_44, NULL, signingKey, GetPublicKeyLen ()); + } + + bool MLDSA44Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const + { + if (m_Pkey) + { + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, m_Pkey); + auto ret = EVP_DigestVerify (ctx, signature, GetSignatureLen (), buf, len); + EVP_MD_CTX_destroy (ctx); + return ret; + } + else + LogPrint (eLogError, "MLDSA44 verification key is not set"); + return false; + } + #endif } } diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index 2a731703..3cc7e9c0 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -560,6 +560,30 @@ namespace crypto RedDSA25519Signer signer (signingPrivateKey); memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH); } + +#if OPENSSL_PQ + + // Post-Quantum + const size_t MLDSA44_PUBLIC_KEY_LENGTH = 1312; + const size_t MLDSA44_SIGNATURE_LENGTH = 2420; + class MLDSA44Verifier: public Verifier + { + public: + + MLDSA44Verifier (); + void SetPublicKey (const uint8_t * signingKey); + ~MLDSA44Verifier (); + + bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; + + size_t GetPublicKeyLen () const { return MLDSA44_PUBLIC_KEY_LENGTH; }; + size_t GetSignatureLen () const { return MLDSA44_SIGNATURE_LENGTH; }; + + private: + + EVP_PKEY * m_Pkey; + }; +#endif } } From e3227ee5ee79772cb390b390366777e6723af0b1 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 13 Mar 2025 15:43:22 -0400 Subject: [PATCH 404/527] MLDSA44 signer and keygen --- libi2pd/Identity.cpp | 10 +++++ libi2pd/Signature.cpp | 99 +++++++++++++++++++++++++++++++++++++++---- libi2pd/Signature.h | 27 ++++++++++++ 3 files changed, 128 insertions(+), 8 deletions(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 50d5c9c5..93d7ec08 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -652,6 +652,11 @@ namespace data case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: return new i2p::crypto::RedDSA25519Signer (priv); break; +#if OPENSSL_PQ + case SIGNING_KEY_TYPE_MLDSA44: + return new i2p::crypto::MLDSA44Signer (priv); + break; +#endif default: LogPrint (eLogError, "Identity: Signing key type ", (int)keyType, " is not supported"); } @@ -757,6 +762,11 @@ namespace data case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: i2p::crypto::CreateRedDSA25519RandomKeys (priv, pub); break; +#if OPENSSL_PQ + case SIGNING_KEY_TYPE_MLDSA44: + i2p::crypto::CreateMLDSA44RandomKeys (priv, pub); + break; +#endif default: LogPrint (eLogWarning, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1"); i2p::crypto::CreateDSARandomKeys (priv, pub); // DSA-SHA1 diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index 1ad4d2cb..1c19c907 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -202,6 +202,14 @@ namespace crypto #endif #if OPENSSL_PQ +#include + + static const OSSL_PARAM MLDSAParams[] = + { + OSSL_PARAM_octet_string("context-string", (unsigned char *)"A context string", 16), + OSSL_PARAM_END + }; + MLDSA44Verifier::MLDSA44Verifier (): m_Pkey (nullptr) { @@ -214,24 +222,99 @@ namespace crypto void MLDSA44Verifier::SetPublicKey (const uint8_t * signingKey) { - if (m_Pkey) EVP_PKEY_free (m_Pkey); - m_Pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ML_DSA_44, NULL, signingKey, GetPublicKeyLen ()); + 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 *)signingKey, GetPublicKeyLen ()), + OSSL_PARAM_END + }; + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "ML-DSA-44", 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, "MLDSA44 can't create PKEY context"); } bool MLDSA44Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const { + bool ret = false; if (m_Pkey) { - EVP_MD_CTX * ctx = EVP_MD_CTX_create (); - EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, m_Pkey); - auto ret = EVP_DigestVerify (ctx, signature, GetSignatureLen (), buf, len); - EVP_MD_CTX_destroy (ctx); - return ret; + EVP_PKEY_CTX * vctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL); + if (vctx) + { + EVP_SIGNATURE * sig = EVP_SIGNATURE_fetch (NULL, "ML-DSA-44", NULL); + if (sig) + { + EVP_PKEY_verify_message_init (vctx, sig, MLDSAParams); + ret = EVP_PKEY_verify (vctx, signature, GetSignatureLen (), buf, len); + EVP_SIGNATURE_free (sig); + } + EVP_PKEY_CTX_free (vctx); + } + else + LogPrint (eLogError, "MLDSA44 can't obtain context from PKEY"); } else LogPrint (eLogError, "MLDSA44 verification key is not set"); - return false; + return ret; } + + MLDSA44Signer::MLDSA44Signer (const uint8_t * signingPrivateKey): + m_Pkey (nullptr) + { + OSSL_PARAM params[] = + { + OSSL_PARAM_octet_string (OSSL_PKEY_PARAM_PRIV_KEY, (uint8_t *)signingPrivateKey, MLDSA44_PRIVATE_KEY_LENGTH), + OSSL_PARAM_END + }; + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "ML-DSA-44", NULL); + if (ctx) + { + EVP_PKEY_fromdata_init (ctx); + EVP_PKEY_fromdata (ctx, &m_Pkey, OSSL_KEYMGMT_SELECT_PRIVATE_KEY, params); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "MLDSA44 can't create PKEY context"); + } + + MLDSA44Signer::~MLDSA44Signer () + { + if (m_Pkey) EVP_PKEY_free (m_Pkey); + } + + void MLDSA44Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const + { + if (m_Pkey) + { + EVP_PKEY_CTX * sctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL); + if (sctx) + { + EVP_SIGNATURE * sig = EVP_SIGNATURE_fetch (NULL, "ML-DSA-44", NULL); + if (sig) + { + EVP_PKEY_sign_message_init (sctx, sig, MLDSAParams); + size_t siglen = MLDSA44_SIGNATURE_LENGTH; + EVP_PKEY_sign (sctx, signature, &siglen, buf, len); + EVP_SIGNATURE_free (sig); + } + EVP_PKEY_CTX_free (sctx); + } + else + LogPrint (eLogError, "MLDSA44 can't obtain context from PKEY"); + } + else + LogPrint (eLogError, "MLDSA44 signing key is not set"); + } #endif } diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index 3cc7e9c0..c77e10dd 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -562,10 +562,12 @@ namespace crypto } #if OPENSSL_PQ +#include // Post-Quantum const size_t MLDSA44_PUBLIC_KEY_LENGTH = 1312; const size_t MLDSA44_SIGNATURE_LENGTH = 2420; + const size_t MLDSA44_PRIVATE_KEY_LENGTH = 2560; class MLDSA44Verifier: public Verifier { public: @@ -578,11 +580,36 @@ namespace crypto size_t GetPublicKeyLen () const { return MLDSA44_PUBLIC_KEY_LENGTH; }; size_t GetSignatureLen () const { return MLDSA44_SIGNATURE_LENGTH; }; + size_t GetPrivateKeyLen () const { return MLDSA44_PRIVATE_KEY_LENGTH; }; private: EVP_PKEY * m_Pkey; }; + + class MLDSA44Signer: public Signer + { + public: + + MLDSA44Signer (const uint8_t * signingPrivateKey); + ~MLDSA44Signer (); + + void Sign (const uint8_t * buf, int len, uint8_t * signature) const; + + private: + + EVP_PKEY * m_Pkey; + }; + + inline void CreateMLDSA44RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + EVP_PKEY * pkey = EVP_PKEY_Q_keygen (NULL, NULL, "ML-DSA-44"); + size_t len = MLDSA44_PUBLIC_KEY_LENGTH; + EVP_PKEY_get_octet_string_param (pkey, OSSL_PKEY_PARAM_PUB_KEY, signingPublicKey, MLDSA44_PUBLIC_KEY_LENGTH, &len); + len = MLDSA44_PRIVATE_KEY_LENGTH; + EVP_PKEY_get_octet_string_param (pkey, OSSL_PKEY_PARAM_PRIV_KEY, signingPrivateKey, MLDSA44_PRIVATE_KEY_LENGTH, &len); + EVP_PKEY_free (pkey); + } #endif } } From cd9427d5d5d318ffb82ad8775fbe1c218aabd332 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 13 Mar 2025 20:39:51 -0400 Subject: [PATCH 405/527] correct ML-DSA-44 signature verification params --- libi2pd/Signature.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index 1c19c907..3a1bb104 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -254,7 +254,13 @@ namespace crypto EVP_SIGNATURE * sig = EVP_SIGNATURE_fetch (NULL, "ML-DSA-44", NULL); if (sig) { - EVP_PKEY_verify_message_init (vctx, sig, MLDSAParams); + int encode = 0; + OSSL_PARAM params[] = + { + OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, &encode), + OSSL_PARAM_construct_end() + }; + EVP_PKEY_verify_message_init (vctx, sig, params); ret = EVP_PKEY_verify (vctx, signature, GetSignatureLen (), buf, len); EVP_SIGNATURE_free (sig); } From ad7ca428ae4b5ba4def265f8bb5f3a07c2b2561c Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 14 Mar 2025 11:40:54 -0400 Subject: [PATCH 406/527] enable encoding of ML-DSA-44 messages --- libi2pd/Signature.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index 3a1bb104..f684f10f 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -203,13 +203,7 @@ namespace crypto #if OPENSSL_PQ #include - - static const OSSL_PARAM MLDSAParams[] = - { - OSSL_PARAM_octet_string("context-string", (unsigned char *)"A context string", 16), - OSSL_PARAM_END - }; - + MLDSA44Verifier::MLDSA44Verifier (): m_Pkey (nullptr) { @@ -254,11 +248,11 @@ namespace crypto EVP_SIGNATURE * sig = EVP_SIGNATURE_fetch (NULL, "ML-DSA-44", NULL); if (sig) { - int encode = 0; + int encode = 1; OSSL_PARAM params[] = { - OSSL_PARAM_construct_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, &encode), - OSSL_PARAM_construct_end() + OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, &encode), + OSSL_PARAM_END }; EVP_PKEY_verify_message_init (vctx, sig, params); ret = EVP_PKEY_verify (vctx, signature, GetSignatureLen (), buf, len); @@ -308,7 +302,13 @@ namespace crypto EVP_SIGNATURE * sig = EVP_SIGNATURE_fetch (NULL, "ML-DSA-44", NULL); if (sig) { - EVP_PKEY_sign_message_init (sctx, sig, MLDSAParams); + int encode = 1; + OSSL_PARAM params[] = + { + OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, &encode), + OSSL_PARAM_END + }; + EVP_PKEY_sign_message_init (sctx, sig, params); size_t siglen = MLDSA44_SIGNATURE_LENGTH; EVP_PKEY_sign (sctx, signature, &siglen, buf, len); EVP_SIGNATURE_free (sig); From c3d4d1bdf407a585e27d3fdbcfca426395926553 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 14 Mar 2025 13:07:45 -0400 Subject: [PATCH 407/527] use array/string_view for exluded HTTP headers in server tunnel --- libi2pd_client/I2PTunnel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 6d45c10c..d6436c78 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -391,7 +391,7 @@ namespace client else { // strip up some headers - static const std::vector excluded // list of excluded headers + static const std::array excluded // list of excluded headers { "Keep-Alive:", "X-I2P" }; @@ -474,7 +474,7 @@ namespace client if (line == "\r") endOfHeader = true; else { - static const std::vector excluded // list of excluded headers + static const std::array excluded // list of excluded headers { "Server:", "Date:", "X-Runtime:", "X-Powered-By:", "Proxy" }; From ede8244e54e0d7363990d89d2051e223755e9cce Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 14 Mar 2025 14:46:24 -0400 Subject: [PATCH 408/527] store translation as string_view --- daemon/HTTPServer.cpp | 13 +++++++------ i18n/Afrikaans.cpp | 4 ++-- i18n/Armenian.cpp | 4 ++-- i18n/Chinese.cpp | 4 ++-- i18n/Czech.cpp | 4 ++-- i18n/English.cpp | 4 ++-- i18n/French.cpp | 4 ++-- i18n/German.cpp | 4 ++-- i18n/I18N.cpp | 4 ++-- i18n/I18N.h | 16 +++++++++------- i18n/Italian.cpp | 4 ++-- i18n/Polish.cpp | 4 ++-- i18n/Portuguese.cpp | 4 ++-- i18n/Russian.cpp | 4 ++-- i18n/Spanish.cpp | 4 ++-- i18n/Swedish.cpp | 4 ++-- i18n/Turkish.cpp | 4 ++-- i18n/Turkmen.cpp | 4 ++-- i18n/Ukrainian.cpp | 4 ++-- i18n/Uzbek.cpp | 4 ++-- 20 files changed, 52 insertions(+), 49 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 2ac636ce..f10bd1e2 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.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 * @@ -132,7 +132,8 @@ namespace http { static void ShowTunnelDetails (std::stringstream& s, enum i2p::tunnel::TunnelState eState, bool explr, int bytes) { - std::string state, stateText; + std::string state; + std::string_view stateText; switch (eState) { case i2p::tunnel::eTunnelStateBuildReplyReceived : @@ -146,7 +147,7 @@ namespace http { } if (stateText.empty ()) stateText = tr(state); - s << " " << stateText << ((explr) ? " (" + tr("exploratory") + ")" : "") << ", "; + s << " " << stateText << ((explr) ? " (" + std::string(tr("exploratory")) + ")" : "") << ", "; // TODO: ShowTraffic(s, bytes); s << "\r\n"; } @@ -213,7 +214,7 @@ namespace http { "\r\n"; } - static void ShowError(std::stringstream& s, const std::string& string) + static void ShowError(std::stringstream& s, std::string_view string) { s << "" << tr("ERROR") << ": " << string << "
    \r\n"; } @@ -1262,7 +1263,7 @@ namespace http { ShowLeasesSets(s); else { res.code = 400; - ShowError(s, tr("Unknown page") + ": " + page); + ShowError(s, std::string (tr("Unknown page")) + ": " + page); // TODO return; } } @@ -1462,7 +1463,7 @@ namespace http { else { res.code = 400; - ShowError(s, tr("Unknown command") + ": " + cmd); + ShowError(s, std::string (tr("Unknown command")) + ": " + cmd); // TODO return; } diff --git a/i18n/Afrikaans.cpp b/i18n/Afrikaans.cpp index b582a06a..b69c42ef 100644 --- a/i18n/Afrikaans.cpp +++ b/i18n/Afrikaans.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2021, The PurpleI2P Project +* Copyright (c) 2021-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace afrikaans // language namespace return n != 1 ? 1 : 0; } - static std::map strings + static const LocaleStrings strings { {"failed", "Het misluk"}, {"unknown", "onbekend"}, diff --git a/i18n/Armenian.cpp b/i18n/Armenian.cpp index b99e5032..67955d8a 100644 --- a/i18n/Armenian.cpp +++ b/i18n/Armenian.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2021-2023, The PurpleI2P Project +* Copyright (c) 2021-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace armenian // language namespace return n != 1 ? 1 : 0; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f ԿիԲ"}, {"%.2f MiB", "%.2f ՄիԲ"}, diff --git a/i18n/Chinese.cpp b/i18n/Chinese.cpp index ad46178c..e3b63ebd 100644 --- a/i18n/Chinese.cpp +++ b/i18n/Chinese.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022-2024, The PurpleI2P Project +* Copyright (c) 2022-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace chinese // language namespace return 0; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, {"%.2f MiB", "%.2f MiB"}, diff --git a/i18n/Czech.cpp b/i18n/Czech.cpp index 3b865474..94803354 100644 --- a/i18n/Czech.cpp +++ b/i18n/Czech.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022-2024, The PurpleI2P Project +* Copyright (c) 2022-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace czech // language namespace return (n == 1) ? 0 : (n >= 2 && n <= 4) ? 1 : 2; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, {"%.2f MiB", "%.2f MiB"}, diff --git a/i18n/English.cpp b/i18n/English.cpp index 2670e984..fb774527 100644 --- a/i18n/English.cpp +++ b/i18n/English.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2021, The PurpleI2P Project +* Copyright (c) 2021-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -30,7 +30,7 @@ namespace english // language namespace return n != 1 ? 1 : 0; } - static std::map strings + static const LocaleStrings strings { {"", ""}, }; diff --git a/i18n/French.cpp b/i18n/French.cpp index 999f82b9..985296a3 100644 --- a/i18n/French.cpp +++ b/i18n/French.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022-2024, The PurpleI2P Project +* Copyright (c) 2022-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace french // language namespace return n != 1 ? 1 : 0; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f Kio"}, {"%.2f MiB", "%.2f Mio"}, diff --git a/i18n/German.cpp b/i18n/German.cpp index 02662e8e..90ce82f4 100644 --- a/i18n/German.cpp +++ b/i18n/German.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022-2023, The PurpleI2P Project +* Copyright (c) 2022-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace german // language namespace return n != 1 ? 1 : 0; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, {"%.2f MiB", "%.2f MiB"}, diff --git a/i18n/I18N.cpp b/i18n/I18N.cpp index cf4873eb..e444164a 100644 --- a/i18n/I18N.cpp +++ b/i18n/I18N.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2021-2023, The PurpleI2P Project +* Copyright (c) 2021-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -30,7 +30,7 @@ namespace i18n } } - std::string translate (const std::string& arg) + std::string_view translate (std::string_view arg) { return i2p::client::context.GetLanguage ()->GetString (arg); } diff --git a/i18n/I18N.h b/i18n/I18N.h index 6ec5b16e..489d1842 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2021-2023, The PurpleI2P Project +* Copyright (c) 2021-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -10,6 +10,7 @@ #define __I18N_H__ #include +#include #include #include #include @@ -18,12 +19,13 @@ namespace i2p { namespace i18n { + typedef std::map LocaleStrings; class Locale { public: Locale ( const std::string& language, - const std::map& strings, + const LocaleStrings& strings, const std::map>& plurals, std::function formula ): m_Language (language), m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { }; @@ -34,7 +36,7 @@ namespace i18n return m_Language; } - std::string GetString (const std::string& arg) const + std::string_view GetString (std::string_view arg) const { const auto it = m_Strings.find(arg); if (it == m_Strings.end()) @@ -63,13 +65,13 @@ namespace i18n private: const std::string m_Language; - const std::map m_Strings; + const LocaleStrings m_Strings; const std::map> m_Plurals; std::function m_Formula; }; void SetLanguage(const std::string &lang); - std::string translate (const std::string& arg); + std::string_view translate (std::string_view arg); std::string translate (const std::string& arg, const std::string& arg2, const int& n); } // i18n } // i2p @@ -79,7 +81,7 @@ namespace i18n * @param arg String with message */ template -std::string tr (TValue&& arg) +std::string_view tr (TValue&& arg) { return i2p::i18n::translate(std::forward(arg)); } @@ -92,7 +94,7 @@ std::string tr (TValue&& arg) template std::string tr (TValue&& arg, TArgs&&... args) { - std::string tr_str = i2p::i18n::translate(std::forward(arg)); + std::string tr_str = std::string (i2p::i18n::translate(std::forward(arg))); // TODO: size_t size = std::snprintf(NULL, 0, tr_str.c_str(), std::forward(args)...); std::string str(size, 0); diff --git a/i18n/Italian.cpp b/i18n/Italian.cpp index 2dcaab5e..0ae26f21 100644 --- a/i18n/Italian.cpp +++ b/i18n/Italian.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022-2023, The PurpleI2P Project +* Copyright (c) 2022-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace italian // language namespace return n != 1 ? 1 : 0; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, {"%.2f MiB", "%.2f MiB"}, diff --git a/i18n/Polish.cpp b/i18n/Polish.cpp index b2abda11..0e8df096 100644 --- a/i18n/Polish.cpp +++ b/i18n/Polish.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023-2024, The PurpleI2P Project +* Copyright (c) 2023-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace polish // language namespace return (n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, {"%.2f MiB", "%.2f MiB"}, diff --git a/i18n/Portuguese.cpp b/i18n/Portuguese.cpp index 0c490ba3..26204dc3 100644 --- a/i18n/Portuguese.cpp +++ b/i18n/Portuguese.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023-2024, The PurpleI2P Project +* Copyright (c) 2023-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace portuguese // language namespace return n != 1 ? 1 : 0; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, {"%.2f MiB", "%.2f MiB"}, diff --git a/i18n/Russian.cpp b/i18n/Russian.cpp index 15952710..235cc0ae 100644 --- a/i18n/Russian.cpp +++ b/i18n/Russian.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2021-2023, The PurpleI2P Project +* Copyright (c) 2021-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace russian // language namespace return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f КиБ"}, {"%.2f MiB", "%.2f МиБ"}, diff --git a/i18n/Spanish.cpp b/i18n/Spanish.cpp index a5ecc30a..0e657fb4 100644 --- a/i18n/Spanish.cpp +++ b/i18n/Spanish.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022-2023, The PurpleI2P Project +* Copyright (c) 2022-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace spanish // language namespace return n != 1 ? 1 : 0; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, {"%.2f MiB", "%.2f MiB"}, diff --git a/i18n/Swedish.cpp b/i18n/Swedish.cpp index 05ed1e18..df13d22f 100644 --- a/i18n/Swedish.cpp +++ b/i18n/Swedish.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023, The PurpleI2P Project +* Copyright (c) 2023-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace swedish // language namespace return n != 1 ? 1 : 0; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, {"%.2f MiB", "%.2f MiB"}, diff --git a/i18n/Turkish.cpp b/i18n/Turkish.cpp index d4398ebe..9946b336 100644 --- a/i18n/Turkish.cpp +++ b/i18n/Turkish.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023, The PurpleI2P Project +* Copyright (c) 2023-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace turkish // language namespace return n != 1 ? 1 : 0; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, {"%.2f MiB", "%.2f MiB"}, diff --git a/i18n/Turkmen.cpp b/i18n/Turkmen.cpp index 35ee0f89..7efb8891 100644 --- a/i18n/Turkmen.cpp +++ b/i18n/Turkmen.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2021-2023, The PurpleI2P Project +* Copyright (c) 2021-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace turkmen // language namespace return n != 1 ? 1 : 0; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, {"%.2f MiB", "%.2f MiB"}, diff --git a/i18n/Ukrainian.cpp b/i18n/Ukrainian.cpp index d089c142..c1b6c772 100644 --- a/i18n/Ukrainian.cpp +++ b/i18n/Ukrainian.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2021-2023, The PurpleI2P Project +* Copyright (c) 2021-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace ukrainian // language namespace return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f КіБ"}, {"%.2f MiB", "%.2f МіБ"}, diff --git a/i18n/Uzbek.cpp b/i18n/Uzbek.cpp index cf94a489..8e870772 100644 --- a/i18n/Uzbek.cpp +++ b/i18n/Uzbek.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2021-2023, The PurpleI2P Project +* Copyright (c) 2021-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -29,7 +29,7 @@ namespace uzbek // language namespace return n > 1 ? 1 : 0; } - static std::map strings + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, {"%.2f MiB", "%.2f MiB"}, From 6a656806197a5ade9ad4d3968cb4af739b3e70a7 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 14 Mar 2025 18:45:27 -0400 Subject: [PATCH 409/527] use array/string_view for HTTP methods and versions --- libi2pd/HTTP.cpp | 25 ++++++++++++++++++------- libi2pd/HTTP.h | 4 +--- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index 258d3ada..8e9c4733 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.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 * @@ -10,6 +10,7 @@ #include #include #include +#include #include "util.h" #include "Base.h" #include "HTTP.h" @@ -18,26 +19,36 @@ namespace i2p { namespace http { - const std::vector HTTP_METHODS = { + // list of valid HTTP methods + static constexpr std::array HTTP_METHODS = { "GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "CONNECT", // HTTP basic methods "COPY", "LOCK", "MKCOL", "MOVE", "PROPFIND", "PROPPATCH", "UNLOCK", "SEARCH" // WebDAV methods, for SEARCH see rfc5323 }; - const std::vector HTTP_VERSIONS = { + + // list of valid HTTP versions + static constexpr std::array HTTP_VERSIONS = + { "HTTP/1.0", "HTTP/1.1" }; - const std::vector weekdays = { + + static constexpr std::array weekdays = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; - const std::vector months = { + + static constexpr std::array months = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - inline bool is_http_version(const std::string & str) { + static inline bool is_http_version(std::string_view str) + { return std::find(HTTP_VERSIONS.begin(), HTTP_VERSIONS.end(), str) != std::end(HTTP_VERSIONS); } - inline bool is_http_method(const std::string & str) { + static inline bool is_http_method(std::string_view str) + { return std::find(HTTP_METHODS.begin(), HTTP_METHODS.end(), str) != std::end(HTTP_METHODS); } diff --git a/libi2pd/HTTP.h b/libi2pd/HTTP.h index 438ef953..21a99099 100644 --- a/libi2pd/HTTP.h +++ b/libi2pd/HTTP.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 * @@ -23,8 +23,6 @@ namespace http { const char CRLF[] = "\r\n"; /**< HTTP line terminator */ const char HTTP_EOH[] = "\r\n\r\n"; /**< HTTP end-of-headers mark */ - extern const std::vector HTTP_METHODS; /**< list of valid HTTP methods */ - extern const std::vector HTTP_VERSIONS; /**< list of valid HTTP versions */ struct URL { From 2def747564d5ea4c9d4e33bf91789bf8da67e203 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 14 Mar 2025 19:28:22 -0400 Subject: [PATCH 410/527] use array instead vector for reserved ranges --- libi2pd/util.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 76bfe103..925cf629 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.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 * @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -123,8 +124,8 @@ const char *inet_ntop_xp(int af, const void *src, char *dst, socklen_t size) #endif #endif -#define address_pair_v4(a,b) { boost::asio::ip::make_address (a).to_v4 ().to_uint (), boost::asio::ip::make_address(b).to_v4 ().to_uint () } -#define address_pair_v6(a,b) { boost::asio::ip::make_address (a).to_v6 ().to_bytes (), boost::asio::ip::make_address(b).to_v6 ().to_bytes () } +#define address_pair_v4(a,b) std::pair{ boost::asio::ip::make_address (a).to_v4 ().to_uint (), boost::asio::ip::make_address(b).to_v4 ().to_uint () } +#define address_pair_v6(a,b) std::pair{ boost::asio::ip::make_address (a).to_v6 ().to_bytes (), boost::asio::ip::make_address(b).to_v6 ().to_bytes () } namespace i2p { @@ -647,7 +648,8 @@ namespace net if (host.is_unspecified ()) return false; if (host.is_v4()) { - static const std::vector< std::pair > reservedIPv4Ranges { + static const std::array, 14> reservedIPv4Ranges + { address_pair_v4("0.0.0.0", "0.255.255.255"), address_pair_v4("10.0.0.0", "10.255.255.255"), address_pair_v4("100.64.0.0", "100.127.255.255"), @@ -672,7 +674,8 @@ namespace net } if (host.is_v6()) { - static const std::vector< std::pair > reservedIPv6Ranges { + static const std::array, 7> reservedIPv6Ranges + { address_pair_v6("64:ff9b::", "64:ff9b:ffff:ffff:ffff:ffff:ffff:ffff"), // NAT64 address_pair_v6("2001:db8::", "2001:db8:ffff:ffff:ffff:ffff:ffff:ffff"), address_pair_v6("fc00::", "fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"), From 67ab4fef6d2d42eb94308597c9c4374464f821b9 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 15 Mar 2025 13:19:53 -0400 Subject: [PATCH 411/527] implement strsplit using string_view instead stringstream --- libi2pd/HTTP.cpp | 48 ++++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index 8e9c4733..23cbcab2 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "util.h" #include "Base.h" #include "HTTP.h" @@ -20,7 +21,8 @@ namespace i2p namespace http { // list of valid HTTP methods - static constexpr std::array HTTP_METHODS = { + static constexpr std::array HTTP_METHODS = + { "GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "CONNECT", // HTTP basic methods "COPY", "LOCK", "MKCOL", "MOVE", "PROPFIND", "PROPPATCH", "UNLOCK", "SEARCH" // WebDAV methods, for SEARCH see rfc5323 }; @@ -52,31 +54,17 @@ namespace http return std::find(HTTP_METHODS.begin(), HTTP_METHODS.end(), str) != std::end(HTTP_METHODS); } - static void strsplit(std::stringstream& ss, std::vector &tokens, char delim, std::size_t limit = 0) - { - std::size_t count = 0; - std::string token; - while (1) + static void strsplit(std::string_view line, std::vector &tokens, char delim, std::size_t limit = 0) + { + size_t count = 0, pos; + while ((pos = line.find (delim)) != line.npos) { count++; - if (limit > 0 && count >= limit) - delim = '\n'; /* reset delimiter */ - if (!std::getline(ss, token, delim)) - break; - tokens.push_back(token); + if (limit > 0 && count >= limit) delim = '\n'; // reset delimiter + tokens.push_back (line.substr (0, pos)); + line = line.substr (pos + 1); } - } - - static void strsplit(const std::string & line, std::vector &tokens, char delim, std::size_t limit = 0) - { - std::stringstream ss{line}; - strsplit (ss, tokens, delim, limit); - } - - static void strsplit(std::string_view line, std::vector &tokens, char delim, std::size_t limit = 0) - { - std::stringstream ss{std::string(line)}; - strsplit (ss, tokens, delim, limit); + if (!line.empty ()) tokens.push_back (line); } static std::pair parse_header_line(std::string_view line) @@ -222,8 +210,9 @@ namespace http return true; } - bool URL::parse_query(std::map & params) { - std::vector tokens; + bool URL::parse_query(std::map & params) + { + std::vector tokens; strsplit(query, tokens, '&'); params.clear(); @@ -319,8 +308,9 @@ namespace http if (expect == REQ_LINE) { std::string_view line = str.substr(pos, eol - pos); - std::vector tokens; + std::vector tokens; strsplit(line, tokens, ' '); + if (tokens.size() != 3) return -1; if (!is_http_method(tokens[0])) @@ -462,13 +452,15 @@ namespace http if (expect == RES_LINE) { std::string_view line = str.substr(pos, eol - pos); - std::vector tokens; + std::vector tokens; strsplit(line, tokens, ' ', 3); if (tokens.size() != 3) return -1; if (!is_http_version(tokens[0])) return -1; - code = atoi(tokens[1].c_str()); + auto res = std::from_chars(tokens[1].data (), tokens[1].data() + tokens[1].size(), code); + if (res.ec != std::errc()) + return -1; if (code < 100 || code >= 600) return -1; /* all ok */ From 960a85e415cbaae4f3568543b92f640479ea8087 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 15 Mar 2025 16:43:08 -0400 Subject: [PATCH 412/527] replace more strings to string_view --- libi2pd/HTTP.cpp | 21 +++++++++++---------- libi2pd/HTTP.h | 10 +++++----- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index 23cbcab2..3cd5c193 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "util.h" #include "Base.h" @@ -334,11 +333,11 @@ namespace http else return -1; } - pos = eol + strlen(CRLF); + pos = eol + CRLF.length(); if (pos >= eoh) break; } - return eoh + strlen(HTTP_EOH); + return eoh + HTTP_EOH.length(); } void HTTPReq::write(std::ostream & o) @@ -382,7 +381,7 @@ namespace http } } - std::string HTTPReq::GetHeader (const std::string& name) const + std::string HTTPReq::GetHeader (std::string_view name) const { for (auto& it : headers) if (it.first == name) @@ -390,7 +389,7 @@ namespace http return ""; } - size_t HTTPReq::GetNumHeaders (const std::string& name) const + size_t HTTPReq::GetNumHeaders (std::string_view name) const { size_t num = 0; for (auto& it : headers) @@ -477,11 +476,11 @@ namespace http else return -1; } - pos = eol + strlen(CRLF); + pos = eol + CRLF.length(); if (pos >= eoh) break; } - return eoh + strlen(HTTP_EOH); + return eoh + HTTP_EOH.length(); } std::string HTTPRes::to_string() { @@ -506,9 +505,11 @@ namespace http return ss.str(); } - const char * HTTPCodeToStatus(int code) { - const char *ptr; - switch (code) { + std::string_view HTTPCodeToStatus(int code) + { + std::string_view ptr; + switch (code) + { case 105: ptr = "Name Not Resolved"; break; /* success */ case 200: ptr = "OK"; break; diff --git a/libi2pd/HTTP.h b/libi2pd/HTTP.h index 21a99099..c65c1ce4 100644 --- a/libi2pd/HTTP.h +++ b/libi2pd/HTTP.h @@ -21,8 +21,8 @@ namespace i2p { namespace http { - const char CRLF[] = "\r\n"; /**< HTTP line terminator */ - const char HTTP_EOH[] = "\r\n\r\n"; /**< HTTP end-of-headers mark */ + constexpr std::string_view CRLF = "\r\n"; /**< HTTP line terminator */ + constexpr std::string_view HTTP_EOH = "\r\n\r\n"; /**< HTTP end-of-headers mark */ struct URL { @@ -101,8 +101,8 @@ namespace http void UpdateHeader (const std::string& name, const std::string& value); void RemoveHeader (const std::string& name, const std::string& exempt); // remove all headers starting with name, but exempt void RemoveHeader (const std::string& name) { RemoveHeader (name, ""); }; - std::string GetHeader (const std::string& name) const; - size_t GetNumHeaders (const std::string& name) const; + std::string GetHeader (std::string_view name) const; + size_t GetNumHeaders (std::string_view name) const; size_t GetNumHeaders () const { return headers.size (); }; }; @@ -152,7 +152,7 @@ namespace http * @param code HTTP code [100, 599] * @return Immutable string with status */ - const char * HTTPCodeToStatus(int code); + std::string_view HTTPCodeToStatus(int code); /** * @brief Replaces %-encoded characters in string with their values From d93a80cd2ba1099f464559f200aa148cedae8c91 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Mar 2025 11:07:17 -0400 Subject: [PATCH 413/527] Support v1 datagram sessions without port --- libi2pd_client/SAM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 13992efa..81b1726d 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -415,7 +415,7 @@ namespace client { session->UDPEndpoint = forward; auto dest = session->GetLocalDestination ()->CreateDatagramDestination (); - auto port = std::stoi(params[SAM_PARAM_PORT]); + auto port = forward ? std::stoi(params[SAM_PARAM_PORT]) : 0; 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), From c0b5f2d2ef752b59a6ce66108e94a6e504deba50 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Mar 2025 15:17:08 -0400 Subject: [PATCH 414/527] pass n by value --- i18n/I18N.cpp | 2 +- i18n/I18N.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/i18n/I18N.cpp b/i18n/I18N.cpp index e444164a..48a02357 100644 --- a/i18n/I18N.cpp +++ b/i18n/I18N.cpp @@ -35,7 +35,7 @@ namespace i18n return i2p::client::context.GetLanguage ()->GetString (arg); } - std::string translate (const std::string& arg, const std::string& arg2, const int& n) + std::string translate (const std::string& arg, const std::string& arg2, const int n) { return i2p::client::context.GetLanguage ()->GetPlural (arg, arg2, n); } diff --git a/i18n/I18N.h b/i18n/I18N.h index 489d1842..8ed77a6b 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -49,7 +49,7 @@ namespace i18n } } - std::string GetPlural (const std::string& arg, const std::string& arg2, const int& n) const + std::string GetPlural (const std::string& arg, const std::string& arg2, int n) const { const auto it = m_Plurals.find(arg2); if (it == m_Plurals.end()) // not found, fallback to english @@ -72,7 +72,7 @@ namespace i18n void SetLanguage(const std::string &lang); std::string_view translate (std::string_view arg); - std::string translate (const std::string& arg, const std::string& arg2, const int& n); + std::string translate (const std::string& arg, const std::string& arg2, int n); } // i18n } // i2p @@ -110,7 +110,7 @@ std::string tr (TValue&& arg, TArgs&&... args) * @param n Integer, used for selection of form */ template -std::string ntr (TValue&& arg, TValue2&& arg2, int& n) +std::string ntr (TValue&& arg, TValue2&& arg2, int n) { return i2p::i18n::translate(std::forward(arg), std::forward(arg2), std::forward(n)); } @@ -123,7 +123,7 @@ std::string ntr (TValue&& arg, TValue2&& arg2, int& n) * @param args Array of arguments for string formatting */ template -std::string ntr (TValue&& arg, TValue2&& arg2, int& n, TArgs&&... args) +std::string ntr (TValue&& arg, TValue2&& arg2, int n, TArgs&&... args) { std::string tr_str = i2p::i18n::translate(std::forward(arg), std::forward(arg2), std::forward(n)); From 706b9c51b161e47d18d180d81d2b3974fb7d2bc0 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Mar 2025 17:21:22 -0400 Subject: [PATCH 415/527] make Base64EncodingBufferSize constexpr --- libi2pd/Base.cpp | 27 ++++----------------------- libi2pd/Base.h | 32 +++++++++++++++++++++++--------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/libi2pd/Base.cpp b/libi2pd/Base.cpp index b8de571b..719cdec3 100644 --- a/libi2pd/Base.cpp +++ b/libi2pd/Base.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2023, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -27,11 +27,6 @@ namespace data { return T32; } - - bool IsBase32 (char ch) - { - return (ch >= 'a' && ch <= 'z') || (ch >= '2' && ch <= '7'); - } static void iT64Build(void); @@ -59,11 +54,6 @@ namespace data { return T64; } - - bool IsBase64 (char ch) - { - return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '-' || ch == '~'; - } /* * Reverse Substitution Table (built in run time) @@ -234,21 +224,12 @@ namespace data return outCount; } - - size_t Base64EncodingBufferSize (const size_t input_size) - { - auto d = div (input_size, 3); - if (d.rem) - d.quot++; - - return 4 * d.quot; - } - - std::string ToBase64Standard (const std::string& in) + + std::string ToBase64Standard (std::string_view in) { auto len = Base64EncodingBufferSize (in.length ()); char * str = new char[len + 1]; - auto l = ByteStreamToBase64 ((const uint8_t *)in.c_str (), in.length (), str, len); + auto l = ByteStreamToBase64 ((const uint8_t *)in.data (), in.length (), str, len); str[l] = 0; // replace '-' by '+' and '~' by '/' for (size_t i = 0; i < l; i++) diff --git a/libi2pd/Base.h b/libi2pd/Base.h index a163435c..25a4e7aa 100644 --- a/libi2pd/Base.h +++ b/libi2pd/Base.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2023, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -11,27 +11,41 @@ #include #include -#include +#include +#include -namespace i2p { -namespace data { +namespace i2p +{ +namespace data +{ size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len); size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len ); const char * GetBase32SubstitutionTable (); const char * GetBase64SubstitutionTable (); - bool IsBase64 (char ch); + constexpr bool IsBase64 (char ch) + { + return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '-' || ch == '~'; + } size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen); size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen); - bool IsBase32 (char ch); + constexpr bool IsBase32 (char ch) + { + return (ch >= 'a' && ch <= 'z') || (ch >= '2' && ch <= '7'); + } /** * Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes */ - size_t Base64EncodingBufferSize(const size_t input_size); - - std::string ToBase64Standard (const std::string& in); // using standard table, for Proxy-Authorization + constexpr size_t Base64EncodingBufferSize(size_t input_size) + { + auto d = std::div (input_size, 3); + if (d.rem) d.quot++; + return 4 * d.quot; + } + std::string ToBase64Standard (std::string_view in); // using standard table, for Proxy-Authorization + } // data } // i2p From c2f67312967828d27d503a39830c4e9ed46ea71c Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Mar 2025 18:06:12 -0400 Subject: [PATCH 416/527] don't use fixed size buffer for local destination's keys --- libi2pd_client/SAM.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 81b1726d..6c5dd15d 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -470,15 +470,11 @@ namespace client auto session = m_Owner.FindSession(m_ID); if (session) { - uint8_t buf[1024]; - char priv[1024]; - size_t l = session->GetLocalDestination ()->GetPrivateKeys ().ToBuffer (buf, 1024); - size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, priv, 1024); - priv[l1] = 0; + std::string priv = session->GetLocalDestination ()->GetPrivateKeys ().ToBase64 (); #ifdef _MSC_VER - size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv); + size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv.c_str ()); #else - size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv); + size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv.c_str ()); #endif SendMessageReply (m_Buffer, l2, false); } From e0a21cf702179ed7a2f66f12efedf61e8ec03c74 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Mar 2025 20:40:36 -0400 Subject: [PATCH 417/527] use string/string_view for base32 --- libi2pd/Base.cpp | 24 ++++++++++++------------ libi2pd/Base.h | 5 +++-- libi2pd/Blinding.cpp | 7 +++---- libi2pd/Tag.h | 6 ++---- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/libi2pd/Base.cpp b/libi2pd/Base.cpp index 719cdec3..dc331e3e 100644 --- a/libi2pd/Base.cpp +++ b/libi2pd/Base.cpp @@ -261,13 +261,12 @@ namespace data iT64[(int)P64] = 0; } - size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen) + size_t Base32ToByteStream (std::string_view base32Str, uint8_t * outBuf, size_t outLen) { unsigned int tmp = 0, bits = 0; size_t ret = 0; - for (size_t i = 0; i < len; i++) + for (auto ch: base32Str) { - char ch = inBuf[i]; if (ch >= '2' && ch <= '7') // digit ch = (ch - '2') + 26; // 26 means a-z else if (ch >= 'a' && ch <= 'z') @@ -287,13 +286,15 @@ namespace data tmp <<= 5; } return ret; - } - - size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen) + } + + std::string ByteStreamToBase32 (const uint8_t * inBuf, size_t len) { - size_t ret = 0, pos = 1; + std::string out; + out.reserve ((len * 8 + 4) / 5); + size_t pos = 1; unsigned int bits = 8, tmp = inBuf[0]; - while (ret < outLen && (bits > 0 || pos < len)) + while (bits > 0 || pos < len) { if (bits < 5) { @@ -313,10 +314,9 @@ namespace data bits -= 5; int ind = (tmp >> bits) & 0x1F; - outBuf[ret] = (ind < 26) ? (ind + 'a') : ((ind - 26) + '2'); - ret++; + out.push_back ((ind < 26) ? (ind + 'a') : ((ind - 26) + '2')); } - return ret; - } + return out; + } } } diff --git a/libi2pd/Base.h b/libi2pd/Base.h index 25a4e7aa..3bdbe211 100644 --- a/libi2pd/Base.h +++ b/libi2pd/Base.h @@ -27,8 +27,9 @@ namespace data return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '-' || ch == '~'; } - size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen); - size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen); + size_t Base32ToByteStream (std::string_view base32Str, uint8_t * outBuf, size_t outLen); + std::string ByteStreamToBase32 (const uint8_t * inBuf, size_t len); + constexpr bool IsBase32 (char ch) { return (ch >= 'a' && ch <= 'z') || (ch >= '2' && ch <= '7'); diff --git a/libi2pd/Blinding.cpp b/libi2pd/Blinding.cpp index 5266a6eb..a661b428 100644 --- a/libi2pd/Blinding.cpp +++ b/libi2pd/Blinding.cpp @@ -156,7 +156,7 @@ namespace data m_SigType (0) // 0 means invalid, we can't blind DSA, set it later { uint8_t addr[40]; // TODO: define length from b33 - size_t l = i2p::data::Base32ToByteStream (b33.data (), b33.length (), addr, 40); + size_t l = i2p::data::Base32ToByteStream (b33, addr, 40); if (l < 32) { LogPrint (eLogError, "Blinding: Malformed b33 ", b33); @@ -198,7 +198,7 @@ namespace data std::string BlindedPublicKey::ToB33 () const { if (m_PublicKey.size () > 32) return ""; // assume 25519 - uint8_t addr[35]; char str[60]; // TODO: define actual length + uint8_t addr[35]; uint8_t flags = 0; if (m_IsClientAuth) flags |= B33_PER_CLIENT_AUTH_FLAG; addr[0] = flags; // flags @@ -208,8 +208,7 @@ namespace data uint32_t checksum = crc32 (0, addr + 3, m_PublicKey.size ()); // checksum is Little Endian addr[0] ^= checksum; addr[1] ^= (checksum >> 8); addr[2] ^= (checksum >> 16); - auto l = ByteStreamToBase32 (addr, m_PublicKey.size () + 3, str, 60); - return std::string (str, str + l); + return ByteStreamToBase32 (addr, m_PublicKey.size () + 3); } void BlindedPublicKey::GetCredential (uint8_t * credential) const diff --git a/libi2pd/Tag.h b/libi2pd/Tag.h index 92dfd090..af2de154 100644 --- a/libi2pd/Tag.h +++ b/libi2pd/Tag.h @@ -69,14 +69,12 @@ namespace data std::string ToBase32 (size_t len = sz) const { - char str[sz*2]; - size_t l = i2p::data::ByteStreamToBase32 (m_Buf, len, str, sz*2); - return std::string (str, str + l); + return i2p::data::ByteStreamToBase32 (m_Buf, len); } size_t FromBase32 (std::string_view s) { - return i2p::data::Base32ToByteStream (s.data (), s.length (), m_Buf, sz); + return i2p::data::Base32ToByteStream (s, m_Buf, sz); } size_t FromBase64 (std::string_view s) From 93cc810f2987cc90b7a4f8699655af43b36c6c23 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 17 Mar 2025 09:06:11 -0400 Subject: [PATCH 418/527] use string/string_view for base64 --- libi2pd/Base.cpp | 184 ++++++++++++++++++++++++-------------- libi2pd/Base.h | 9 +- libi2pd/Family.cpp | 9 +- libi2pd/Identity.cpp | 32 +++---- libi2pd/Identity.h | 2 +- libi2pd/NetDb.cpp | 4 +- libi2pd/NetDbRequests.cpp | 4 +- libi2pd/RouterInfo.cpp | 12 ++- libi2pd/Tag.h | 6 +- 9 files changed, 142 insertions(+), 120 deletions(-) diff --git a/libi2pd/Base.cpp b/libi2pd/Base.cpp index dc331e3e..bce303a2 100644 --- a/libi2pd/Base.cpp +++ b/libi2pd/Base.cpp @@ -15,7 +15,7 @@ namespace i2p { namespace data { - static const char T32[32] = + static constexpr char T32[32] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', @@ -38,7 +38,7 @@ namespace data * Direct Substitution Table */ - static const char T64[64] = + static constexpr char T64[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', @@ -77,11 +77,11 @@ namespace data * */ - 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 */ + 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; @@ -108,24 +108,24 @@ namespace data { acc_1 = *ps++; acc_2 = (acc_1 << 4) & 0x30; - acc_1 >>= 2; /* base64 digit #1 */ + acc_1 >>= 2; // base64 digit #1 *pd++ = T64[acc_1]; acc_1 = *ps++; - acc_2 |= acc_1 >> 4; /* base64 digit #2 */ + 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 */ + acc_1 |= acc_2 >> 6; // base64 digit #3 *pd++ = T64[acc_1]; - acc_2 &= 0x3f; /* base64 digit #4 */ + 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 */ + 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; @@ -136,13 +136,13 @@ namespace data { acc_1 = *ps++; acc_2 = (acc_1 << 4) & 0x3f; - acc_1 >>= 2; /* base64 digit #1 */ + acc_1 >>= 2; // base64 digit #1 *pd++ = T64[acc_1]; acc_1 = *ps++; - acc_2 |= acc_1 >> 4; /* base64 digit #2 */ + acc_2 |= acc_1 >> 4; // base64 digit #2 *pd++ = T64[acc_2]; acc_1 &= 0x0f; - acc_1 <<= 2; /* base64 digit #3 */ + acc_1 <<= 2; // base64 digit #3 *pd++ = T64[acc_1]; *pd++ = P64; } @@ -150,60 +150,112 @@ namespace data return outCount; } - /* - * - * Base64ToByteStream - * ------------------ - * - * Converts BASE64 encoded data to binary format. If input buffer is - * not properly padded, buffer of negative length is returned - * - */ - - size_t Base64ToByteStream ( /* Number of output bytes */ - const char * InBuffer, /* BASE64 encoded buffer */ - size_t InCount, /* Number of input bytes */ - uint8_t * OutBuffer, /* output buffer length */ - size_t len /* length of output buffer */ + std::string ByteStreamToBase64 (// base64 encoded string + const uint8_t * InBuffer, // Input buffer, binary data + size_t InCount // Number of bytes in the input buffer ) { unsigned char * ps; - unsigned char * pd; unsigned char acc_1; unsigned char acc_2; int i; int n; int m; + + ps = (unsigned char *)InBuffer; + n = InCount / 3; + m = InCount % 3; + size_t outCount = m ? (4 * (n + 1)) : (4 * n); + + std::string out; + out.reserve (outCount); + for ( i = 0; i < n; i++ ) + { + acc_1 = *ps++; + acc_2 = (acc_1 << 4) & 0x30; + acc_1 >>= 2; // base64 digit #1 + out.push_back (T64[acc_1]); + acc_1 = *ps++; + acc_2 |= acc_1 >> 4; // base64 digit #2 + out.push_back (T64[acc_2]); + acc_1 &= 0x0f; + acc_1 <<= 2; + acc_2 = *ps++; + acc_1 |= acc_2 >> 6; // base64 digit #3 + out.push_back (T64[acc_1]); + acc_2 &= 0x3f; // base64 digit #4 + out.push_back (T64[acc_2]); + } + if ( m == 1 ) + { + acc_1 = *ps++; + acc_2 = (acc_1 << 4) & 0x3f; // base64 digit #2 + acc_1 >>= 2; // base64 digit #1 + out.push_back (T64[acc_1]); + out.push_back (T64[acc_2]); + out.push_back (P64); + out.push_back (P64); + + } + else if ( m == 2 ) + { + acc_1 = *ps++; + acc_2 = (acc_1 << 4) & 0x3f; + acc_1 >>= 2; // base64 digit #1 + out.push_back (T64[acc_1]); + acc_1 = *ps++; + acc_2 |= acc_1 >> 4; // base64 digit #2 + out.push_back (T64[acc_2]); + acc_1 &= 0x0f; + acc_1 <<= 2; // base64 digit #3 + out.push_back (T64[acc_1]); + out.push_back (P64); + } + + return out; + } + + /* + * + * Base64ToByteStream + * ------------------ + * + * Converts BASE64 encoded string to binary format. If input buffer is + * not properly padded, buffer of negative length is returned + * + */ + size_t Base64ToByteStream ( // Number of output bytes + std::string_view base64Str, // BASE64 encoded string + uint8_t * OutBuffer, // output buffer length + size_t len // length of output buffer + ) + { + unsigned char * pd; + unsigned char acc_1; + unsigned char acc_2; size_t outCount; - if (isFirstTime) - iT64Build(); - - n = InCount / 4; - m = InCount % 4; - - if (InCount && !m) - outCount = 3 * n; + if (base64Str.empty () || base64Str[0] == P64) return 0; + auto d = std::div (base64Str.length (), 4); + if (!d.rem) + outCount = 3 * d.quot; else return 0; - if(*InBuffer == P64) - return 0; - - ps = (unsigned char *)(InBuffer + InCount - 1); - while ( *ps-- == P64 ) - outCount--; - ps = (unsigned char *)InBuffer; - - if (outCount > len) - return 0; + if (isFirstTime) iT64Build(); + auto pos = base64Str.find_last_not_of (P64); + if (pos == base64Str.npos) return 0; + outCount -= (base64Str.length () - pos - 1); + if (outCount > len) return 0; + + auto ps = base64Str.begin (); pd = OutBuffer; auto endOfOutBuffer = OutBuffer + outCount; - for ( i = 0; i < n; i++ ) + for (int i = 0; i < d.quot; i++) { - acc_1 = iT64[*ps++]; - acc_2 = iT64[*ps++]; + acc_1 = iT64[int(*ps++)]; + acc_2 = iT64[int(*ps++)]; acc_1 <<= 2; acc_1 |= acc_2 >> 4; *pd++ = acc_1; @@ -211,36 +263,30 @@ namespace data break; acc_2 <<= 4; - acc_1 = iT64[*ps++]; + acc_1 = iT64[int(*ps++)]; acc_2 |= acc_1 >> 2; *pd++ = acc_2; if (pd >= endOfOutBuffer) break; - acc_2 = iT64[*ps++]; + acc_2 = iT64[int(*ps++)]; acc_2 |= acc_1 << 6; *pd++ = acc_2; } return outCount; - } + } std::string ToBase64Standard (std::string_view in) { - auto len = Base64EncodingBufferSize (in.length ()); - char * str = new char[len + 1]; - auto l = ByteStreamToBase64 ((const uint8_t *)in.data (), in.length (), str, len); - str[l] = 0; + auto str = ByteStreamToBase64 ((const uint8_t *)in.data (), in.length ()); // replace '-' by '+' and '~' by '/' - for (size_t i = 0; i < l; i++) - if (str[i] == '-') - str[i] = '+'; - else if (str[i] == '~') - str[i] = '/'; - - std::string s(str); - delete[] str; - return s; + for (auto& ch: str) + if (ch == '-') + ch = '+'; + else if (ch == '~') + ch = '/'; + return str; } /* diff --git a/libi2pd/Base.h b/libi2pd/Base.h index 3bdbe211..c14abac7 100644 --- a/libi2pd/Base.h +++ b/libi2pd/Base.h @@ -18,8 +18,10 @@ namespace i2p { namespace data { - size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len); - size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len ); + 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); + const char * GetBase32SubstitutionTable (); const char * GetBase64SubstitutionTable (); constexpr bool IsBase64 (char ch) @@ -28,8 +30,7 @@ namespace data } size_t Base32ToByteStream (std::string_view base32Str, uint8_t * outBuf, size_t outLen); - std::string ByteStreamToBase32 (const uint8_t * inBuf, size_t len); - + std::string ByteStreamToBase32 (const uint8_t * inBuf, size_t len); constexpr bool IsBase32 (char ch) { return (ch >= 'a' && ch <= 'z') || (ch >= '2' && ch <= '7'); diff --git a/libi2pd/Family.cpp b/libi2pd/Family.cpp index f8cf9c0a..300a50ab 100644 --- a/libi2pd/Family.cpp +++ b/libi2pd/Family.cpp @@ -105,7 +105,7 @@ namespace data memcpy (buf, family.c_str (), len); memcpy (buf + len, (const uint8_t *)ident, 32); len += 32; - auto signatureBufLen = Base64ToByteStream (signature.data (), signature.length (), signatureBuf, 64); + auto signatureBufLen = Base64ToByteStream (signature, signatureBuf, 64); if (signatureBufLen) { EVP_MD_CTX * ctx = EVP_MD_CTX_create (); @@ -154,12 +154,7 @@ namespace data memcpy (buf + len, (const uint8_t *)ident, 32); len += 32; signer.Sign (buf, len, signature); - len = Base64EncodingBufferSize (64); - char * b64 = new char[len+1]; - len = ByteStreamToBase64 (signature, 64, b64, len); - b64[len] = 0; - sig = b64; - delete[] b64; + sig = ByteStreamToBase64 (signature, 64); } else LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 93d7ec08..e98e5fbc 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -271,21 +271,17 @@ namespace data size_t IdentityEx::FromBase64(std::string_view s) { - const size_t slen = s.length(); - std::vector buf(slen); // binary data can't exceed base64 - const size_t len = Base64ToByteStream (s.data(), slen, buf.data(), slen); + std::vector buf(s.length ()); // binary data can't exceed base64 + auto len = Base64ToByteStream (s, buf.data(), buf.size ()); return FromBuffer (buf.data(), len); } std::string IdentityEx::ToBase64 () const { const size_t bufLen = GetFullLen(); - const size_t strLen = Base64EncodingBufferSize(bufLen); std::vector buf(bufLen); - std::vector str(strLen); size_t l = ToBuffer (buf.data(), bufLen); - size_t l1 = i2p::data::ByteStreamToBase64 (buf.data(), l, str.data(), strLen); - return std::string (str.data(), l1); + return i2p::data::ByteStreamToBase64 (buf.data(), l); } size_t IdentityEx::GetSigningPublicKeyLen () const @@ -570,26 +566,18 @@ namespace data return ret; } - size_t PrivateKeys::FromBase64(const std::string& s) + size_t PrivateKeys::FromBase64(std::string_view s) { - uint8_t * buf = new uint8_t[s.length ()]; - size_t l = i2p::data::Base64ToByteStream (s.c_str (), s.length (), buf, s.length ()); - size_t ret = FromBuffer (buf, l); - delete[] buf; - return ret; + std::vector buf(s.length ()); + size_t l = i2p::data::Base64ToByteStream (s, buf.data (), buf.size ()); + return FromBuffer (buf.data (), l); } std::string PrivateKeys::ToBase64 () const { - uint8_t * buf = new uint8_t[GetFullLen ()]; - char * str = new char[GetFullLen ()*2]; - size_t l = ToBuffer (buf, GetFullLen ()); - size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, str, GetFullLen ()*2); - str[l1] = 0; - delete[] buf; - std::string ret(str); - delete[] str; - return ret; + std::vector buf(GetFullLen ()); + size_t l = ToBuffer (buf.data (), buf.size ()); + return i2p::data::ByteStreamToBase64 (buf.data (), l); } void PrivateKeys::Sign (const uint8_t * buf, int len, uint8_t * signature) const diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index cf1dbfcd..e08ac802 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -164,7 +164,7 @@ namespace data size_t FromBuffer (const uint8_t * buf, size_t len); size_t ToBuffer (uint8_t * buf, size_t len) const; - size_t FromBase64(const std::string& s); + size_t FromBase64(std::string_view s); std::string ToBase64 () const; std::shared_ptr CreateDecryptor (const uint8_t * key) const; diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 7f6882c4..2bfaa8d8 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -951,9 +951,7 @@ namespace data LogPrint (eLogError, "NetDb: DatabaseLookup for zero ident. Ignored"); return; } - char key[48]; - int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48); - key[l] = 0; + auto key = i2p::data::ByteStreamToBase64 (buf, 32); IdentHash replyIdent(buf + 32); uint8_t flag = buf[64]; diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index f8c5037c..0648d6bf 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -360,9 +360,7 @@ namespace data void NetDbRequests::HandleDatabaseSearchReplyMsg (std::shared_ptr msg) { const uint8_t * buf = msg->GetPayload (); - char key[48]; - int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48); - key[l] = 0; + auto key = i2p::data::ByteStreamToBase64 (buf, 32); size_t num = buf[32]; // num LogPrint (eLogDebug, "NetDbReq: DatabaseSearchReply for ", key, " num=", num); IdentHash ident (buf); diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index f5ed27e6..41f71e14 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -281,7 +281,7 @@ namespace data address->caps = ExtractAddressCaps (value); else if (key == "s") // ntcp2 or ssu2 static key { - if (Base64ToByteStream (value.data (), value.length (), address->s, 32) == 32 && + if (Base64ToByteStream (value, address->s, 32) == 32 && !(address->s[31] & 0x80)) // check if x25519 public key isStaticKey = true; else @@ -291,14 +291,14 @@ namespace data { if (address->IsNTCP2 ()) { - if (Base64ToByteStream (value.data (), value.length (), address->i, 16) == 16) + if (Base64ToByteStream (value, address->i, 16) == 16) address->published = true; // presence of "i" means "published" NTCP2 else address->transportStyle = eTransportUnknown; // invalid address } else if (address->IsSSU2 ()) { - if (Base64ToByteStream (value.data (), value.length (), address->i, 32) == 32) + if (Base64ToByteStream (value, address->i, 32) == 32) isIntroKey = true; else address->transportStyle = eTransportUnknown; // invalid address @@ -343,7 +343,7 @@ namespace data LogPrint (eLogWarning, "RouterInfo: 'itag' conversion error: ", std::make_error_code (res.ec).message ()); } else if (key1 == "ih") - Base64ToByteStream (value.data (), value.length (), introducer.iH, 32); + Base64ToByteStream (value, introducer.iH, 32); else if (key1 == "iexp") { auto res = std::from_chars(value.data(), value.data() + value.size(), introducer.iExp); @@ -1394,9 +1394,7 @@ namespace data if (!introducer.iTag) continue; WriteString ("ih" + std::to_string(i), properties); properties << '='; - char value[64]; - size_t l = ByteStreamToBase64 (introducer.iH, 32, value, 64); - value[l] = 0; + auto value = ByteStreamToBase64 (introducer.iH, 32); WriteString (value, properties); properties << ';'; i++; diff --git a/libi2pd/Tag.h b/libi2pd/Tag.h index af2de154..30b7708d 100644 --- a/libi2pd/Tag.h +++ b/libi2pd/Tag.h @@ -62,9 +62,7 @@ namespace data std::string ToBase64 (size_t len = sz) const { - char str[sz*2]; - size_t l = i2p::data::ByteStreamToBase64 (m_Buf, len, str, sz*2); - return std::string (str, str + l); + return i2p::data::ByteStreamToBase64 (m_Buf, len); } std::string ToBase32 (size_t len = sz) const @@ -79,7 +77,7 @@ namespace data size_t FromBase64 (std::string_view s) { - return i2p::data::Base64ToByteStream (s.data (), s.length (), m_Buf, sz); + return i2p::data::Base64ToByteStream (s, m_Buf, sz); } uint8_t GetBit (int i) const From 9cc625b19eeb50602ae2232ca7dc034642ded7ec Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 17 Mar 2025 10:16:05 -0400 Subject: [PATCH 419/527] fixed warning --- libi2pd/Base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Base.h b/libi2pd/Base.h index c14abac7..daf0f7ed 100644 --- a/libi2pd/Base.h +++ b/libi2pd/Base.h @@ -39,7 +39,7 @@ namespace data /** * Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes */ - constexpr size_t Base64EncodingBufferSize(size_t input_size) + inline size_t Base64EncodingBufferSize(size_t input_size) { auto d = std::div (input_size, 3); if (d.rem) d.quot++; From 8e6b9370d04b7938d1bdb02d3c0e1496d47f638d Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 17 Mar 2025 19:00:48 -0400 Subject: [PATCH 420/527] use ToBase64 for incoming stream accept --- libi2pd_client/SAM.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 6c5dd15d..3114bb5a 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -1112,18 +1112,19 @@ namespace client } } if (!m_IsSilent) - { - // get remote peer address - auto ident_ptr = stream->GetRemoteIdentity(); - const size_t ident_len = ident_ptr->GetFullLen(); - uint8_t* ident = new uint8_t[ident_len]; - - // send remote peer address as base64 - const size_t l = ident_ptr->ToBuffer (ident, ident_len); - const size_t l1 = i2p::data::ByteStreamToBase64 (ident, l, (char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE); - delete[] ident; - m_StreamBuffer[l1] = '\n'; - HandleI2PReceive (boost::system::error_code (), l1 +1); // we send identity like it has been received from stream + { + if (m_SocketType != eSAMSocketTypeTerminated) + { + // get remote peer address + auto ident = std::make_shared(stream->GetRemoteIdentity()->ToBase64 ()); // we need to keep it until sent + ident->push_back ('\n'); + // send remote peer address back to client like received from stream + boost::asio::async_write (m_Socket, boost::asio::buffer (ident->data (), ident->size ()), boost::asio::transfer_all(), + [ident, s = shared_from_this ()](const boost::system::error_code& ecode, size_t bytes_transferred) + { + s->HandleWriteI2PData (ecode, bytes_transferred); + }); + } } else I2PReceive (); From bbf5c1655a5f331b36cc7e16ad0bba86bb36eed4 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 17 Mar 2025 19:05:10 -0400 Subject: [PATCH 421/527] ByteStreamToBase64 always returns std::string --- daemon/HTTPServer.cpp | 5 +-- libi2pd/Base.cpp | 78 +------------------------------------------ libi2pd/Base.h | 1 - 3 files changed, 2 insertions(+), 82 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index f10bd1e2..dca545fe 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -1419,13 +1419,11 @@ namespace http { { auto signatureLen = dest->GetIdentity ()->GetSignatureLen (); uint8_t * signature = new uint8_t[signatureLen]; - char * sig = new char[signatureLen*2]; std::stringstream out; out << name << "=" << dest->GetIdentity ()->ToBase64 (); dest->Sign ((uint8_t *)out.str ().c_str (), out.str ().length (), signature); - auto len = i2p::data::ByteStreamToBase64 (signature, signatureLen, sig, signatureLen*2); - sig[len] = 0; + auto sig = i2p::data::ByteStreamToBase64 (signature, signatureLen); out << "#!sig=" << sig; s << "" << tr("SUCCESS") << ":
    \r\n
    \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 422/527] 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 423/527] 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 424/527] 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 425/527] 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 426/527] 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 427/527] 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 428/527] 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 429/527] 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 430/527] 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 431/527] 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 432/527] 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 433/527] 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 434/527] 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 435/527] 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 436/527] 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 437/527] 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 438/527] 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 439/527] 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 440/527] 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 441/527] 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 442/527] 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 443/527] 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 444/527] 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 445/527] 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 446/527] 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 447/527] 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 448/527] 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 449/527] 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 450/527] [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 451/527] 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 452/527] 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 453/527] 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 454/527] 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 455/527] 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 456/527] 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 457/527] 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 458/527] 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 459/527] 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 460/527] 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 461/527] 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 462/527] 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 463/527] 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 464/527] 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 465/527] 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 466/527] 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 467/527] 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 468/527] 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 469/527] 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 470/527] [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 471/527] 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 472/527] 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 473/527] 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 474/527] 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 475/527] 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 476/527] 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 477/527] 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/," From fdbf4366ebaf9857edcb1a932193259a57749097 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 28 Apr 2025 20:41:36 -0400 Subject: [PATCH 478/527] remove reseed.memcpy.io --- .../reseed/hottuna_at_mail.i2p.crt | 33 ------------------- libi2pd/Config.cpp | 1 - 2 files changed, 34 deletions(-) delete mode 100644 contrib/certificates/reseed/hottuna_at_mail.i2p.crt diff --git a/contrib/certificates/reseed/hottuna_at_mail.i2p.crt b/contrib/certificates/reseed/hottuna_at_mail.i2p.crt deleted file mode 100644 index d0ff7c33..00000000 --- a/contrib/certificates/reseed/hottuna_at_mail.i2p.crt +++ /dev/null @@ -1,33 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFxzCCA6+gAwIBAgIQZfqn0yiJL3dGgCjeOeWS6DANBgkqhkiG9w0BAQsFADBw -MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK -ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEZMBcGA1UEAwwQ -aG90dHVuYUBtYWlsLmkycDAeFw0xNjExMDkwMzE1MzJaFw0yNjExMDkwMzE1MzJa -MHAxCzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxHjAcBgNV -BAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRkwFwYDVQQD -DBBob3R0dW5hQG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC -AgEA21Bfgcc9VVH4l2u1YvYlTw2OPUyQb16X2IOW0PzdsUO5W78Loueu974BkiKi -84lQZanLr0OwEopdfutGc6gegSLmwaWx5YCG5uwpLOPkDiObfX+nptH6As/B1cn+ -mzejYdVKRnWd7EtHW0iseSsILBK1YbGw4AGpXJ8k18DJSzUt2+spOkpBW6XqectN -8y2JDSTns8yiNxietVeRN/clolDXT9ZwWHkd+QMHTKhgl3Uz1knOffU0L9l4ij4E -oFgPfQo8NL63kLM24hF1hM/At7XvE4iOlObFwPXE+H5EGZpT5+A7Oezepvd/VMzM -tCJ49hM0OlR393tKFONye5GCYeSDJGdPEB6+rBptpRrlch63tG9ktpCRrg2wQWgC -e3aOE1xVRrmwiTZ+jpfsOCbZrrSA/C4Bmp6AfGchyHuDGGkRU/FJwa1YLJe0dkWG -ITLWeh4zeVuAS5mctdv9NQ5wflSGz9S8HjsPBS5+CDOFHh4cexXRG3ITfk6aLhuY -KTMlkIO4SHKmnwAvy1sFlsqj6PbfVjpHPLg625fdNxBpe57TLxtIdBB3C7ccQSRW -+UG6Cmbcmh80PbsSR132NLMlzLhbaOjxeCWWJRo6cLuHBptAFMNwqsXt8xVf9M0N -NdJoKUmblyvjnq0N8aMEqtQ1uGMTaCB39cutHQq+reD/uzsCAwEAAaNdMFswDgYD -VR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNV -HRMBAf8EBTADAQH/MBkGA1UdDgQSBBBob3R0dW5hQG1haWwuaTJwMA0GCSqGSIb3 -DQEBCwUAA4ICAQCibFV8t4pajP176u3jx31x1kgqX6Nd+0YFARPZQjq99kUyoZer -GyHGsMWgM281RxiZkveHxR7Hm7pEd1nkhG3rm+d7GdJ2p2hujr9xUvl0zEqAAqtm -lkYI6uJ13WBjFc9/QuRIdeIeSUN+eazSXNg2nJhoV4pF9n2Q2xDc9dH4GWO93cMX -JPKVGujT3s0b7LWsEguZBPdaPW7wwZd902Cg/M5fE1hZQ8/SIAGUtylb/ZilVeTS -spxWP1gX3NT1SSvv0s6oL7eADCgtggWaMxEjZhi6WMnPUeeFY8X+6trkTlnF9+r/ -HiVvvzQKrPPtB3j1xfQCAF6gUKN4iY+2AOExv4rl/l+JJbPhpd/FuvD8AVkLMZ8X -uPe0Ew2xv30cc8JjGDzQvoSpBmVTra4f+xqH+w8UEmxnx97Ye2aUCtnPykACnFte -oT97K5052B1zq+4fu4xaHZnEzPYVK5POzOufNLPgciJsWrR5GDWtHd+ht/ZD37+b -+j1BXpeBWUBQgluFv+lNMVNPJxc2OMELR1EtEwXD7mTuuUEtF5Pi63IerQ5LzD3G -KBvXhMB0XhpE6WG6pBwAvkGf5zVv/CxClJH4BQbdZwj9HYddfEQlPl0z/XFR2M0+ -9/8nBfGSPYIt6KeHBCeyQWTdE9gqSzMwTMFsennXmaT8gyc7eKqKF6adqw== ------END CERTIFICATE----- diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index bd9329a1..939cd9ff 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -234,7 +234,6 @@ namespace config { "https://reseed2.i2p.net/," "https://reseed.diva.exchange/," "https://reseed-fr.i2pd.xyz/," - "https://reseed.memcpy.io/," "https://reseed.onion.im/," "https://i2pseed.creativecowpat.net:8443/," "https://reseed.i2pgit.org/," From b03ec650eff99b3b1dcd0960eaf6b7eba88dfef5 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 29 Apr 2025 12:56:35 -0400 Subject: [PATCH 479/527] keep receving new data from socket while previous is being sent to stream --- libi2pd_client/I2PTunnel.cpp | 22 +++++++++++++++------- libi2pd_client/I2PTunnel.h | 1 + 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index d6436c78..ae9849db 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -32,7 +32,8 @@ namespace client I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, std::shared_ptr leaseSet, uint16_t port): - I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()) + I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()), + m_IsReceiving (false) { m_Stream = GetOwner()->GetLocalDestination ()->CreateStream (leaseSet, port); } @@ -40,13 +41,13 @@ namespace client I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, std::shared_ptr stream): I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream), - m_RemoteEndpoint (socket->remote_endpoint ()) + m_RemoteEndpoint (socket->remote_endpoint ()), m_IsReceiving (false) { } I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr stream, const boost::asio::ip::tcp::endpoint& target,std::shared_ptr sslCtx): - I2PServiceHandler(owner), m_Stream (stream), m_RemoteEndpoint (target) + I2PServiceHandler(owner), m_Stream (stream), m_RemoteEndpoint (target), m_IsReceiving (false) { m_Socket = std::make_shared (owner->GetService ()); if (sslCtx) @@ -149,18 +150,23 @@ namespace client void I2PTunnelConnection::Receive () { + if (m_IsReceiving) return; // already receiving + size_t unsentSize = m_Stream ? m_Stream->GetSendBufferSize () : 0; + if (unsentSize >= I2P_TUNNEL_CONNECTION_BUFFER_SIZE) return; // buffer is full + m_IsReceiving = true; if (m_SSL) - m_SSL->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), + m_SSL->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE - unsentSize), std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); else - m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), + m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE - unsentSize), std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } void I2PTunnelConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) { + m_IsReceiving = false; if (ecode) { if (ecode != boost::asio::error::operation_aborted) @@ -170,16 +176,18 @@ namespace client } } else + { WriteToStream (m_Buffer, bytes_transferred); + Receive (); // try to receive more while being sent to stream + } } void I2PTunnelConnection::WriteToStream (const uint8_t * buf, size_t len) { if (m_Stream) { - auto s = shared_from_this (); m_Stream->AsyncSend (buf, len, - [s](const boost::system::error_code& ecode) + [s = shared_from_this ()](const boost::system::error_code& ecode) { if (!ecode) s->Receive (); diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index 7d4c3400..be35cfec 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -82,6 +82,7 @@ namespace client std::shared_ptr > m_SSL; std::shared_ptr m_Stream; boost::asio::ip::tcp::endpoint m_RemoteEndpoint; + bool m_IsReceiving; }; class I2PClientTunnelConnectionHTTP: public I2PTunnelConnection From d9f64c6f51e341d913f2512e2e7f7d66c0527c55 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 1 May 2025 18:09:39 -0400 Subject: [PATCH 480/527] connection max stream buffer size --- libi2pd_client/I2PTunnel.cpp | 6 +++--- libi2pd_client/I2PTunnel.h | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index ae9849db..4d818e60 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -152,7 +152,7 @@ namespace client { if (m_IsReceiving) return; // already receiving size_t unsentSize = m_Stream ? m_Stream->GetSendBufferSize () : 0; - if (unsentSize >= I2P_TUNNEL_CONNECTION_BUFFER_SIZE) return; // buffer is full + if (unsentSize >= I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE) return; // buffer is full m_IsReceiving = true; if (m_SSL) m_SSL->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE - unsentSize), @@ -216,7 +216,7 @@ namespace client if (m_Stream->GetStatus () == i2p::stream::eStreamStatusNew || m_Stream->GetStatus () == i2p::stream::eStreamStatusOpen) // regular { - m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), + m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_STREAM_BUFFER_SIZE), std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2), I2P_TUNNEL_CONNECTION_MAX_IDLE); @@ -224,7 +224,7 @@ namespace client else // closed by peer { // get remaining data - auto len = m_Stream->ReadSome (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE); + auto len = m_Stream->ReadSome (m_StreamBuffer, I2P_TUNNEL_CONNECTION_STREAM_BUFFER_SIZE); if (len > 0) // still some data Write (m_StreamBuffer, len); else // no more data diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index be35cfec..9abae09a 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -27,7 +27,9 @@ namespace i2p { namespace client { - const size_t I2P_TUNNEL_CONNECTION_BUFFER_SIZE = 16384; + constexpr size_t I2P_TUNNEL_CONNECTION_BUFFER_SIZE = 8192; + constexpr size_t I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE = 8*I2P_TUNNEL_CONNECTION_BUFFER_SIZE; + constexpr size_t I2P_TUNNEL_CONNECTION_STREAM_BUFFER_SIZE = 16384; const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds // for HTTP tunnels @@ -77,7 +79,7 @@ namespace client private: - uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE]; + uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_STREAM_BUFFER_SIZE]; std::shared_ptr m_Socket; std::shared_ptr > m_SSL; std::shared_ptr m_Stream; From 855e111bd011b87d5126a2040d3a324798576043 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 2 May 2025 08:32:20 -0400 Subject: [PATCH 481/527] fixed private key size and publishing for crypto type 1 --- libi2pd/CryptoKey.h | 2 +- libi2pd/Destination.cpp | 17 ++--------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/libi2pd/CryptoKey.h b/libi2pd/CryptoKey.h index b6c37ddf..099bdd56 100644 --- a/libi2pd/CryptoKey.h +++ b/libi2pd/CryptoKey.h @@ -165,7 +165,7 @@ namespace crypto 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_P256_SHA256_AES256CBC: return 256; // actual size is 32, but we use 256 for compatibility with old keys files case i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: return 32; // ML-KEM hybrid case i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD: diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index fd23e228..b243ba0a 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -728,22 +728,9 @@ namespace client { if (m_PublishReplyToken) { + LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " milliseconds or failed. will try again"); m_PublishReplyToken = 0; - if (GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) - { - LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " milliseconds or failed. will try again"); - Publish (); - } - else - { - LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " milliseconds from Java floodfill for crypto type ", (int)GetIdentity ()->GetCryptoKeyType ()); - // Java floodfill never sends confirmation back for unknown crypto type - // assume it successive and try to verify - m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT + PUBLISH_VERIFICATION_TIMEOUT_VARIANCE)); // always max - m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, - shared_from_this (), std::placeholders::_1)); - - } + Publish (); } } } From 0cbada2196f44a3ed5972569568b58d3dfc205ce Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 2 May 2025 13:23:53 -0400 Subject: [PATCH 482/527] correct receive buffer size --- libi2pd_client/I2PTunnel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 4d818e60..c06a35a0 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -155,11 +155,11 @@ namespace client if (unsentSize >= I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE) return; // buffer is full m_IsReceiving = true; if (m_SSL) - m_SSL->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE - unsentSize), + m_SSL->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); else - m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE - unsentSize), + m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } From 539cd5a656d937e3bab94744c74ed718f91af2ec Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 2 May 2025 13:36:59 -0400 Subject: [PATCH 483/527] max i2p stream buffer size --- libi2pd_client/SAM.cpp | 45 ++++++++++++++++++++++++------------------ libi2pd_client/SAM.h | 7 +++++-- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 2c0f8d92..7ec94dcb 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -27,7 +27,7 @@ namespace client m_Owner (owner), m_Socket(owner.GetService()), m_Timer (m_Owner.GetService ()), m_BufferOffset (0), m_SocketType (eSAMSocketTypeUnknown), m_IsSilent (false), - m_IsAccepting (false), m_Stream (nullptr) + m_IsAccepting (false), m_IsReceiving (false) { } @@ -944,13 +944,23 @@ namespace client void SAMSocket::Receive () { - m_Socket.async_read_some (boost::asio::buffer(m_Buffer + m_BufferOffset, SAM_SOCKET_BUFFER_SIZE - m_BufferOffset), - std::bind((m_SocketType == eSAMSocketTypeStream) ? &SAMSocket::HandleReceived : &SAMSocket::HandleMessage, - shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + if (m_SocketType == eSAMSocketTypeStream) + { + if (m_IsReceiving) return; + size_t unsentSize = m_Stream ? m_Stream->GetSendBufferSize () : 0; + if (unsentSize >= SAM_STREAM_MAX_SEND_BUFFER_SIZE) return; // buffer is full + m_IsReceiving = true; + m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), + std::bind(&SAMSocket::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + else + m_Socket.async_read_some (boost::asio::buffer(m_Buffer + m_BufferOffset, SAM_SOCKET_BUFFER_SIZE - m_BufferOffset), + std::bind(&SAMSocket::HandleMessage, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } void SAMSocket::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { + m_IsReceiving = false; if (ecode) { LogPrint (eLogError, "SAM: Read error: ", ecode.message ()); @@ -960,16 +970,13 @@ namespace client else { if (m_Stream) - { - bytes_transferred += m_BufferOffset; - m_BufferOffset = 0; + { m_Stream->AsyncSend ((uint8_t *)m_Buffer, bytes_transferred, std::bind(&SAMSocket::HandleStreamSend, shared_from_this(), std::placeholders::_1)); - } + Receive (); + } else - { Terminate("No Stream Remaining"); - } } } @@ -980,16 +987,16 @@ namespace client if (m_Stream->GetStatus () == i2p::stream::eStreamStatusNew || m_Stream->GetStatus () == i2p::stream::eStreamStatusOpen) // regular { - m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE), + m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, SAM_STREAM_BUFFER_SIZE), std::bind (&SAMSocket::HandleI2PReceive, shared_from_this(), std::placeholders::_1, std::placeholders::_2), SAM_SOCKET_CONNECTION_MAX_IDLE); } else // closed by peer { - uint8_t * buff = new uint8_t[SAM_SOCKET_BUFFER_SIZE]; + uint8_t * buff = new uint8_t[SAM_STREAM_BUFFER_SIZE]; // get remaining data - auto len = m_Stream->ReadSome (buff, SAM_SOCKET_BUFFER_SIZE); + auto len = m_Stream->ReadSome (buff, SAM_STREAM_BUFFER_SIZE); if (len > 0) // still some data { WriteI2PDataImmediate(buff, len); @@ -1186,11 +1193,11 @@ namespace client else { #ifdef _MSC_VER - size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (long unsigned int)len); + size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_STREAM_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (long unsigned int)len); #else - size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (long unsigned int)len); + size_t l = snprintf ((char *)m_StreamBuffer, SAM_STREAM_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (long unsigned int)len); #endif - if (len < SAM_SOCKET_BUFFER_SIZE - l) + if (len < SAM_STREAM_BUFFER_SIZE - l) { memcpy (m_StreamBuffer + l, buf, len); WriteI2PData(len + l); @@ -1214,11 +1221,11 @@ namespace client else { #ifdef _MSC_VER - size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_RAW_RECEIVED, (long unsigned int)len); + size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_STREAM_BUFFER_SIZE, SAM_RAW_RECEIVED, (long unsigned int)len); #else - size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_RAW_RECEIVED, (long unsigned int)len); + size_t l = snprintf ((char *)m_StreamBuffer, SAM_STREAM_BUFFER_SIZE, SAM_RAW_RECEIVED, (long unsigned int)len); #endif - if (len < SAM_SOCKET_BUFFER_SIZE - l) + if (len < SAM_STREAM_BUFFER_SIZE - l) { memcpy (m_StreamBuffer + l, buf, len); WriteI2PData(len + l); diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 1886324a..cd619678 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -29,6 +29,8 @@ namespace i2p namespace client { const size_t SAM_SOCKET_BUFFER_SIZE = 8192; + const size_t SAM_STREAM_BUFFER_SIZE = 16384; + const size_t SAM_STREAM_MAX_SEND_BUFFER_SIZE = 8*SAM_SOCKET_BUFFER_SIZE; const int SAM_SOCKET_CONNECTION_MAX_IDLE = 3600; // in seconds const int SAM_SESSION_READINESS_CHECK_INTERVAL = 3; // in seconds const size_t SAM_SESSION_MAX_ACCEPT_QUEUE_SIZE = 50; @@ -170,12 +172,13 @@ namespace client Socket_t m_Socket; boost::asio::deadline_timer m_Timer; char m_Buffer[SAM_SOCKET_BUFFER_SIZE + 1]; - size_t m_BufferOffset; - uint8_t m_StreamBuffer[SAM_SOCKET_BUFFER_SIZE]; + size_t m_BufferOffset; // for session only + uint8_t m_StreamBuffer[SAM_STREAM_BUFFER_SIZE]; SAMSocketType m_SocketType; std::string m_ID; // nickname bool m_IsSilent; bool m_IsAccepting; // for eSAMSocketTypeAcceptor only + bool m_IsReceiving; // for eSAMSocketTypeStream only std::shared_ptr m_Stream; }; From aece5bb16c3877fcafe29239ca15856f0057ce35 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 3 May 2025 08:47:49 -0400 Subject: [PATCH 484/527] don't exceed stream max send buffer size --- libi2pd_client/I2PTunnel.cpp | 12 +++++++++--- libi2pd_client/SAM.cpp | 10 ++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index c06a35a0..82a6ed03 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -151,15 +151,21 @@ namespace client void I2PTunnelConnection::Receive () { if (m_IsReceiving) return; // already receiving + size_t bufSize = I2P_TUNNEL_CONNECTION_BUFFER_SIZE; size_t unsentSize = m_Stream ? m_Stream->GetSendBufferSize () : 0; - if (unsentSize >= I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE) return; // buffer is full + if (unsentSize) + { + if (unsentSize >= I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE) return; // buffer is full + if (unsentSize > I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE - I2P_TUNNEL_CONNECTION_BUFFER_SIZE) + bufSize = I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE - unsentSize; + } m_IsReceiving = true; if (m_SSL) - m_SSL->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), + m_SSL->async_read_some (boost::asio::buffer(m_Buffer, bufSize), std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); else - m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), + m_Socket->async_read_some (boost::asio::buffer(m_Buffer, bufSize), std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 7ec94dcb..f0df414c 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -947,10 +947,16 @@ namespace client if (m_SocketType == eSAMSocketTypeStream) { if (m_IsReceiving) return; + size_t bufSize = SAM_SOCKET_BUFFER_SIZE; size_t unsentSize = m_Stream ? m_Stream->GetSendBufferSize () : 0; - if (unsentSize >= SAM_STREAM_MAX_SEND_BUFFER_SIZE) return; // buffer is full + if (unsentSize) + { + if (unsentSize >= SAM_STREAM_MAX_SEND_BUFFER_SIZE) return; // buffer is full + if (unsentSize > SAM_STREAM_MAX_SEND_BUFFER_SIZE - SAM_SOCKET_BUFFER_SIZE) + bufSize = SAM_STREAM_MAX_SEND_BUFFER_SIZE - unsentSize; + } m_IsReceiving = true; - m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), + m_Socket.async_read_some (boost::asio::buffer(m_Buffer, bufSize), std::bind(&SAMSocket::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } else From 0d278d2ae58dea13ec7d82dee24184975c513bb8 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 3 May 2025 13:09:06 -0400 Subject: [PATCH 485/527] probing resistance --- libi2pd/NTCP2.cpp | 17 +++++++++++++++-- libi2pd/NTCP2.h | 3 ++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index b3a51488..bc18f5a6 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -528,6 +528,7 @@ namespace transport } else { + m_Establisher->CreateEphemeralKey (); boost::asio::post (m_Server.GetEstablisherService (), [s = shared_from_this (), bytes_transferred] () { @@ -566,7 +567,7 @@ namespace transport SendSessionCreated (); } else - boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + ReadSomethingAndTerminate (); // probing resistance } void NTCP2Session::HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -918,7 +919,6 @@ namespace transport { SetTerminationTimeout (NTCP2_ESTABLISH_TIMEOUT); SetLastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ()); - m_Establisher->CreateEphemeralKey (); boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer, 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -1399,6 +1399,19 @@ namespace transport boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); // let termination message go } + void NTCP2Session::ReadSomethingAndTerminate () + { + size_t len = m_Server.GetRng ()() % NTCP2_SESSION_REQUEST_MAX_SIZE; + if (len > 0 && m_Establisher) + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer, len), boost::asio::transfer_all (), + [s = shared_from_this()](const boost::system::error_code& ecode, size_t bytes_transferred) + { + s->Terminate (); + }); + else + boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); + } + void NTCP2Session::SendI2NPMessages (std::list >& msgs) { if (m_IsTerminated || msgs.empty ()) diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 5ad5b955..b50d9087 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.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 * @@ -200,6 +200,7 @@ namespace transport void SendRouterInfo (); void SendTermination (NTCP2TerminationReason reason); void SendTerminationAndTerminate (NTCP2TerminationReason reason); + void ReadSomethingAndTerminate (); void PostI2NPMessages (); private: From 209eb174c6b0f0c181329f0da9874124cbde3b42 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 4 May 2025 18:59:21 -0400 Subject: [PATCH 486/527] fixed choked stream hanging --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 99da5fd2..25608cbc 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -642,7 +642,7 @@ namespace stream if (wasInitial) ScheduleResend (); } - if (m_IsClientChoked && ackThrough >= m_DropWindowDelaySequenceNumber) + if (m_IsClientChoked && (ackThrough >= m_DropWindowDelaySequenceNumber || m_SentPackets.empty ())) m_IsClientChoked = false; if (m_IsWinDropped && ackThrough > m_DropWindowDelaySequenceNumber) { From 246bc43dea07e72de90283acfcabbcf7d367c31f Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 7 May 2025 18:54:55 -0400 Subject: [PATCH 487/527] read more data from socket if available and stream buffer is not full --- libi2pd_client/I2PTunnel.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 82a6ed03..fe83d47f 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -183,6 +183,29 @@ namespace client } else { + if (bytes_transferred < I2P_TUNNEL_CONNECTION_BUFFER_SIZE && !m_SSL) + { + boost::system::error_code ec; + size_t moreBytes = m_Socket->available(ec); + if (!ec && moreBytes && m_Stream) + { + // read more data from socket before sending to stream + if (bytes_transferred + moreBytes > I2P_TUNNEL_CONNECTION_BUFFER_SIZE) + moreBytes = I2P_TUNNEL_CONNECTION_BUFFER_SIZE - bytes_transferred; + if (m_Stream->GetSendBufferSize () < I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE) + { + size_t remaining = I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE - m_Stream->GetSendBufferSize (); + if (remaining < moreBytes) moreBytes = remaining; + } + else + moreBytes = 0; + } + if (moreBytes) + { + moreBytes = boost::asio::read (*m_Socket, boost::asio::buffer(m_Buffer + bytes_transferred, moreBytes), boost::asio::transfer_all (), ec); + if (!ec) bytes_transferred += moreBytes; + } + } WriteToStream (m_Buffer, bytes_transferred); Receive (); // try to receive more while being sent to stream } From aab82966190e59036be7839603800e49712d21ae Mon Sep 17 00:00:00 2001 From: r4sas Date: Sun, 18 May 2025 02:20:31 +0300 Subject: [PATCH 488/527] [i18n] add Hebrew and Hindi translations, add rtl support (testing) Signed-off-by: r4sas --- daemon/HTTPServer.cpp | 11 +- i18n/Afrikaans.cpp | 5 +- i18n/Armenian.cpp | 5 +- i18n/Chinese.cpp | 5 +- i18n/Czech.cpp | 5 +- i18n/English.cpp | 5 +- i18n/French.cpp | 7 +- i18n/German.cpp | 5 +- i18n/Hebrew.cpp | 202 +++++++++++++++++++++++++++++++++++++ i18n/Hindi.cpp | 226 ++++++++++++++++++++++++++++++++++++++++++ i18n/I18N.h | 11 +- i18n/I18N_langs.h | 6 +- i18n/Italian.cpp | 5 +- i18n/Polish.cpp | 5 +- i18n/Portuguese.cpp | 5 +- i18n/Russian.cpp | 5 +- i18n/Spanish.cpp | 5 +- i18n/Swedish.cpp | 5 +- i18n/Turkish.cpp | 5 +- i18n/Turkmen.cpp | 5 +- i18n/Ukrainian.cpp | 5 +- i18n/Uzbek.cpp | 5 +- 22 files changed, 518 insertions(+), 25 deletions(-) create mode 100644 i18n/Hebrew.cpp create mode 100644 i18n/Hindi.cpp diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index dca545fe..be1ec4ac 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -134,7 +134,7 @@ namespace http { { std::string state; std::string_view stateText; - switch (eState) + switch (eState) { case i2p::tunnel::eTunnelStateBuildReplyReceived : case i2p::tunnel::eTunnelStatePending : state = "building"; break; @@ -146,7 +146,7 @@ namespace http { default: state = "unknown"; break; } if (stateText.empty ()) stateText = tr(state); - + s << " " << stateText << ((explr) ? " (" + std::string(tr("exploratory")) + ")" : "") << ", "; // TODO: ShowTraffic(s, bytes); s << "\r\n"; @@ -172,9 +172,12 @@ namespace http { auto it = i2p::i18n::languages.find(currLang); std::string langCode = it->second.ShortCode; + // Right to Left language option + bool rtl = i2p::client::context.GetLanguage ()->GetRTL(); + s << "\r\n" - "\r\n" + "\r\n" " \r\n" /* TODO: Find something to parse html/template system. This is horrible. */ " \r\n" " \r\n" @@ -1479,7 +1482,7 @@ namespace http { reply.body = content; m_SendBuffer = reply.to_string(); - boost::asio::async_write (*m_Socket, boost::asio::buffer(m_SendBuffer), boost::asio::transfer_all (), + boost::asio::async_write (*m_Socket, boost::asio::buffer(m_SendBuffer), boost::asio::transfer_all (), std::bind (&HTTPConnection::Terminate, shared_from_this (), std::placeholders::_1)); } diff --git a/i18n/Afrikaans.cpp b/i18n/Afrikaans.cpp index b69c42ef..0afa086f 100644 --- a/i18n/Afrikaans.cpp +++ b/i18n/Afrikaans.cpp @@ -29,6 +29,9 @@ namespace afrikaans // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"failed", "Het misluk"}, @@ -73,7 +76,7 @@ namespace afrikaans // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Armenian.cpp b/i18n/Armenian.cpp index 67955d8a..af22d0d9 100644 --- a/i18n/Armenian.cpp +++ b/i18n/Armenian.cpp @@ -29,6 +29,9 @@ namespace armenian // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f ԿիԲ"}, @@ -196,7 +199,7 @@ namespace armenian // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Chinese.cpp b/i18n/Chinese.cpp index e3b63ebd..f439bb67 100644 --- a/i18n/Chinese.cpp +++ b/i18n/Chinese.cpp @@ -29,6 +29,9 @@ namespace chinese // language namespace return 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -215,7 +218,7 @@ namespace chinese // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Czech.cpp b/i18n/Czech.cpp index 94803354..c9697f41 100644 --- a/i18n/Czech.cpp +++ b/i18n/Czech.cpp @@ -29,6 +29,9 @@ namespace czech // language namespace return (n == 1) ? 0 : (n >= 2 && n <= 4) ? 1 : 2; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -215,7 +218,7 @@ namespace czech // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/English.cpp b/i18n/English.cpp index fb774527..eb7067e2 100644 --- a/i18n/English.cpp +++ b/i18n/English.cpp @@ -30,6 +30,9 @@ namespace english // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"", ""}, @@ -42,7 +45,7 @@ namespace english // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/French.cpp b/i18n/French.cpp index 985296a3..2618772f 100644 --- a/i18n/French.cpp +++ b/i18n/French.cpp @@ -29,6 +29,9 @@ namespace french // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f Kio"}, @@ -44,7 +47,7 @@ namespace french // language namespace {"i2pd webconsole", "Console web i2pd"}, {"Main page", "Page principale"}, {"Router commands", "Commandes du routeur"}, - {"Local Destinations", "Destinations locales"}, + {"Local Destinations", "Destinatioans localeAlger"}, {"LeaseSets", "Jeu de baux"}, {"Tunnels", "Tunnels"}, {"Transit Tunnels", "Tunnels transitoires"}, @@ -215,7 +218,7 @@ namespace french // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/German.cpp b/i18n/German.cpp index 90ce82f4..b3b35e99 100644 --- a/i18n/German.cpp +++ b/i18n/German.cpp @@ -29,6 +29,9 @@ namespace german // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -210,7 +213,7 @@ namespace german // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Hebrew.cpp b/i18n/Hebrew.cpp new file mode 100644 index 00000000..7e56395f --- /dev/null +++ b/i18n/Hebrew.cpp @@ -0,0 +1,202 @@ +/* +* 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 +#include +#include +#include +#include "I18N.h" + +// Hebrew localization file + +namespace i2p +{ +namespace i18n +{ +namespace hebrew // language namespace +{ + // language name in lowercase + static std::string language = "hebrew"; + + // See for language plural forms here: + // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html + static int plural (int n) { + return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3; + } + + // Right to Left language? + static bool rtl = true; + + static const LocaleStrings strings + { + {"%.2f KiB", "%.2f קי״ב"}, + {"%.2f MiB", "%.2f מי״ב"}, + {"%.2f GiB", "%.2f קי״ב"}, + {"Purple I2P Webconsole", "קונסולת Purple I2P"}, + {"i2pd webconsole", "קונסולת i2pd"}, + {"Main page", "עמוד ראשי"}, + {"Router commands", "פקודות נתב"}, + {"Local Destinations", "יעדים מקומיים"}, + {"Tunnels", "מנהרות"}, + {"Transit Tunnels", "מנהרות מעבר"}, + {"Transports", "מובילים"}, + {"I2P tunnels", "מנהרות I2P"}, + {"SAM sessions", "הפעלות SAM"}, + {"Unknown", "לא מוכר"}, + {"Proxy", "פרוקסי"}, + {"Mesh", "סיבוך"}, + {"Clock skew", "לכסון שעון"}, + {"Offline", "לא מקוון"}, + {"Symmetric NAT", "NAT סימטרי"}, + {"Full cone NAT", "NAT חסום לחלוטין"}, + {"No Descriptors", "אין מתארים"}, + {"Uptime", "זמן הפעלה"}, + {"Network status", "מצב רשת תקשורת"}, + {"Network status v6", "מצב רשת תקשורת v6"}, + {"Stopping in", "מפסיק בעוד"}, + {"Family", "משפחה"}, + {"Tunnel creation success rate", "שיעור הצלחה של יצירת מנהרות"}, + {"Total tunnel creation success rate", "שיעור הצלחה כולל של יצירת מנהרות"}, + {"Received", "נתקבל"}, + {"%.2f KiB/s", "%.2f קי״ב/ש"}, + {"Sent", "נשלח"}, + {"Transit", "מעבר"}, + {"Data path", "נתיב מידע"}, + {"Hidden content. Press on text to see.", "תוכן מוסתר. לחץ על הטקסט כדי לראותו."}, + {"Router Ident", "מזהה נתב"}, + {"Router Family", "משפחת נתב"}, + {"Version", "גרסא"}, + {"Our external address", "הכתובת החיצונית שלנו"}, + {"supported", "נתמך"}, + {"Routers", "נתבים"}, + {"Client Tunnels", "מנהרות לקוח"}, + {"Services", "שירותים"}, + {"Enabled", "מאופשר"}, + {"Disabled", "מנוטרל"}, + {"Encrypted B33 address", "כתובת B33 מוצפנת"}, + {"Address registration line", "שורת רישום כתובת"}, + {"Domain", "תחום"}, + {"Generate", "צור"}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "הערה מחרוזת תוצאה יכולה להיות מועילה רק לצורך רישום תחומים 2LD (example.i2p). לשם רישום תתי-תחום עליך להיוועץ עם i2pd-tools."}, + {"Address", "כתובת"}, + {"Type", "טיפוס"}, + {"Expire LeaseSet", "פקיעת LeaseSet"}, + {"Inbound tunnels", "מנהרות פנימיות"}, + {"%dms", "מילישניות %d"}, + {"Outbound tunnels", "מנהרות חיצוניות"}, + {"Tags", "תוויות"}, + {"Incoming", "נכנס"}, + {"Outgoing", "יוצא"}, + {"Destination", "יעד"}, + {"Amount", "כמות"}, + {"Incoming Tags", "תוויות נכנסות"}, + {"Tags sessions", "הפעלות תוויות"}, + {"Status", "מצב"}, + {"Local Destination", "יעד מקומי"}, + {"Streams", "זרמים"}, + {"Close stream", "סגור זרם"}, + {"Such destination is not found", "יעד כזה לא נמצא"}, + {"I2CP session not found", "הפעלת I2CP לא נמצאה"}, + {"I2CP is not enabled", "I2CP לא מאופשר"}, + {"Invalid", "לא תקין"}, + {"Store type", "טיפוס אחסון"}, + {"Expires", "פוקע"}, + {"Non Expired Leases", "חכירות בלתי פקיעות"}, + {"Gateway", "שער-דרך"}, + {"TunnelID", "מזהה מנהרה"}, + {"EndDate", "תאריך סיום"}, + {"floodfill mode is disabled", "מצב floodfill הינו מנוטרל"}, + {"Queue size", "גודל תור"}, + {"Run peer test", "הרץ בדיקת עמית"}, + {"Reload tunnels configuration", "טען מחדש תצורת מנהרות"}, + {"Decline transit tunnels", "דחה מנהרות מעבר"}, + {"Accept transit tunnels", "קבל מנהרות מעבר"}, + {"Cancel graceful shutdown", "בטל כיבוי עדין"}, + {"Start graceful shutdown", "התחל כיבוי עדין"}, + {"Force shutdown", "כפה כיבוי"}, + {"Reload external CSS styles", "טען מחדש סגנונות CSS חיצוניים"}, + {"Note: any action done here are not persistent and not changes your config files.", "הערה כל פעולה אשר מבוצעת כאן אינה המשכית ולא משנה את קובצי התצורה שלך."}, + {"Logging level", "דרגת רישום יומן"}, + {"Transit tunnels limit", "מגבלת מנהרות מעבר"}, + {"Change", "שנה"}, + {"Change language", "שנה שפה"}, + {"no transit tunnels currently built", "אין מנהרות מעבר אשר בנויות כעת"}, + {"SAM disabled", "SAM מנוטרל"}, + {"no sessions currently running", "אין הפעלה אשר מורצת כעת"}, + {"SAM session not found", "הפעלת SAM לא נמצאה"}, + {"SAM Session", "הפעלת SAM"}, + {"Server Tunnels", "מנהרות שרת"}, + {"Unknown page", "עמוד לא מוכר"}, + {"Invalid token", "סימן לא תקין"}, + {"SUCCESS", "הצלחה"}, + {"Stream closed", "זרם סגור"}, + {"Stream not found or already was closed", "זרם לא נמצא או שהוא היה כבר סגור"}, + {"Destination not found", "יעד לא נמצא"}, + {"StreamID can't be null", "מזהה זרם (StreamID) לא יכול להיות אפסי"}, + {"Return to destination page", "חזור לעמוד יעד"}, + {"You will be redirected in %d seconds", "אתה תכוון מחדש בעוד %d שניות"}, + {"LeaseSet expiration time updated", "זמן פקיעה של LeaseSet עודכן"}, + {"LeaseSet is not found or already expired", "LeaseSet אינו נמצא או שהוא כבר פקע"}, + {"Transit tunnels count must not exceed %d", "אסור לספירת מנהרות מעבר לעלות על %d"}, + {"Back to commands list", "חזור לרשימת פקודות"}, + {"Register at reg.i2p", "הירשם באתר reg.i2p"}, + {"Description", "תיאור"}, + {"A bit information about service on domain", "מידע אודות שירות על תחום"}, + {"Submit", "שלח"}, + {"Domain can't end with .b32.i2p", "תחום לא יכול להסתיים עם ‎.b32.i2p"}, + {"Domain must end with .i2p", "תחום חייב להסתיים עם ‎.i2p"}, + {"Unknown command", "פקודה לא מוכרת"}, + {"Command accepted", "פקודה נתקבלה"}, + {"Proxy error", "שגיאת פרוקסי"}, + {"Proxy info", "מידע פרוקסי"}, + {"Proxy error: Host not found", "שגיאת פרוקסי: מארח לא נמצא"}, + {"Remote host not found in router's addressbook", "ארח מרוחק לא נמצא בתוך הפנקס כתובות של הנתב"}, + {"You may try to find this host on jump services below", "באפשרותך לנסות למצוא את מארח זה דרך שירותי קפיצה להלן"}, + {"Invalid request", "בקשה לא תקינה"}, + {"Proxy unable to parse your request", "פרוקסי לא מסוגל לנתח את בקשתך"}, + {"Addresshelper is not supported", "סייען-כתובות אינו נתמך"}, + {"Host %s is already in router's addressbook. Be careful: source of this URL may be harmful! Click here to update record: Continue.", "מארח %s is כבר נמצא בפנקס כתובות של הנתב. זהירות: מקור URL זה עלול להזיק! לחץ כאן כדי לעדכן מרשם: המשך."}, + {"Addresshelper forced update rejected", "אילוץ עדכון של סייען-כתובות נדחה"}, + {"To add host %s in router's addressbook, click here: Continue.", "Tכדי להוסיף את מארח %s לפנקס כתובות של הנתב: המשך."}, + {"Addresshelper request", "בקשת סייען-כתובות"}, + {"Host %s added to router's addressbook from helper. Click here to proceed: Continue.", "מארח %s נתווסף לסייען-כתובות של הנתב דרך סייען. לחץ כאן כדי proceed: המשך."}, + {"Addresshelper adding", "הוספת סייען-כתובות"}, + {"Host %s is already in router's addressbook. Click here to update record: Continue.", "מארח %s כבר נמצא בספר כתובות של הנתב. לחץ כאן כדי לעדכן מרשם: המשך."}, + {"Addresshelper update", "עדכון סייען-כתובות"}, + {"Invalid request URI", "בקשת URI לא תקינה"}, + {"Can't detect destination host from request", "לא יכול לאתר יעד מארח מתוך בקשה"}, + {"Host %s is not inside I2P network, but outproxy is not enabled", "מארח %s לא נמצא בתוך רשת I2P, אולם outproxy אינו מאופשר"}, + {"Hostname is too long", "שם-מארח הינו ארוך מדי"}, + {"Cannot negotiate with SOCKS proxy", "לא מסוגל להסדיר פרוקסי SOCKS"}, + {"CONNECT error", "שגיאת חיבור"}, + {"Failed to connect", "נכשל להתחבר"}, + {"SOCKS proxy error", "שגיאת פרוקסי SOCKS"}, + {"No reply from SOCKS proxy", "אין מענה מתוך פרוקסי SOCKS"}, + {"Cannot connect", "לא מסוגל להתחבר"}, + {"Host is down", "מארח הינו מושבת"}, + {"Can't create connection to requested host, it may be down. Please try again later.", "לא יכול ליצור חיבור למארח מבוקש, המארח עשוי להיות מושבת. אנא נסה שוב מאוחר יותר."}, + {"", ""}, + }; + + static std::map> plurals + { + {"%d days", {"יום %d", "יומיים", "ימים %d", "ימים %d"}}, + {"%d hours", {"שעה %d", "שעתיים", "שעות %d", "שעות %d"}}, + {"%d minutes", {"דקה %d", "שתי דקות", "דקות %d", "דקות %d"}}, + {"%d seconds", {"שניה %d", "שתי שניות", "שניות %d", "שניות %d"}}, + {"", {"", "", ""}}, + }; + + std::shared_ptr GetLocale() + { + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); + } + +} // language +} // i18n +} // i2p diff --git a/i18n/Hindi.cpp b/i18n/Hindi.cpp new file mode 100644 index 00000000..7ce9b65b --- /dev/null +++ b/i18n/Hindi.cpp @@ -0,0 +1,226 @@ +/* +* 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 +#include +#include +#include +#include "I18N.h" + +// Hindi localization file + +namespace i2p +{ +namespace i18n +{ +namespace hindi // language namespace +{ + // language name in lowercase + static std::string language = "hindi"; + + // See for language plural forms here: + // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html + static int plural (int n) { + return n != 1 ? 1 : 0; + } + + // Right to Left language? + static bool rtl = false; + + static const LocaleStrings strings + { + {"%.2f KiB", "%.2f कीबी"}, + {"%.2f MiB", "%.2f मीबी"}, + {"%.2f GiB", "%.2f जीबी"}, + {"building", "निर्माण"}, + {"failed", "विफल"}, + {"expiring", "समाप्त होना"}, + {"established", "स्थापित"}, + {"unknown", "अज्ञात"}, + {"exploratory", "अन्वेषणात्मक"}, + {"Purple I2P Webconsole", "पर्पल I2P वेब कंसोल"}, + {"i2pd webconsole", "i2pd वेब कंसोल"}, + {"Main page", "मुख्य पृष्ठ"}, + {"Router commands", "राउटर आदेश"}, + {"Local Destinations", "स्थानीय गंतव्य"}, + {"LeaseSets", "पट्ट समुच्चय"}, + {"Tunnels", "सुरंग"}, + {"Transit Tunnels", "संचरण सुरंगें"}, + {"Transports", "परिवहन"}, + {"I2P tunnels", "I2P सुरंगें"}, + {"SAM sessions", "SAM सत्र"}, + {"ERROR", "त्रुटि"}, + {"OK", "ठीक है"}, + {"Testing", "परीक्षण"}, + {"Firewalled", "फायरवॉल"}, + {"Unknown", "अज्ञात"}, + {"Proxy", "प्रॉक्सी"}, + {"Mesh", "जाली"}, + {"Clock skew", "घड़ी संकेत विचलन"}, + {"Offline", "ऑफलाइन"}, + {"Symmetric NAT", "सममितीय NAT"}, + {"Full cone NAT", "पूर्णकोण NAT"}, + {"No Descriptors", "कोई वर्णनकर्त्तृ नहीं हैं"}, + {"Uptime", "संचालन समय"}, + {"Network status", "संपर्क स्थिति"}, + {"Network status v6", "संपर्क स्थिति v6"}, + {"Stopping in", "में अवसान प्रारंभ हो रहा है"}, + {"Family", "परिवार"}, + {"Tunnel creation success rate", "सुरंग निर्माण सफलता दर"}, + {"Total tunnel creation success rate", "कुल सुरंग निर्माण सफलता दर"}, + {"Received", "प्राप्त हुआ"}, + {"%.2f KiB/s", "%.2f कीबी/से"}, + {"Sent", "प्रेषित"}, + {"Transit", "संचरण"}, + {"Data path", "डेटा पथ"}, + {"Hidden content. Press on text to see.", "सामग्री छिपाई गई है। देखने हेतु पाठ पर दबाएँ।"}, + {"Router Ident", "राउटर परिचय"}, + {"Router Family", "राउटर परिवार"}, + {"Router Caps", "राउटर कैप्स"}, + {"Version", "संस्करण"}, + {"Our external address", "हमारा बाह्य पता"}, + {"supported", "समर्थित"}, + {"Routers", "राउटर"}, + {"Floodfills", "पूर्णक संवाहक"}, + {"Client Tunnels", "क्लाइंट सुरंगें"}, + {"Services", "सेवाएँ"}, + {"Enabled", "सक्षम है"}, + {"Disabled", "निष्क्रिय है"}, + {"Encrypted B33 address", "कूटलिखित B33 पता"}, + {"Address registration line", "पता पंजीकरण पंक्ति"}, + {"Domain", "डोमेन"}, + {"Generate", "सृजित करें"}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "नोट: परिणाम स्ट्रिंग का उपयोग केवल 2LD डोमेनों (जैसे example.i2p) को रजिस्टर करने के लिए किया जा सकता है। सबडोमेन रजिस्टर करने के लिए कृपया i2pd-tools का उपयोग करें।"}, + {"Address", "पता"}, + {"Type", "प्रकार"}, + {"EncType", "कूट प्रकार"}, + {"Expire LeaseSet", "पट्ट समुच्चय का अवसान करें"}, + {"Inbound tunnels", "आगमनशील सुरंगें"}, + {"%dms", "%dms"}, + {"Outbound tunnels", "प्रस्थानशील सुरंगें"}, + {"Tags", "चिन्हित"}, + {"Incoming", "आगामी"}, + {"Outgoing", "निर्गामी"}, + {"Destination", "गंतव्य"}, + {"Amount", "मात्रा"}, + {"Incoming Tags", "आगामी चिन्हित"}, + {"Tags sessions", "चिन्हित सत्र OR सत्र को चिन्हित करें"}, + {"Status", "स्थिति"}, + {"Local Destination", "स्थानीय गंतव्य"}, + {"Streams", "धाराएँ"}, + {"Close stream", "प्रवाह समाप्त करें"}, + {"Such destination is not found", "ऐसा गंतव्य नहीं मिला"}, + {"I2CP session not found", "I2CP सत्र नहीं मिला"}, + {"I2CP is not enabled", "I2CP निष्क्रिय है"}, + {"Invalid", "अमान्य"}, + {"Store type", "भण्डारगार का प्रकार"}, + {"Expires", "अवसान होता है"}, + {"Non Expired Leases", "अनवसित पट्ट"}, + {"Gateway", "प्रवेशद्वार"}, + {"TunnelID", "सुरंग ID"}, + {"EndDate", "समाप्ति तिथि"}, + {"floodfill mode is disabled", "पूर्णक संवाहक विधि निष्क्रिय है"}, + {"Queue size", "क्यू आकार"}, + {"Run peer test", "सहकर्मी परीक्षण चलाएँ"}, + {"Reload tunnels configuration", "सुरंग विन्यास पुनः लोड करें"}, + {"Decline transit tunnels", "संचरण सुरंगों को अस्वीकार करें"}, + {"Accept transit tunnels", "संचरण सुरंगों को स्वीकार करें"}, + {"Cancel graceful shutdown", "सौम्य अवसान निरस्त करें"}, + {"Start graceful shutdown", "सौम्य समापन प्रारंभ करें"}, + {"Force shutdown", "बाध्य अवसान"}, + {"Reload external CSS styles", "बाह्य CSS शैलियों को पुनः लोड करें"}, + {"Note: any action done here are not persistent and not changes your config files.", "टिप्पणी: यहाँ किए गए कोई भी क्रियाएँ स्थायी नहीं हैं और आपके विन्यास संचिका में कोई परिवर्तन नहीं करतीं।"}, + {"Logging level", "लॉगिंग स्तर"}, + {"Transit tunnels limit", "संचरण सुरंगों की सीमा"}, + {"Change", "बदलना"}, + {"Change language", "भाषा बदलें"}, + {"no transit tunnels currently built", "संचरण सुरंगों का निर्माण नहीं हुआ है"}, + {"SAM disabled", "SAM निष्क्रिय है"}, + {"no sessions currently running", "वर्तमान में कोई सत्र सक्रिय नहीं है"}, + {"SAM session not found", "SAM सत्र नहीं मिला"}, + {"SAM Session", "SAM सत्र"}, + {"Server Tunnels", "सर्वर सुरंग"}, + {"Client Forwards", "क्लाइंट फॉरवर्ड्स"}, + {"Server Forwards", "सर्वर फॉरवर्ड्स"}, + {"Unknown page", "अज्ञात पृष्ठ"}, + {"Invalid token", "अमान्य टोकन"}, + {"SUCCESS", "सफलता"}, + {"Stream closed", "प्रवाह समाप्त हो गया है"}, + {"Stream not found or already was closed", "प्रवाह प्राप्त नहीं हुआ अथवा इसका पूर्व में ही समापन हो चुका है"}, + {"Destination not found", "गंतव्य नहीं मिला"}, + {"StreamID can't be null", "प्रवाह ID शून्य नहीं हो सकता है"}, + {"Return to destination page", "गंतव्य पृष्ठ पर पुनः वापस जाएँ"}, + {"You will be redirected in %d seconds", "आपको %d सेकंड में पुनर्निर्देशित किया जाएगा"}, + {"LeaseSet expiration time updated", "पट्ट समुच्चय की अवसान समय को अद्यतित किया गया है"}, + {"LeaseSet is not found or already expired", "पट्ट समुच्चय प्राप्त नहीं हुआ या इसका पूर्वमेव अवसान हो चुका है"}, + {"Transit tunnels count must not exceed %d", "संचरण सुरंगों की संख्या %d से अधिक नहीं होनी चाहिए"}, + {"Back to commands list", "आदेश सूची पर पुनः लौटें"}, + {"Register at reg.i2p", "reg.i2p पर पंजीकरण करें"}, + {"Description", "विवरण"}, + {"A bit information about service on domain", "डोमेन पर सेवा से संबंधित थोड़ी जानकारी"}, + {"Submit", "प्रस्तुत करें"}, + {"Domain can't end with .b32.i2p", "डोमेन का अंत .b32.i2p से नहीं हो सकता"}, + {"Domain must end with .i2p", "डोमेन का अंत .i2p से होना आवश्यक है"}, + {"Unknown command", "अज्ञात आदेश"}, + {"Command accepted", "आदेश स्वीकार किया गया"}, + {"Proxy error", "प्रॉक्सी त्रुटि"}, + {"Proxy info", "प्रॉक्सी जानकारी"}, + {"Proxy error: Host not found", "प्रॉक्सी त्रुटि: होस्ट नहीं मिला"}, + {"Remote host not found in router's addressbook", "राउटर की पता पुस्तक में दूरस्थ होस्ट नहीं मिला"}, + {"You may try to find this host on jump services below", "आप नीचे दिए गए जंप सेवाओं में इस होस्ट को खोजने की कोशिश कर सकते हैं"}, + {"Invalid request", "अमान्य अनुरोध"}, + {"Proxy unable to parse your request", "प्रॉक्सी आपके अनुरोध को विश्लेषित करने में असमर्थ है"}, + {"Addresshelper is not supported", "Addresshelper समर्थित नहीं है"}, + {"Host %s is already in router's addressbook. Be careful: source of this URL may be harmful! Click here to update record: Continue.", "होस्ट %s पहले से ही राउटर की पता-पुस्तिका में उपस्थित हैसावधान रहें: इस URL का स्रोत हानिकारक हो सकता है! अभिलेख को अद्यतन करने हेतु यहाँ क्लिक करें: जारी रखें।"}, + {"Addresshelper forced update rejected", "Addresshelper का जबरन अद्यतन अस्वीकृत किया गया"}, + {"To add host %s in router's addressbook, click here: Continue.", "राउटर की पता-पुस्तिका में होस्ट %s को जोड़ने हेतु, कृपया यहाँ क्लिक करें: जारी रखें।"}, + {"Addresshelper request", "Addresshelper अनुरोध"}, + {"Host %s added to router's addressbook from helper. Click here to proceed: Continue.", "सहायक से होस्ट %s राउटर की पता-पुस्तिका में जोड़ दिया गया है। आगे बढ़ने हेतु यहाँ क्लिक करें: जारी रखें।"}, + {"Addresshelper adding", "Addresshelper जोड़ना"}, + {"Host %s is already in router's addressbook. Click here to update record: Continue.", "होस्ट %s पहले से ही राउटर की पता-पुस्तिका में उपस्थित है। अभिलेख को अद्यतन करने हेतु यहाँ क्लिक करें: जारी रखें।"}, + {"Addresshelper update", "Addresshelper अद्यतन करना"}, + {"Invalid request URI", "अमान्य अनुरोध URI"}, + {"Can't detect destination host from request", "अनुरोध से गंतव्य होस्ट का पता नहीं लगा सकते"}, + {"Outproxy failure", "आउटप्रॉक्सी विफलता"}, + {"Bad outproxy settings", "गलत आउटप्रॉक्सी सेटिंग्स"}, + {"Host %s is not inside I2P network, but outproxy is not enabled", "होस्ट %s I2P नेटवर्क के भीतर नहीं है, लेकिन आउटप्रॉक्सी सक्षम नहीं है"}, + {"Unknown outproxy URL", "अज्ञात आउटप्रॉक्सी URL"}, + {"Cannot resolve upstream proxy", "ऊर्ध्वधारा प्रॉक्सी का समाधान नहीं किया जा सका"}, + {"Hostname is too long", "होस्टनाम अत्यधिक लंबा है"}, + {"Cannot connect to upstream SOCKS proxy", "उर्ध्वधारा SOCKS प्रॉक्सी से संपर्क स्थापित नहीं हो पा रहा है"}, + {"Cannot negotiate with SOCKS proxy", "SOCKS प्रॉक्सी के साथ समन्वयन स्थापित नहीं किया जा सका"}, + {"CONNECT error", "संपर्क त्रुटि"}, + {"Failed to connect", "संपर्क स्थापित करने में विफल"}, + {"SOCKS proxy error", "SOCKS प्रॉक्सी त्रुटि"}, + {"Failed to send request to upstream", "ऊर्ध्ववाहिनी को अनुरोध प्रेषित करने में विफलता हुई"}, + {"No reply from SOCKS proxy", "SOCKS प्रॉक्सी से कोई प्रत्युत्तर प्राप्त नहीं हुआ"}, + {"Cannot connect", "संपर्क नहीं हो पा रहा है"}, + {"HTTP out proxy not implemented", "HTTP आउट प्रॉक्सी कार्यान्वित नहीं किया गया है"}, + {"Cannot connect to upstream HTTP proxy", "उर्ध्वधारा HTTP प्रॉक्सी से संपर्क स्थापित नहीं हो पा रहा है"}, + {"Host is down", "होस्ट अनुपलब्ध है"}, + {"Can't create connection to requested host, it may be down. Please try again later.", "अनुरोधित होस्ट से संपर्क स्थापित नहीं किया जा सका। संभवतः वह सक्रिय नहीं है। कृपया बाद में पुनः प्रयास करें।"}, + {"", ""}, + }; + + static std::map> plurals + { + {"%d days", {"%d दिन", "%d दिन"}}, + {"%d hours", {"%d घंटा", "%dघंटे"}}, + {"%d minutes", {"%d मिनट", "%d मिनट"}}, + {"%d seconds", {"%d सेकंड", "%d सेकंड"}}, + {"", {"", "", ""}}, + }; + + std::shared_ptr GetLocale() + { + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); + } + +} // language +} // i18n +} // i2p diff --git a/i18n/I18N.h b/i18n/I18N.h index 8ed77a6b..00398f78 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -19,16 +19,17 @@ namespace i2p { namespace i18n { - typedef std::map LocaleStrings; + typedef std::map LocaleStrings; class Locale { public: Locale ( const std::string& language, + const bool& rtl, const LocaleStrings& strings, const std::map>& plurals, std::function formula - ): m_Language (language), m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { }; + ): m_Language (language), m_RTL (rtl), m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { }; // Get activated language name for webconsole std::string GetLanguage() const @@ -36,6 +37,11 @@ namespace i18n return m_Language; } + bool GetRTL() const + { + return m_RTL; + } + std::string_view GetString (std::string_view arg) const { const auto it = m_Strings.find(arg); @@ -65,6 +71,7 @@ namespace i18n private: const std::string m_Language; + const bool m_RTL; const LocaleStrings m_Strings; const std::map> m_Plurals; std::function m_Formula; diff --git a/i18n/I18N_langs.h b/i18n/I18N_langs.h index 6426e2ce..b3d09af8 100644 --- a/i18n/I18N_langs.h +++ b/i18n/I18N_langs.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2021-2023, The PurpleI2P Project +* Copyright (c) 2021-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -30,6 +30,8 @@ namespace i18n namespace english { std::shared_ptr GetLocale (); } namespace french { std::shared_ptr GetLocale (); } namespace german { std::shared_ptr GetLocale (); } + namespace hebrew { std::shared_ptr GetLocale (); } + namespace hindi { std::shared_ptr GetLocale (); } namespace italian { std::shared_ptr GetLocale (); } namespace polish { std::shared_ptr GetLocale (); } namespace portuguese { std::shared_ptr GetLocale (); } @@ -53,6 +55,8 @@ namespace i18n { "english", {"English", "en", i2p::i18n::english::GetLocale} }, { "french", {"Français", "fr", i2p::i18n::french::GetLocale} }, { "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} }, + { "hebrew", {"עִבְרִית‎", "he", i2p::i18n::hebrew::GetLocale} }, + { "hindi", {"हिन्दी", "hi", i2p::i18n::hindi::GetLocale} }, { "italian", {"Italiano", "it", i2p::i18n::italian::GetLocale} }, { "polish", {"Polski", "pl", i2p::i18n::polish::GetLocale} }, { "portuguese", {"Português", "pt", i2p::i18n::portuguese::GetLocale} }, diff --git a/i18n/Italian.cpp b/i18n/Italian.cpp index 0ae26f21..339654ba 100644 --- a/i18n/Italian.cpp +++ b/i18n/Italian.cpp @@ -29,6 +29,9 @@ namespace italian // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -215,7 +218,7 @@ namespace italian // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Polish.cpp b/i18n/Polish.cpp index 0e8df096..97422e45 100644 --- a/i18n/Polish.cpp +++ b/i18n/Polish.cpp @@ -29,6 +29,9 @@ namespace polish // language namespace return (n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -215,7 +218,7 @@ namespace polish // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Portuguese.cpp b/i18n/Portuguese.cpp index 26204dc3..970a7b8f 100644 --- a/i18n/Portuguese.cpp +++ b/i18n/Portuguese.cpp @@ -29,6 +29,9 @@ namespace portuguese // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -215,7 +218,7 @@ namespace portuguese // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Russian.cpp b/i18n/Russian.cpp index 235cc0ae..e5bcb0b0 100644 --- a/i18n/Russian.cpp +++ b/i18n/Russian.cpp @@ -29,6 +29,9 @@ namespace russian // language namespace return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f КиБ"}, @@ -215,7 +218,7 @@ namespace russian // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Spanish.cpp b/i18n/Spanish.cpp index 0e657fb4..5b51ce4d 100644 --- a/i18n/Spanish.cpp +++ b/i18n/Spanish.cpp @@ -29,6 +29,9 @@ namespace spanish // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -196,7 +199,7 @@ namespace spanish // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Swedish.cpp b/i18n/Swedish.cpp index df13d22f..1dcb7e61 100644 --- a/i18n/Swedish.cpp +++ b/i18n/Swedish.cpp @@ -29,6 +29,9 @@ namespace swedish // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -211,7 +214,7 @@ namespace swedish // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Turkish.cpp b/i18n/Turkish.cpp index 9946b336..139b004e 100644 --- a/i18n/Turkish.cpp +++ b/i18n/Turkish.cpp @@ -29,6 +29,9 @@ namespace turkish // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -106,7 +109,7 @@ namespace turkish // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Turkmen.cpp b/i18n/Turkmen.cpp index 7efb8891..8cdcae52 100644 --- a/i18n/Turkmen.cpp +++ b/i18n/Turkmen.cpp @@ -29,6 +29,9 @@ namespace turkmen // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -196,7 +199,7 @@ namespace turkmen // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Ukrainian.cpp b/i18n/Ukrainian.cpp index c1b6c772..3c3c44a4 100644 --- a/i18n/Ukrainian.cpp +++ b/i18n/Ukrainian.cpp @@ -29,6 +29,9 @@ namespace ukrainian // language namespace return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f КіБ"}, @@ -215,7 +218,7 @@ namespace ukrainian // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Uzbek.cpp b/i18n/Uzbek.cpp index 8e870772..681a8e19 100644 --- a/i18n/Uzbek.cpp +++ b/i18n/Uzbek.cpp @@ -29,6 +29,9 @@ namespace uzbek // language namespace return n > 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -215,7 +218,7 @@ namespace uzbek // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language From d440b5bf098f61e27dea3a2689e8a0c4ad5f6a13 Mon Sep 17 00:00:00 2001 From: nobs2p Date: Sun, 18 May 2025 00:24:25 +0300 Subject: [PATCH 489/527] Fix FORWARD session host handling in SAM; refactor SAMSocket::ProcessStreamForward - Fixed validation of HOST and PORT parameters for FORWARD sessions: - Improved IP address parsing with fallback to 127.0.0.1 if invalid - Added checks for required parameters (ID, HOST, PORT) - General cleanup and refactoring for improved readability and stability Signed-off-by: nobs2p --- libi2pd_client/SAM.cpp | 90 +++++++++++++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 24 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index f0df414c..96f2c2ee 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -637,53 +637,95 @@ namespace client SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); } - void SAMSocket::ProcessStreamForward (char * buf, size_t len) + void SAMSocket::ProcessStreamForward(char* buf, size_t len) { - LogPrint (eLogDebug, "SAM: Stream forward: ", buf); + LogPrint(eLogDebug, "SAM: Stream forward: ", buf); + std::map params; - ExtractParams (buf, params); - std::string& id = params[SAM_PARAM_ID]; - auto session = m_Owner.FindSession (id); + ExtractParams(buf, params); + + const auto itId = params.find(SAM_PARAM_ID); + if (itId == params.end()) + { + SendSessionI2PError("Missing ID"); + return; + } + const std::string& id = itId->second; + + auto session = m_Owner.FindSession(id); if (!session) { - SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); + SendMessageReply(SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); return; } - if (session->GetLocalDestination ()->IsAcceptingStreams ()) + if (session->GetLocalDestination()->IsAcceptingStreams()) { - SendSessionI2PError ("Already accepting"); + SendSessionI2PError("Already accepting"); return; } - auto it = params.find (SAM_PARAM_PORT); - if (it == params.end ()) + + const auto itPort = params.find(SAM_PARAM_PORT); + if (itPort == params.end()) { - SendSessionI2PError ("PORT is missing"); + SendSessionI2PError("PORT is missing"); return; } - auto port = std::stoi (it->second); + + const std::string& portStr = itPort->second; + if (!std::all_of(portStr.begin(), portStr.end(), ::isdigit)) + { + SendSessionI2PError("Port must be numeric"); + return; + } + + int port = std::stoi(portStr); if (port <= 0 || port >= 0xFFFF) { - SendSessionI2PError ("Invalid PORT"); + SendSessionI2PError("Invalid port"); return; } - boost::system::error_code ec; - auto ep = m_Socket.remote_endpoint (ec); - if (ec) + + boost::asio::ip::tcp::endpoint ep; + const auto itHost = params.find(SAM_PARAM_HOST); + + if (itHost != params.end()) { - SendSessionI2PError ("Socket error"); - return; + boost::system::error_code ec; + auto addr = boost::asio::ip::make_address(itHost->second, ec); + if (ec) + { + SendSessionI2PError("Invalid IP Address in HOST"); + return; + } + ep = boost::asio::ip::tcp::endpoint(addr, port); } - ep.port (port); + else + { + boost::system::error_code ec; + ep = m_Socket.remote_endpoint(ec); + if (ec) + { + SendSessionI2PError("Socket error: cannot get remote endpoint"); + return; + } + ep.port(port); + } + m_SocketType = eSAMSocketTypeForward; m_ID = id; m_IsAccepting = true; - std::string& silent = params[SAM_PARAM_SILENT]; - if (silent == SAM_VALUE_TRUE) m_IsSilent = true; - session->GetLocalDestination ()->AcceptStreams (std::bind (&SAMSocket::HandleI2PForward, - shared_from_this (), std::placeholders::_1, ep)); - SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); + + auto itSilent = params.find(SAM_PARAM_SILENT); + if (itSilent != params.end() && itSilent->second == SAM_VALUE_TRUE) + m_IsSilent = true; + + session->GetLocalDestination()->AcceptStreams( + std::bind(&SAMSocket::HandleI2PForward, shared_from_this(), std::placeholders::_1, ep)); + + SendMessageReply(SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); } + size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data) { LogPrint (eLogDebug, "SAM: Datagram send: ", buf, " ", len); From 4c6be3b85a0d2a4501a718201b869cc7cac74561 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 23 May 2025 21:26:44 -0400 Subject: [PATCH 490/527] disable loss-control --- libi2pd/Streaming.cpp | 125 ++++++++++++++++++++++-------------------- libi2pd/Streaming.h | 18 +++--- 2 files changed, 75 insertions(+), 68 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 25608cbc..4ac4e179 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -84,21 +84,21 @@ namespace stream Stream::Stream (boost::asio::io_context& service, StreamingDestination& local, std::shared_ptr remote, int port): m_Service (service), - m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0), + m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (INITIAL_WINDOW_SIZE), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsIncoming (false), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), - m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsClientChoked (false), - m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_DoubleWinIncCounter (false), m_LocalDestination (local), + m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (true), m_IsClientChoked (false), + m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_IsBufferEmpty (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), - m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), + m_RTT (INITIAL_RTT), m_MinRTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_FastRTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), - m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_WindowSizeTail (0), + m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0), m_LastWindowIncTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed - m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) + m_NumResendAttempts (0), m_NumPacketsToSend (0), m_JitterAccum (0), m_JitterDiv (1), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); m_RemoteIdentity = remote->GetIdentity (); @@ -112,20 +112,20 @@ namespace stream } Stream::Stream (boost::asio::io_context& service, StreamingDestination& local): - m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0), + m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (INITIAL_WINDOW_SIZE), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_Status (eStreamStatusNew), m_IsIncoming (true), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), - m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsClientChoked (false), - m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_DoubleWinIncCounter (false), m_LocalDestination (local), + m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (true), m_IsClientChoked (false), + m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_IsBufferEmpty (false), m_LocalDestination (local), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), - m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), + m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_MinRTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_FastRTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), - m_PrevRTTSample (INITIAL_RTT), m_WindowSizeTail (0), m_Jitter (0), m_MinPacingTime (0), + m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0), m_LastWindowIncTime (0), m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed - m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) + m_NumResendAttempts (0), m_NumPacketsToSend (0), m_JitterAccum (0), m_JitterDiv (1), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); auto outboundSpeed = local.GetOwner ()->GetStreamingOutboundSpeed (); @@ -389,6 +389,7 @@ namespace stream m_IsClientChoked = true; m_IsWinDropped = false; m_DropWindowDelaySequenceNumber = m_SequenceNumber; + m_IsFirstRttSample = true; UpdatePacingTime (); } } @@ -588,47 +589,53 @@ namespace stream if (m_IsFirstRttSample && !m_IsFirstACK) { m_RTT = rttSample; + m_MinRTT = m_RTT; m_SlowRTT = rttSample; - m_SlowRTT2 = rttSample; + m_FastRTT = rttSample; m_PrevRTTSample = rttSample; - m_Jitter = rttSample / 10; // 10% - m_Jitter += 15; // for low-latency connections + m_Jitter = rttSample / 5; // 20% + m_Jitter += 3; // for low-latency connections + m_JitterAccum = m_Jitter; + m_JitterDiv = 1; m_IsFirstRttSample = false; } else + { m_RTT = (m_PrevRTTSample + rttSample) / 2; + } if (!m_IsWinDropped) { m_SlowRTT = SLOWRTT_EWMA_ALPHA * m_RTT + (1.0 - SLOWRTT_EWMA_ALPHA) * m_SlowRTT; - m_SlowRTT2 = RTT_EWMA_ALPHA * m_RTT + (1.0 - RTT_EWMA_ALPHA) * m_SlowRTT2; + m_FastRTT = RTT_EWMA_ALPHA * m_RTT + (1.0 - RTT_EWMA_ALPHA) * m_FastRTT; // calculate jitter double jitter = 0; if (rttSample > m_PrevRTTSample) jitter = rttSample - m_PrevRTTSample; else if (rttSample < m_PrevRTTSample) jitter = m_PrevRTTSample - rttSample; - else - jitter = rttSample / 10; // 10% - jitter += 15; // for low-latency connections - m_Jitter = (0.05 * jitter) + (1.0 - 0.05) * m_Jitter; + if (jitter) + { + jitter += 3; // for low-latency connections + m_JitterAccum += jitter; + m_Jitter = m_JitterAccum / m_JitterDiv; + m_JitterDiv++; + } + if (m_MinRTT > m_RTT) + { + m_MinRTT = m_RTT; + m_FastRTT = m_MinRTT + m_Jitter; + m_SlowRTT = m_MinRTT + m_Jitter; + } } - if (rttSample > m_SlowRTT) + if (m_IsBufferEmpty || m_FastRTT >= m_MinRTT + m_Jitter*3 || m_RTT >= m_MinRTT + m_Jitter*3 || m_SlowRTT >= m_MinRTT + m_Jitter*3 || m_RTT > m_FastRTT) { incCounter = 0; - m_DoubleWinIncCounter = 1; - } - else if (rttSample < m_SlowRTT) - { - if (m_DoubleWinIncCounter) - { - incCounter = incCounter * 2; - m_DoubleWinIncCounter = 0; - } + m_WindowIncCounter = 0; } m_WindowIncCounter = m_WindowIncCounter + incCounter; // // delay-based CC - if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped && !m_IsClientChoked) // Drop window if RTT grows too fast, late detection + if ((m_SlowRTT > m_MinRTT + m_Jitter*6) && !m_IsWinDropped && !m_IsClientChoked) // Drop window if RTT grows too fast { LogPrint (eLogDebug, "Streaming: Congestion detected, reduce window size"); ProcessWindowDrop (); @@ -852,6 +859,8 @@ namespace stream packets.push_back (p); numMsgs--; } + if (m_SendBuffer.GetSize() == 0) m_IsBufferEmpty = true; + else m_IsBufferEmpty = false; if (packets.size () > 0) { if (m_SavedPackets.empty ()) // no NACKS @@ -1324,7 +1333,7 @@ namespace stream m_NumPacketsToSend = 1; m_PacingTimeRem = 0; } m_IsSendTime = true; - if (m_WindowIncCounter && (m_WindowSize < MAX_WINDOW_SIZE || m_WindowDropTargetSize) && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime && m_RTT <= m_SlowRTT) + if (m_WindowIncCounter && (m_WindowSize < MAX_WINDOW_SIZE || m_WindowDropTargetSize) && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) { float winSize = m_WindowSize; if (m_WindowDropTargetSize) @@ -1372,14 +1381,9 @@ namespace stream else break; } - m_LastWindowIncTime = ts; UpdatePacingTime (); } - else if (m_WindowIncCounter && m_WindowSize == MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) - { - m_WindowSizeTail = m_WindowSizeTail + m_WindowIncCounter; - if (m_WindowSizeTail > MAX_WINDOW_SIZE) m_WindowSizeTail = MAX_WINDOW_SIZE; - } + m_LastWindowIncTime = ts; if (m_IsNAcked || m_IsResendNeeded || m_IsClientChoked) // resend packets ResendPacket (); else if (m_WindowSize > int(m_SentPackets.size ())) // send packets @@ -1445,7 +1449,7 @@ namespace stream { if (ts >= it->sendTime + m_RTO) { - if (ts < it->sendTime + m_RTO*2) + if (ts < it->sendTime + m_RTO*3) it->resent = true; else it->resent = false; @@ -1461,7 +1465,7 @@ namespace stream { if (ts >= it->sendTime + m_RTO) { - if (ts < it->sendTime + m_RTO*2) + if (ts < it->sendTime + m_RTO*3) it->resent = true; else it->resent = false; @@ -1483,7 +1487,18 @@ namespace stream if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED && !m_IsClientChoked) { LogPrint (eLogDebug, "Streaming: Packet loss, reduce window size"); - ProcessWindowDrop (); + if (m_WindowDropTargetSize) + m_LastWindowDropSize = m_WindowDropTargetSize; + else + m_LastWindowDropSize = m_WindowSize; + m_WindowDropTargetSize = m_LastWindowDropSize * 0.75; // -25% to drain queue + if (m_WindowDropTargetSize < MIN_WINDOW_SIZE) + m_WindowDropTargetSize = MIN_WINDOW_SIZE; + m_WindowIncCounter = 0; // disable window growth + m_DropWindowDelaySequenceNumber = m_SequenceNumber + int(m_WindowDropTargetSize); + m_IsFirstACK = true; // ignore first RTT sample + m_IsWinDropped = true; // don't drop window twice + UpdatePacingTime (); } } else if (m_IsTimeOutResend) @@ -1680,10 +1695,11 @@ namespace stream void Stream::UpdatePacingTime () { + double rtt = m_MinRTT + m_Jitter*2; if (m_WindowDropTargetSize) - m_PacingTime = std::round (m_RTT*1000/m_WindowDropTargetSize); + m_PacingTime = std::round (rtt*1000/m_WindowDropTargetSize); else - m_PacingTime = std::round (m_RTT*1000/m_WindowSize); + m_PacingTime = std::round (rtt*1000/m_WindowSize); if (m_MinPacingTime && m_PacingTime < m_MinPacingTime) m_PacingTime = m_MinPacingTime; } @@ -1691,28 +1707,16 @@ namespace stream void Stream::ProcessWindowDrop () { if (m_WindowDropTargetSize) - m_WindowDropTargetSize = (m_WindowDropTargetSize / 2) * 0.75; // congestion window size and -25% to drain queue + m_LastWindowDropSize = m_WindowDropTargetSize * ((m_MinRTT + m_Jitter*4) / m_FastRTT); else - { - if (m_WindowSize < m_LastWindowDropSize) - { - m_LastWindowDropSize = std::max ((m_WindowSize - MAX_WINDOW_SIZE_INC_PER_RTT), (m_WindowSize - (m_LastWindowDropSize - m_WindowSize))); - if (m_LastWindowDropSize < MIN_WINDOW_SIZE) m_LastWindowDropSize = MIN_WINDOW_SIZE; - } - else - { - m_LastWindowDropSize = std::max ((m_WindowSize - MAX_WINDOW_SIZE_INC_PER_RTT), ((m_LastWindowDropSize + m_WindowSize + m_WindowSizeTail) / 2)); - if (m_LastWindowDropSize > MAX_WINDOW_SIZE) m_LastWindowDropSize = MAX_WINDOW_SIZE; - } - m_WindowDropTargetSize = m_LastWindowDropSize * 0.75; // -25% to drain queue - } + m_LastWindowDropSize = m_WindowSize * ((m_MinRTT + m_Jitter*4) / m_FastRTT); + m_WindowDropTargetSize = m_LastWindowDropSize * 0.75; // -25% to drain queue if (m_WindowDropTargetSize < MIN_WINDOW_SIZE) m_WindowDropTargetSize = MIN_WINDOW_SIZE; m_WindowIncCounter = 0; // disable window growth m_DropWindowDelaySequenceNumber = m_SequenceNumber + int(m_WindowDropTargetSize); m_IsFirstACK = true; // ignore first RTT sample m_IsWinDropped = true; // don't drop window twice - m_WindowSizeTail = 0; UpdatePacingTime (); } @@ -1730,10 +1734,11 @@ namespace stream m_WindowSize = INITIAL_WINDOW_SIZE; } m_LastWindowDropSize = 0; - m_WindowIncCounter = 0; m_IsFirstRttSample = true; m_IsFirstACK = true; - m_WindowSizeTail = 0; + m_WindowIncCounter = 0; // disable window growth + m_DropWindowDelaySequenceNumber = m_SequenceNumber - int(m_SentPackets.size ()) + INITIAL_WINDOW_SIZE; + m_IsWinDropped = true; // don't drop window twice UpdatePacingTime (); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 570fdd1d..9fbcb178 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -61,10 +61,10 @@ namespace stream const int INITIAL_WINDOW_SIZE = 10; const int MIN_WINDOW_SIZE = 3; const int MAX_WINDOW_SIZE = 512; - const int MAX_WINDOW_SIZE_INC_PER_RTT = 16; - const double RTT_EWMA_ALPHA = 0.25; - const double SLOWRTT_EWMA_ALPHA = 0.05; - const double PREV_SPEED_KEEP_TIME_COEFF = 0.35; // 0.1 - 1 // how long will the window size stay around the previous drop level, less is longer + const int MAX_WINDOW_SIZE_INC_PER_RTT = 12; + const double RTT_EWMA_ALPHA = 0.1; + const double SLOWRTT_EWMA_ALPHA = 0.02; + const double PREV_SPEED_KEEP_TIME_COEFF = 0.2; // 0.1 - 1 // how long will the window size stay around the previous drop level, less is longer const int MIN_RTO = 20; // in milliseconds const int INITIAL_RTT = 1500; // in milliseconds const int INITIAL_RTO = 9000; // in milliseconds @@ -79,7 +79,7 @@ namespace stream const uint64_t SEND_INTERVAL_VARIANCE = 2000; // in microseconds const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL = 7500; // in milliseconds const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL_VARIANCE = 3200; // in milliseconds - const bool LOSS_BASED_CONTROL_ENABLED = 1; // 0/1 + const bool LOSS_BASED_CONTROL_ENABLED = 0; // 0/1 const uint64_t STREAMING_DESTINATION_POOLS_CLEANUP_INTERVAL = 646; // in seconds struct Packet @@ -281,7 +281,7 @@ namespace stream bool m_IsTimeOutResend; bool m_IsImmediateAckRequested; bool m_IsRemoteLeaseChangeInProgress; - bool m_DoubleWinIncCounter; + bool m_IsBufferEmpty; StreamingDestination& m_LocalDestination; std::shared_ptr m_RemoteIdentity; std::shared_ptr m_TransientVerifier; // in case of offline key @@ -299,14 +299,16 @@ namespace stream uint16_t m_Port; SendBufferQueue m_SendBuffer; - double m_RTT, m_SlowRTT, m_SlowRTT2; + double m_RTT, m_MinRTT, m_SlowRTT, m_FastRTT; float m_WindowSize, m_LastWindowDropSize, m_WindowDropTargetSize; - int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample, m_WindowSizeTail; + int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; double m_Jitter; uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, // microseconds m_LastSendTime, m_LastACKRecieveTime, m_ACKRecieveInterval, m_RemoteLeaseChangeTime, m_LastWindowIncTime; // milliseconds uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed int m_NumResendAttempts, m_NumPacketsToSend; + uint64_t m_JitterAccum; + int m_JitterDiv; size_t m_MTU; }; From 606881898bdce1b37a8ab865b0508109bf595618 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 25 May 2025 14:49:58 -0400 Subject: [PATCH 491/527] fill phony record for inbound tunnel with x25519 public key --- libi2pd/Tunnel.cpp | 18 ++++++++--- libi2pd/Tunnel.h | 10 +++--- libi2pd/TunnelConfig.cpp | 68 +++++++++++++++++++++++++++++++++++++++- libi2pd/TunnelConfig.h | 40 ++++++++++++++--------- 4 files changed, 110 insertions(+), 26 deletions(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 1b317121..1347b5b8 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -29,7 +29,7 @@ namespace i2p { namespace tunnel { - Tunnel::Tunnel (std::shared_ptr config): + Tunnel::Tunnel (std::shared_ptr config): TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()), m_Config (config), m_IsShortBuildMessage (false), m_Pool (nullptr), m_State (eTunnelStatePending), m_FarEndTransports (i2p::data::RouterInfo::eAllTransports), @@ -44,7 +44,13 @@ namespace tunnel void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr outboundTunnel) { auto numHops = m_Config->GetNumHops (); - const int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : MAX_NUM_RECORDS; + bool insertPhonyRecord = m_Config->IsInbound() && numHops < MAX_NUM_RECORDS; + if (insertPhonyRecord) + { + m_Config->CreatePhonyHop (); + numHops++; + } + int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : MAX_NUM_RECORDS; auto msg = numRecords <= STANDARD_NUM_RECORDS ? NewI2NPShortMessage () : NewI2NPMessage (); *msg->GetPayload () = numRecords; const size_t recordSize = m_Config->IsShort () ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE; @@ -52,8 +58,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(), m_Pool ? m_Pool->GetRng () : 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; TunnelHopConfig * hop = m_Config->GetFirstHop (); @@ -61,7 +66,7 @@ namespace tunnel while (hop) { uint32_t msgID; - if (hop->next) // we set replyMsgID for last hop only + if (hop->next && hop->next->ident) // we set replyMsgID for last non-phony hop only RAND_bytes ((uint8_t *)&msgID, 4); else msgID = replyMsgID; @@ -89,6 +94,9 @@ namespace tunnel } hop = hop->prev; } + // delete phony hop after encryption + if (insertPhonyRecord) m_Config->DeletePhonyHop (); + msg->FillI2NPMessageHeader (m_Config->IsShort () ? eI2NPShortTunnelBuild : eI2NPVariableTunnelBuild); auto s = shared_from_this (); msg->onDrop = [s]() diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 5d21cd8b..78e2d124 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -81,12 +81,12 @@ namespace tunnel /** function for visiting a hops stored in a tunnel */ typedef std::function)> TunnelHopVisitor; - Tunnel (std::shared_ptr config); + Tunnel (std::shared_ptr config); ~Tunnel (); void Build (uint32_t replyMsgID, std::shared_ptr outboundTunnel = nullptr); - std::shared_ptr GetTunnelConfig () const { return m_Config; } + std::shared_ptr GetTunnelConfig () const { return m_Config; } std::vector > GetPeers () const; std::vector > GetInvertedPeers () const; bool IsShortBuildMessage () const { return m_IsShortBuildMessage; }; @@ -125,7 +125,7 @@ namespace tunnel private: - std::shared_ptr m_Config; + std::shared_ptr m_Config; std::vector m_Hops; bool m_IsShortBuildMessage; std::shared_ptr m_Pool; // pool, tunnel belongs to, or null @@ -139,7 +139,7 @@ namespace tunnel { public: - OutboundTunnel (std::shared_ptr config): + OutboundTunnel (std::shared_ptr config): Tunnel (config), m_Gateway (*this), m_EndpointIdentHash (config->GetLastIdentHash ()) {}; void SendTunnelDataMsgTo (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr msg); @@ -164,7 +164,7 @@ namespace tunnel { public: - InboundTunnel (std::shared_ptr config): Tunnel (config), m_Endpoint (true) {}; + InboundTunnel (std::shared_ptr config): Tunnel (config), m_Endpoint (true) {}; void HandleTunnelDataMsg (std::shared_ptr&& msg) override; virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; bool IsInbound() const override { return true; } diff --git a/libi2pd/TunnelConfig.cpp b/libi2pd/TunnelConfig.cpp index fe0e8573..1ae8f3e9 100644 --- a/libi2pd/TunnelConfig.cpp +++ b/libi2pd/TunnelConfig.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 * @@ -219,6 +219,42 @@ namespace tunnel return tag; } + void LongPhonyTunnelHopConfig::CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID) + { + uint8_t * record = records + recordIndex*TUNNEL_BUILD_RECORD_SIZE; + memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetIdentHash (), 16); + memcpy (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, i2p::transport::transports.GetNextX25519KeysPair ()->GetPublicKey (), 32); + RAND_bytes (record + 48, TUNNEL_BUILD_RECORD_SIZE - 48); + } + + void ShortPhonyTunnelHopConfig::CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID) + { + uint8_t * record = records + recordIndex*SHORT_TUNNEL_BUILD_RECORD_SIZE; + memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetIdentHash (), 16); + memcpy (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, i2p::transport::transports.GetNextX25519KeysPair ()->GetPublicKey (), 32); + RAND_bytes (record + 48, SHORT_TUNNEL_BUILD_RECORD_SIZE - 48); + } + + TunnelConfig::TunnelConfig (const std::vector >& peers, + bool isShort, i2p::data::RouterInfo::CompatibleTransports farEndTransports): + m_IsShort (isShort), m_FarEndTransports (farEndTransports) + { + // inbound + CreatePeers (peers); + m_LastHop->SetNextIdent (i2p::context.GetIdentHash ()); + } + + TunnelConfig::TunnelConfig (const std::vector >& peers, + uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent, bool isShort, + i2p::data::RouterInfo::CompatibleTransports farEndTransports): + m_IsShort (isShort), m_FarEndTransports (farEndTransports) + { + // outbound + CreatePeers (peers); + m_FirstHop->isGateway = false; + m_LastHop->SetReplyHop (replyTunnelID, replyIdent); + } + void TunnelConfig::CreatePeers (const std::vector >& peers) { TunnelHopConfig * prev = nullptr; @@ -245,5 +281,35 @@ namespace tunnel } m_LastHop = prev; } + + void TunnelConfig::CreatePhonyHop () + { + if (m_LastHop && m_LastHop->ident) + { + TunnelHopConfig * hop = nullptr; + if (m_IsShort) + hop = new ShortPhonyTunnelHopConfig (); + else + hop = new LongPhonyTunnelHopConfig (); + if (hop) + { + hop->prev = m_LastHop; + m_LastHop->next = hop; + m_LastHop = hop; + } + } + } + + void TunnelConfig::DeletePhonyHop () + { + if (m_LastHop && !m_LastHop->ident) + { + if (m_LastHop->prev) m_LastHop->prev->next = nullptr; + else m_FirstHop = nullptr; + auto tmp = m_LastHop; + m_LastHop = m_LastHop->prev; + delete tmp; + } + } } } \ No newline at end of file diff --git a/libi2pd/TunnelConfig.h b/libi2pd/TunnelConfig.h index 718a6fdb..a024f359 100644 --- a/libi2pd/TunnelConfig.h +++ b/libi2pd/TunnelConfig.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 * @@ -77,28 +77,35 @@ namespace tunnel uint64_t GetGarlicKey (uint8_t * key) const override; }; + struct PhonyTunnelHopConfig: public ECIESTunnelHopConfig + { + PhonyTunnelHopConfig (): ECIESTunnelHopConfig (nullptr) {} + uint8_t GetRetCode (const uint8_t * records) const override { return 0; } + bool DecryptBuildResponseRecord (uint8_t * records) const override { return true; } + void DecryptRecord (uint8_t * records, int index) const override {} // do nothing + }; + + struct LongPhonyTunnelHopConfig: public PhonyTunnelHopConfig + { + void CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID) override; + }; + + struct ShortPhonyTunnelHopConfig: public PhonyTunnelHopConfig + { + void CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID) override; + }; + class TunnelConfig { public: TunnelConfig (const std::vector >& peers, - bool isShort, i2p::data::RouterInfo::CompatibleTransports farEndTransports = i2p::data::RouterInfo::eAllTransports): // inbound - m_IsShort (isShort), m_FarEndTransports (farEndTransports) - { - CreatePeers (peers); - m_LastHop->SetNextIdent (i2p::context.GetIdentHash ()); - } + bool isShort, i2p::data::RouterInfo::CompatibleTransports farEndTransports = i2p::data::RouterInfo::eAllTransports); // inbound TunnelConfig (const std::vector >& peers, uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent, bool isShort, - i2p::data::RouterInfo::CompatibleTransports farEndTransports = i2p::data::RouterInfo::eAllTransports): // outbound - m_IsShort (isShort), m_FarEndTransports (farEndTransports) - { - CreatePeers (peers); - m_FirstHop->isGateway = false; - m_LastHop->SetReplyHop (replyTunnelID, replyIdent); - } - + i2p::data::RouterInfo::CompatibleTransports farEndTransports = i2p::data::RouterInfo::eAllTransports); // outbound + virtual ~TunnelConfig () { TunnelHopConfig * hop = m_FirstHop; @@ -182,6 +189,9 @@ namespace tunnel } size_t GetRecordSize () const { return m_IsShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE; }; + + void CreatePhonyHop (); + void DeletePhonyHop (); protected: From 35ba14d06a51b50cd161f66b90eba7f44af9e1d3 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 25 May 2025 18:23:22 -0400 Subject: [PATCH 492/527] increase message expiration timeout in SSU2 --- libi2pd/I2NPProtocol.h | 3 ++- libi2pd/SSU2Session.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 911a53bf..39aed10f 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.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 * @@ -155,6 +155,7 @@ namespace tunnel const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_FACTOR = 3; // multiples of RTT const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MIN = 200000; // in microseconds const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX = 2000000; // in microseconds + const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_TRANSIT = 4000000; // in microseconds const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT) const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index cb10f848..8f58ec90 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -468,7 +468,7 @@ namespace transport while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) { auto msg = m_SendQueue.front (); - if (!msg || msg->IsExpired (ts) || msg->GetEnqueueTime() + m_MsgLocalExpirationTimeout < mts) + if (!msg || msg->IsExpired (ts) || msg->GetEnqueueTime() + I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_TRANSIT < mts) { // drop null or expired message if (msg) msg->Drop (); From 9573b21c082c74fe9152f943738a7885223d6d8f Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 26 May 2025 17:35:59 -0400 Subject: [PATCH 493/527] changed log level frm warning to info for some messages --- libi2pd/Streaming.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 4ac4e179..1f849925 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -268,7 +268,7 @@ namespace stream if (receivedSeqn <= m_LastReceivedSequenceNumber) { // we have received duplicate - LogPrint (eLogWarning, "Streaming: Duplicate message ", receivedSeqn, " on sSID=", m_SendStreamID); + LogPrint (eLogInfo, "Streaming: Duplicate message ", receivedSeqn, " on sSID=", m_SendStreamID); if (receivedSeqn <= m_PreviousReceivedSequenceNumber || receivedSeqn == m_LastReceivedSequenceNumber) { m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel); @@ -287,7 +287,7 @@ namespace stream } else { - LogPrint (eLogWarning, "Streaming: Missing messages on sSID=", m_SendStreamID, ": from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1); + LogPrint (eLogInfo, "Streaming: Missing messages on sSID=", m_SendStreamID, ": from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1); // save message and wait for missing message again SavePacket (packet); if (m_LastReceivedSequenceNumber >= 0) @@ -1828,7 +1828,7 @@ namespace stream if (it1 != m_IncomingStreams.end ()) { // already pending - LogPrint(eLogWarning, "Streaming: Incoming streaming with rSID=", receiveStreamID, " already exists"); + LogPrint(eLogInfo, "Streaming: Incoming streaming with rSID=", receiveStreamID, " already exists"); it1->second->ResetRoutingPath (); // Ack was not delivered, changing path DeletePacket (packet); // drop it, because previous should be connected return; From 7ec0c98036fb7d4091f2a6fbc4c38f433dd8b98c Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 28 May 2025 06:39:39 -0400 Subject: [PATCH 494/527] fixed newkeys crash --- libi2pd/Identity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 865beeb8..240862ae 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -496,7 +496,7 @@ namespace data m_Public = std::make_shared(Identity (keys)); memcpy (m_PrivateKey, keys.privateKey, 256); // 256 size_t keyLen = m_Public->GetSigningPrivateKeyLen (); - if (keyLen > 128) m_SigningPrivateKey.resize (keyLen); + m_SigningPrivateKey.resize (keyLen); memcpy (m_SigningPrivateKey.data (), keys.signingPrivateKey, keyLen); m_OfflineSignature.resize (0); m_TransientSignatureLen = 0; From 1b068618bab95a0309012cc25264e01c6171fa22 Mon Sep 17 00:00:00 2001 From: nobs2p Date: Thu, 29 May 2025 12:33:48 +0300 Subject: [PATCH 495/527] Add settunneltype parameter to BOB API for i2pd to configure proxy tunnel type This update introduces the settunneltype command to the BOB API, allowing users to specify the tunnel type as either SOCKS or HTTP proxy. When the tunnel type is set, the corresponding proxy service is automatically started. This enhances flexibility in tunnel configuration through the BOB interface. Signed-off-by: nobs2p --- libi2pd_client/BOB.cpp | 119 ++++++++++++++++++++++++++++++++++++++--- libi2pd_client/BOB.h | 18 +++++++ 2 files changed, 131 insertions(+), 6 deletions(-) diff --git a/libi2pd_client/BOB.cpp b/libi2pd_client/BOB.cpp index 8d94e94b..3f02f779 100644 --- a/libi2pd_client/BOB.cpp +++ b/libi2pd_client/BOB.cpp @@ -383,6 +383,15 @@ namespace client const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; }; const auto destReady = [](const BOBDestination * const dest) { return dest && dest->IsRunning(); }; const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str + const auto getProxyType = [](const i2p::client::I2PService* proxy) -> std::string { + if (!proxy) return "NONE"; + if (dynamic_cast(proxy)) return "SOCKS"; + if (dynamic_cast(proxy)) return "HTTPPROXY"; + return "UNKNOWN"; + }; + const auto isProxyRunning = [](const i2p::client::I2PService* proxy) -> bool { + return proxy != nullptr; + }; // tunnel info const std::string nickname = currentTunnel ? m_Nickname : dest->GetNickname(); @@ -395,6 +404,10 @@ namespace client const bool starting = destExists(dest.get ()) && !destReady(dest.get ()); const bool running = destExists(dest.get ()) && destReady(dest.get ()); const bool stopping = false; + + const i2p::client::I2PService* proxy = m_Owner.GetProxy(nickname); + const std::string proxyType = getProxyType(proxy); + const bool proxyStatus = isProxyRunning(proxy); // build line std::stringstream ss; @@ -403,7 +416,8 @@ namespace client << "RUNNING: " << bool_str(running) << " " << "STOPPING: " << bool_str(stopping) << " " << "KEYS: " << bool_str(keys) << " " << "QUIET: " << bool_str(quiet) << " " << "INPORT: " << inport << " " << "INHOST: " << inhost << " " - << "OUTPORT: " << outport << " " << "OUTHOST: " << outhost; + << "OUTPORT: " << outport << " " << "OUTHOST: " << outhost << " " + << "PROXYTYPE: "<< proxyType << " " << "PROXYSTART: " << bool_str(proxyStatus); out = ss.str(); } @@ -468,11 +482,51 @@ namespace client m_Nickname, m_InHost, m_OutHost, m_InPort, m_OutPort, m_IsQuiet); m_Owner.AddDestination (m_Nickname, m_CurrentDestination); } - if (m_InPort) - m_CurrentDestination->CreateInboundTunnel (m_InPort, m_InHost); - if (m_OutPort && !m_OutHost.empty ()) - m_CurrentDestination->CreateOutboundTunnel (m_OutHost, m_OutPort, m_IsQuiet); - m_CurrentDestination->Start (); + if (!m_tunnelType.has_value()) + { + if (m_InPort) + m_CurrentDestination->CreateInboundTunnel (m_InPort, m_InHost); + if (m_OutPort && !m_OutHost.empty ()) + m_CurrentDestination->CreateOutboundTunnel (m_OutHost, m_OutPort, m_IsQuiet); + m_CurrentDestination->Start (); + } + else + { + switch (*m_tunnelType) + { + case TunnelType::SOCKS: + try + { + auto SocksProxy = std::make_unique(m_Nickname, m_InHost, m_InPort, + false, m_OutHost, m_OutPort, m_CurrentDestination->GetLocalDestination()); + SocksProxy->Start(); + m_Owner.SetProxy(m_Nickname, std::move(SocksProxy)); + } + catch (std::exception& e) + { + LogPrint(eLogCritical, "Clients: Exception in SOCKS Proxy: ", e.what()); + ThrowFatal ("Unable to start SOCKS Proxy at ", m_InHost, ":", m_InPort, ": ", e.what ()); + } + break; + case TunnelType::HTTP_PROXY: + try + { + auto HttpProxy = std::make_unique(m_Nickname, m_InHost, m_InPort, + m_OutHost, true, true, m_CurrentDestination->GetLocalDestination()); + HttpProxy->Start(); + m_Owner.SetProxy(m_Nickname, std::move(HttpProxy)); + } + catch (std::exception& e) + { + LogPrint(eLogCritical, "Clients: Exception in HTTP Proxy: ", e.what()); + ThrowFatal ("Unable to start HTTP Proxy at ", m_InHost, ":", m_InPort, ": ", e.what ()); + } + break; + default: + SendReplyError("Unsupported tunnel type."); + return; + } + } SendReplyOK ("Tunnel starting"); m_IsActive = true; } @@ -486,10 +540,15 @@ namespace client return; } auto dest = m_Owner.FindDestination (m_Nickname); + auto proxy = m_Owner.GetProxy (m_Nickname); if (dest) { dest->StopTunnels (); SendReplyOK ("Tunnel stopping"); + if (proxy) + { + m_Owner.RemoveProxy (m_Nickname); + } } else SendReplyError ("tunnel not found"); @@ -522,10 +581,13 @@ namespace client if(*operand) { m_CurrentDestination = m_Owner.FindDestination (operand); + auto proxy = m_Owner.GetProxy (operand); if (m_CurrentDestination) { m_Keys = m_CurrentDestination->GetKeys (); m_IsActive = m_CurrentDestination->IsRunning (); + if(proxy) + m_IsActive = true; m_Nickname = operand; } if (m_Nickname == operand) @@ -843,6 +905,27 @@ namespace client SendReplyError("No such command"); } } + + void BOBCommandSession::SetTunnelTypeCommandHandler (const char * operand, size_t len) + { + std::string_view sv(operand, len); + LogPrint (eLogDebug, "BOB: settunneltype ", operand); + if (sv == "socks") + { + m_tunnelType = TunnelType::SOCKS; + SendReplyOK ("tunnel type set to SOCKS"); + } + else if (sv == "httpproxy") + { + m_tunnelType = TunnelType::HTTP_PROXY; + SendReplyOK ("tunnel type set to HTTP proxy"); + } + else + { + m_tunnelType.reset(); + SendReplyError ("no tunnel type has been set"); + } + } BOBCommandChannel::BOBCommandChannel (const std::string& address, uint16_t port): RunnableService ("BOB"), @@ -871,6 +954,7 @@ namespace client m_CommandHandlers[BOB_COMMAND_OPTION] = &BOBCommandSession::OptionCommandHandler; m_CommandHandlers[BOB_COMMAND_STATUS] = &BOBCommandSession::StatusCommandHandler; m_CommandHandlers[BOB_COMMAND_HELP] = &BOBCommandSession::HelpCommandHandler; + m_CommandHandlers[BOB_COMMAND_SETTUNNELTYPE] = &BOBCommandSession::SetTunnelTypeCommandHandler; // command -> help string m_HelpStrings[BOB_COMMAND_ZAP] = BOB_HELP_ZAP; m_HelpStrings[BOB_COMMAND_QUIT] = BOB_HELP_QUIT; @@ -893,6 +977,7 @@ namespace client m_HelpStrings[BOB_COMMAND_OPTION] = BOB_HELP_OPTION; m_HelpStrings[BOB_COMMAND_STATUS] = BOB_HELP_STATUS; m_HelpStrings[BOB_COMMAND_HELP] = BOB_HELP_HELP; + m_HelpStrings[BOB_COMMAND_SETTUNNELTYPE] = BOB_HELP_SETTUNNELTYPE; } BOBCommandChannel::~BOBCommandChannel () @@ -937,6 +1022,28 @@ namespace client return it->second; return nullptr; } + + void BOBCommandChannel::SetProxy (const std::string& name, std::unique_ptr proxy) + { + m_proxy[name] = std::move(proxy); + } + + const I2PService* BOBCommandChannel::GetProxy(const std::string& name) const + { + auto it = m_proxy.find(name); + if (it != m_proxy.end() && it->second) + return it->second.get(); + return nullptr; + } + + void BOBCommandChannel::RemoveProxy(const std::string& name) + { + auto it = m_proxy.find (name); + if (it != m_proxy.end ()) + { + m_proxy.erase (it); + } + } void BOBCommandChannel::Accept () { diff --git a/libi2pd_client/BOB.h b/libi2pd_client/BOB.h index f5aefd0a..7b92c85d 100644 --- a/libi2pd_client/BOB.h +++ b/libi2pd_client/BOB.h @@ -14,12 +14,15 @@ #include #include #include +#include #include #include "util.h" #include "I2PTunnel.h" #include "I2PService.h" #include "Identity.h" #include "LeaseSet.h" +#include "SOCKS.h" +#include "HTTPProxy.h" namespace i2p { @@ -48,7 +51,9 @@ namespace client const char BOB_COMMAND_OPTION[] = "option"; const char BOB_COMMAND_STATUS[] = "status"; const char BOB_COMMAND_HELP[] = "help"; + const char BOB_COMMAND_SETTUNNELTYPE[] = "settunneltype"; + const char BOB_HELP_ZAP[] = "zap - Shuts down BOB."; const char BOB_HELP_QUIT[] = "quit - Quits this session with BOB."; const char BOB_HELP_START[] = "start - Starts the current nicknamed tunnel."; @@ -70,6 +75,7 @@ namespace client const char BOB_HELP_OPTION[] = "option = - Set an option. NOTE: Don't use any spaces."; const char BOB_HELP_STATUS[] = "status - Display status of a nicknamed tunnel."; const char BOB_HELP_HELP [] = "help - Get help on a command."; + const char BOB_HELP_SETTUNNELTYPE[] = "settunneltype - Sets socks or http proxy tunnel type."; class BOBI2PTunnelIncomingConnection: public I2PTunnelConnection { @@ -232,6 +238,7 @@ namespace client void OptionCommandHandler (const char * operand, size_t len); void StatusCommandHandler (const char * operand, size_t len); void HelpCommandHandler (const char * operand, size_t len); + void SetTunnelTypeCommandHandler (const char * operand, size_t len); private: @@ -258,6 +265,13 @@ namespace client i2p::data::PrivateKeys m_Keys; std::map m_Options; std::shared_ptr m_CurrentDestination; + + enum class TunnelType + { + SOCKS = 0, + HTTP_PROXY = 1 + }; + std::optional m_tunnelType; }; typedef void (BOBCommandSession::*BOBCommandHandler)(const char * operand, size_t len); @@ -275,6 +289,9 @@ namespace client void AddDestination (const std::string& name, std::shared_ptr dest); void DeleteDestination (const std::string& name); std::shared_ptr FindDestination (const std::string& name); + void SetProxy (const std::string& name, std::unique_ptr proxy); + const I2PService* GetProxy(const std::string& name) const; + void RemoveProxy(const std::string& name); private: @@ -287,6 +304,7 @@ namespace client std::map > m_Destinations; std::map m_CommandHandlers; std::map m_HelpStrings; + std::map> m_proxy; public: From 021431d97a70589b9cc352aff0494fb17266ed8d Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 1 Jun 2025 08:40:44 -0400 Subject: [PATCH 496/527] disable post-quantum for release --- libi2pd/Crypto.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 125a217c..80650098 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -33,9 +33,9 @@ # if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL # define OPENSSL_SIPHASH 1 # endif -# if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0 -# define OPENSSL_PQ 1 -# endif +//# if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0 +//# define OPENSSL_PQ 1 +//# endif #endif namespace i2p From 56bd94a1cb700a99c0ca48a5ee2f2a4bf1ddb583 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 1 Jun 2025 08:41:20 -0400 Subject: [PATCH 497/527] 2.57.0 --- ChangeLog | 28 ++++++++++++++++++++++++++++ contrib/rpm/i2pd-git.spec | 5 ++++- contrib/rpm/i2pd.spec | 5 ++++- debian/changelog | 6 ++++++ libi2pd/version.h | 4 ++-- 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 23864c0e..e8d6daf7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,34 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.57.0] - 2025-06-02 +### Added +- Local domain sockets for I2PControl +- "keys=shareddest" tunnel param to run on shared local destination +- HTTP and SOCKS proxy through BOB +- Localization to Hebrew and Hindi +- NTCP2 probing resistance +- Support SAM v1 datagram sessions without port +- OpenIndiana support +### Changed +- Don't request LeaseSet until I2CP destination is ready +- Keep receiving new data from I2PTunnel/SAM socket while previous is being sent to stream +- Insert phony record to inbound tunnel build message with real x25519 ephemeral key +- Set min peer test version to 0.9.62 +- Increase I2NP message expiration timeout in SSU2 +- Cleanup ECIESx25519 new session reply keys on Alice side +- Reduced router profile persist interval to 22 minutes +- SSU2 max padding size to 32 bytes +- Send SSU2 path challenge of 8 bytes. Add datetime and address blocks +- Don't delete trusted routers from netdb +- Disable loss-control in streaming +- Reseeds list +### Fixed +- Crash after SAM stream disconnect +- FORWARD session host handling in SAM +- x86 build for Haiku +- SSU2 session's remote endpoint after receiving path response + ## [2.56.0] - 2025-02-11 ### Added - Config params for shared local destination diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 2083ba18..fd431347 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -1,7 +1,7 @@ %define git_hash %(git rev-parse HEAD | cut -c -7) Name: i2pd-git -Version: 2.56.0 +Version: 2.57.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -148,6 +148,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Mon Jun 02 2025 orignal - 2.57.0 +- update to 2.57.0 + * Tue Feb 11 2025 orignal - 2.56.0 - update to 2.56.0 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 4eb558ba..2d3d4cbb 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.56.0 +Version: 2.57.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git @@ -146,6 +146,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Mon Jun 02 2025 orignal - 2.57.0 +- update to 2.57.0 + * Tue Feb 11 2025 orignal - 2.56.0 - update to 2.56.0 diff --git a/debian/changelog b/debian/changelog index d170f534..8b1e6237 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.57.0-1) unstable; urgency=medium + + * updated to version 2.57.0/0.9.66 + + -- orignal Mon, 02 Jun 2025 16:00:00 +0000 + i2pd (2.56.0-1) unstable; urgency=medium * updated to version 2.56.0/0.9.65 diff --git a/libi2pd/version.h b/libi2pd/version.h index 1e63ae08..45f209ac 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -18,7 +18,7 @@ #define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 56 +#define I2PD_VERSION_MINOR 57 #define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #ifdef GITVER @@ -33,7 +33,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 65 +#define I2P_VERSION_MICRO 66 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) #define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) From 37fd4b4422cc0c1fbe8321d4de9fcaaff2220cdc Mon Sep 17 00:00:00 2001 From: Daniel Bermond Date: Mon, 2 Jun 2025 23:28:51 -0300 Subject: [PATCH 498/527] tests: fix test-base-64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test-base-64 was not updated after the following commits: https://github.com/PurpleI2P/i2pd/commit/93cc810f2987cc90b7a4f8699655af43b36c6c23 https://github.com/PurpleI2P/i2pd/commit/bbf5c1655a5f331b36cc7e16ad0bba86bb36eed4 This leads to errors like: In file included from /usr/include/c++/15.1.1/cassert:46, from /build/i2pd/src/i2pd-2.57.0/tests/test-base-64.cpp:1: /build/i2pd/src/i2pd-2.57.0/tests/test-base-64.cpp: In function ‘int main()’: /build/i2pd/src/i2pd-2.57.0/tests/test-base-64.cpp:14:28: error: too many arguments to function ‘std::string i2p::data::ByteStreamToBase64(const uint8_t*, size_t)’ 14 | assert(ByteStreamToBase64(NULL, 0, NULL, 0) == 0); | ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~ and: In file included from /build/i2pd/src/i2pd-2.57.0/tests/test-base-64.cpp:4: /build/i2pd/src/i2pd-2.57.0/build/../libi2pd/Base.h:21:21: note: declared here 21 | std::string ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount); | ^~~~~~~~~~~~~~~~~~ /build/i2pd/src/i2pd-2.57.0/tests/test-base-64.cpp:14:47: error: no match for ‘operator==’ (operand types are ‘std::string’ {aka ‘std::__cxx11::basic_string’} and ‘int’) 14 | assert(ByteStreamToBase64(NULL, 0, NULL, 0) == 0); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^~ ~ | | | | | int | std::string {aka std::__cxx11::basic_string} among others. --- tests/test-base-64.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/test-base-64.cpp b/tests/test-base-64.cpp index 0ab46c06..63817bf4 100644 --- a/tests/test-base-64.cpp +++ b/tests/test-base-64.cpp @@ -11,8 +11,7 @@ int main() { char out[16]; /* bytes -> b64 */ - assert(ByteStreamToBase64(NULL, 0, NULL, 0) == 0); - assert(ByteStreamToBase64(NULL, 0, out, sizeof(out)) == 0); + assert(ByteStreamToBase64(NULL, 0) == ""); assert(Base64EncodingBufferSize(2) == 4); assert(Base64EncodingBufferSize(4) == 8); @@ -23,19 +22,20 @@ int main() { assert(Base64EncodingBufferSize(12) == 16); assert(Base64EncodingBufferSize(13) == 20); - assert(ByteStreamToBase64((uint8_t *) in, in_len, out, sizeof(out)) == 8); - assert(memcmp(out, "dGVzdA==", 8) == 0); + const std::string out_str(ByteStreamToBase64((uint8_t *) in, in_len)); + assert(out_str.size() == 8); + assert(out_str == "dGVzdA=="); /* b64 -> bytes */ - assert(Base64ToByteStream(NULL, 0, NULL, 0) == 0); - assert(Base64ToByteStream(NULL, 0, (uint8_t *) out, sizeof(out)) == 0); + assert(Base64ToByteStream("", NULL, 0) == 0); + assert(Base64ToByteStream("", (uint8_t *) out, sizeof(out)) == 0); in = "dGVzdA=="; /* valid b64 */ - assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 4); + assert(Base64ToByteStream(in, (uint8_t *) out, sizeof(out)) == 4); assert(memcmp(out, "test", 4) == 0); in = "dGVzdA="; /* invalid b64 : not padded */ - assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 0); + assert(Base64ToByteStream(in, (uint8_t *) out, sizeof(out)) == 0); in = "dG/z.A=="; /* invalid b64 : char not from alphabet */ // assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 0); From 2631255b467760d978f3cbd02e1d65e902b9e378 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Jun 2025 07:57:08 -0400 Subject: [PATCH 499/527] enable post quantum back --- libi2pd/Crypto.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 80650098..125a217c 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -33,9 +33,9 @@ # if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL # define OPENSSL_SIPHASH 1 # endif -//# if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0 -//# define OPENSSL_PQ 1 -//# endif +# if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0 +# define OPENSSL_PQ 1 +# endif #endif namespace i2p From 6ad6a2501eac86623db303bceee70a1989e538e6 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Jun 2025 07:58:31 -0400 Subject: [PATCH 500/527] fixed incorrect limit in strsplit --- libi2pd/HTTP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index 3cd5c193..8c7c8491 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.cpp @@ -55,7 +55,7 @@ namespace http static void strsplit(std::string_view line, std::vector &tokens, char delim, std::size_t limit = 0) { - size_t count = 0, pos; + size_t count = 1, pos; while ((pos = line.find (delim)) != line.npos) { count++; From cbb5250dd4f929f9b0f408186b4d74b745e7d49a Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Jun 2025 18:46:22 -0400 Subject: [PATCH 501/527] don't schedule resend timer while choked --- libi2pd/Streaming.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 1f849925..8d125e6f 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1416,6 +1416,7 @@ namespace stream m_SendTimer.cancel (); // if no ack's in RTO, disable fast retransmit m_IsTimeOutResend = true; m_IsNAcked = false; + m_IsClientChoked = false; m_IsResendNeeded = false; m_NumPacketsToSend = 1; ResendPacket (); // send one packet per RTO, waiting for ack @@ -1538,7 +1539,7 @@ namespace stream } else if (!m_IsClientChoked) SendBuffer (); - if (!m_IsNAcked && !m_IsResendNeeded) ScheduleResend (); + if (!m_IsNAcked && !m_IsResendNeeded && !m_IsClientChoked) ScheduleResend (); if (m_IsClientChoked) ScheduleSend (); } From 9c0051e73b9f56013ea613af621a53eab47d6ae5 Mon Sep 17 00:00:00 2001 From: r4sas Date: Wed, 4 Jun 2025 13:49:44 +0300 Subject: [PATCH 502/527] [rpm] fix build on centos 10, drop 7th support Signed-off-by: r4sas --- contrib/rpm/i2pd-git.spec | 34 +++++++++++----------------------- contrib/rpm/i2pd.spec | 34 +++++++++++----------------------- 2 files changed, 22 insertions(+), 46 deletions(-) diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index fd431347..d9393f47 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -10,11 +10,7 @@ License: BSD URL: https://github.com/PurpleI2P/i2pd Source0: https://github.com/PurpleI2P/i2pd/archive/openssl/i2pd-openssl.tar.gz -%if 0%{?rhel} == 7 -BuildRequires: cmake3 -%else BuildRequires: cmake -%endif BuildRequires: chrpath BuildRequires: gcc-c++ @@ -43,26 +39,18 @@ C++ implementation of I2P. %build cd build -%if 0%{?rhel} == 7 - %cmake3 \ - -DWITH_LIBRARY=OFF \ - -DWITH_UPNP=ON \ - -DWITH_HARDENING=ON \ - -DBUILD_SHARED_LIBS:BOOL=OFF +%cmake \ + -DWITH_LIBRARY=OFF \ + -DWITH_UPNP=ON \ + -DWITH_HARDENING=ON \ +%if 0%{?fedora} > 29 + -DBUILD_SHARED_LIBS:BOOL=OFF \ + . %else - %cmake \ - -DWITH_LIBRARY=OFF \ - -DWITH_UPNP=ON \ - -DWITH_HARDENING=ON \ - %if 0%{?fedora} > 29 - -DBUILD_SHARED_LIBS:BOOL=OFF \ - . - %else - -DBUILD_SHARED_LIBS:BOOL=OFF - %endif + -DBUILD_SHARED_LIBS:BOOL=OFF %endif -%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln} +%if 0%{?rhel} >= 9 || 0%{?fedora} >= 35 || 0%{?eln} pushd redhat-linux-build %else %if 0%{?fedora} >= 33 @@ -76,7 +64,7 @@ cd build make %{?_smp_mflags} -%if 0%{?rhel} == 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7 +%if 0%{?rhel} >= 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7 popd %endif @@ -84,7 +72,7 @@ make %{?_smp_mflags} %install pushd build -%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln} +%if 0%{?rhel} >= 9 || 0%{?fedora} >= 35 || 0%{?eln} pushd redhat-linux-build %else %if 0%{?fedora} >= 33 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 2d3d4cbb..e094c3b7 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -8,11 +8,7 @@ License: BSD URL: https://github.com/PurpleI2P/i2pd Source0: https://github.com/PurpleI2P/i2pd/archive/%{version}/%name-%version.tar.gz -%if 0%{?rhel} == 7 -BuildRequires: cmake3 -%else BuildRequires: cmake -%endif BuildRequires: chrpath BuildRequires: gcc-c++ @@ -41,26 +37,18 @@ C++ implementation of I2P. %build cd build -%if 0%{?rhel} == 7 - %cmake3 \ - -DWITH_LIBRARY=OFF \ - -DWITH_UPNP=ON \ - -DWITH_HARDENING=ON \ - -DBUILD_SHARED_LIBS:BOOL=OFF +%cmake \ + -DWITH_LIBRARY=OFF \ + -DWITH_UPNP=ON \ + -DWITH_HARDENING=ON \ +%if 0%{?fedora} > 29 + -DBUILD_SHARED_LIBS:BOOL=OFF \ + . %else - %cmake \ - -DWITH_LIBRARY=OFF \ - -DWITH_UPNP=ON \ - -DWITH_HARDENING=ON \ - %if 0%{?fedora} > 29 - -DBUILD_SHARED_LIBS:BOOL=OFF \ - . - %else - -DBUILD_SHARED_LIBS:BOOL=OFF - %endif + -DBUILD_SHARED_LIBS:BOOL=OFF %endif -%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln} +%if 0%{?rhel} >= 9 || 0%{?fedora} >= 35 || 0%{?eln} pushd redhat-linux-build %else %if 0%{?fedora} >= 33 @@ -74,7 +62,7 @@ cd build make %{?_smp_mflags} -%if 0%{?rhel} == 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7 +%if 0%{?rhel} >= 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7 popd %endif @@ -82,7 +70,7 @@ make %{?_smp_mflags} %install pushd build -%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln} +%if 0%{?rhel} >= 9 || 0%{?fedora} >= 35 || 0%{?eln} pushd redhat-linux-build %else %if 0%{?fedora} >= 33 From 6363c9202f2e4816215e89548123f3aaee9f73c9 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 7 Jun 2025 11:28:21 -0400 Subject: [PATCH 503/527] drop crypto types higher than ours --- libi2pd/LeaseSet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index fc0e722d..bf07924f 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -417,7 +417,7 @@ namespace data 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) + if (keyType == preferredKeyType || !m_Encryptor || (keyType > m_EncryptionType && keyType < preferredKeyType)) { auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); if (encryptor) From 9c393f50da3a8cb1d51af5992d302452d10c2d1a Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 7 Jun 2025 12:06:47 -0400 Subject: [PATCH 504/527] drop crypto types higher than ours --- libi2pd/LeaseSet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index bf07924f..eb337b63 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -417,7 +417,7 @@ namespace data 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 && keyType < preferredKeyType)) + if (keyType <= preferredKeyType && (!m_Encryptor || keyType > m_EncryptionType)) { auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); if (encryptor) From ba0352e9a04e504529ab7ce0a7e40362543463de Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 7 Jun 2025 20:52:35 -0400 Subject: [PATCH 505/527] check for compatibility of LeaseSet encryption keys with local destination's encryption type --- daemon/HTTPServer.cpp | 2 +- libi2pd/Destination.cpp | 9 +++++---- libi2pd/LeaseSet.cpp | 33 +++++++++++++++++++-------------- libi2pd/LeaseSet.h | 30 +++++++++++++++++------------- libi2pd/NetDb.cpp | 2 +- 5 files changed, 43 insertions(+), 33 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index be1ec4ac..167b8c95 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -661,7 +661,7 @@ namespace http { else { ls.reset (new i2p::data::LeaseSet2 (storeType)); - ls->Update (leaseSet->GetBuffer(), leaseSet->GetBufferLen(), false); + ls->Update (leaseSet->GetBuffer(), leaseSet->GetBufferLen(), nullptr, false); } if (!ls) return; s << "
    second; if (leaseSet->IsNewer (buf + offset, len - offset)) { - leaseSet->Update (buf + offset, len - offset); + leaseSet->Update (buf + offset, len - offset, shared_from_this(), true); if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key && !leaseSet->IsExpired ()) LogPrint (eLogDebug, "Destination: Remote LeaseSet updated"); else @@ -471,7 +471,8 @@ namespace client else { leaseSet = std::make_shared (buf[DATABASE_STORE_TYPE_OFFSET], - buf + offset, len - offset, true, from ? from->GetRemoteStaticKeyType () : GetPreferredCryptoType () ); // LeaseSet2 + buf + offset, len - offset, true, shared_from_this (), + from ? from->GetRemoteStaticKeyType () : GetPreferredCryptoType () ); // LeaseSet2 if (from) { uint8_t pub[32]; @@ -511,8 +512,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, shared_from_this (), + m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr, GetPreferredCryptoType ()); if (ls2->IsValid () && !ls2->IsExpired ()) { leaseSet = ls2; diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index eb337b63..3001bdfb 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -36,7 +36,7 @@ namespace data ReadFromBuffer (); } - void LeaseSet::Update (const uint8_t * buf, size_t len, bool verifySignature) + void LeaseSet::Update (const uint8_t * buf, size_t len, std::shared_ptr dest, bool verifySignature) { SetBuffer (buf, len); ReadFromBuffer (false, verifySignature); @@ -281,28 +281,29 @@ namespace data LogPrint (eLogError, "LeaseSet2: Actual buffer size ", int(len) , " exceeds full buffer size ", int(m_BufferLen)); } - LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto): + LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, + bool storeLeases, std::shared_ptr dest, CryptoKeyType preferredCrypto): LeaseSet (storeLeases), m_StoreType (storeType), m_EncryptionType (preferredCrypto) { SetBuffer (buf, len); if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) - ReadFromBufferEncrypted (buf, len, nullptr, nullptr); + ReadFromBufferEncrypted (buf, len, nullptr, dest, nullptr); else - ReadFromBuffer (buf, len); + ReadFromBuffer (buf, len, dest); } LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, - const uint8_t * secret, CryptoKeyType preferredCrypto): + std::shared_ptr dest, const uint8_t * secret, CryptoKeyType preferredCrypto): LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_EncryptionType (preferredCrypto) { - ReadFromBufferEncrypted (buf, len, key, secret); + ReadFromBufferEncrypted (buf, len, key, dest, secret); } - void LeaseSet2::Update (const uint8_t * buf, size_t len, bool verifySignature) + void LeaseSet2::Update (const uint8_t * buf, size_t len, std::shared_ptr dest, bool verifySignature) { SetBuffer (buf, len); if (GetStoreType () != NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) - ReadFromBuffer (buf, len, false, verifySignature); + ReadFromBuffer (buf, len, dest, false, verifySignature); // TODO: implement encrypted } @@ -312,7 +313,8 @@ namespace data return ExtractPublishedTimestamp (buf, len, expiration) > m_PublishedTimestamp; } - void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity, bool verifySignature) + void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, std::shared_ptr dest, + bool readIdentity, bool verifySignature) { // standard LS2 header std::shared_ptr identity; @@ -350,7 +352,7 @@ namespace data switch (m_StoreType) { case NETDB_STORE_TYPE_STANDARD_LEASESET2: - s = ReadStandardLS2TypeSpecificPart (buf + offset, len - offset); + s = ReadStandardLS2TypeSpecificPart (buf + offset, len - offset, dest); break; case NETDB_STORE_TYPE_META_LEASESET2: s = ReadMetaLS2TypeSpecificPart (buf + offset, len - offset); @@ -392,7 +394,8 @@ namespace data return verified; } - size_t LeaseSet2::ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len) + size_t LeaseSet2::ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len, + std::shared_ptr dest) { size_t offset = 0; // properties @@ -417,7 +420,8 @@ namespace data 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)) + if ((keyType == preferredKeyType || !m_Encryptor || keyType > m_EncryptionType) && + (!dest || dest->SupportsEncryptionType (keyType))) { auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); if (encryptor) @@ -498,7 +502,8 @@ namespace data return offset; } - void LeaseSet2::ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret) + void LeaseSet2::ReadFromBufferEncrypted (const uint8_t * buf, size_t len, + std::shared_ptr key, std::shared_ptr dest, const uint8_t * secret) { size_t offset = 0; // blinded key @@ -601,7 +606,7 @@ namespace data m_StoreType = innerPlainText[0]; SetBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1); // parse and verify Layer 2 - ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1); + ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1, dest); } else LogPrint (eLogError, "LeaseSet2: Unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet"); diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index f5197eb5..f6f5f6da 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -76,7 +76,7 @@ namespace data LeaseSet (const uint8_t * buf, size_t len, bool storeLeases = true); virtual ~LeaseSet () { delete[] m_EncryptionKey; delete[] m_Buffer; }; - virtual void Update (const uint8_t * buf, size_t len, bool verifySignature = true); + virtual void Update (const uint8_t * buf, size_t len, std::shared_ptr dest, bool verifySignature); virtual bool IsNewer (const uint8_t * buf, size_t len) const; void PopulateLeases (); // from buffer @@ -155,15 +155,17 @@ 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_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; }; + LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, + std::shared_ptr dest = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); + LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, + std::shared_ptr dest = nullptr, 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 override { return m_StoreType; }; + uint32_t GetPublishedTimestamp () const override { return m_PublishedTimestamp; }; bool IsPublic () const { return m_IsPublic; }; - bool IsPublishedEncrypted () const { return m_IsPublishedEncrypted; }; - std::shared_ptr GetTransientVerifier () const { return m_TransientVerifier; }; - void Update (const uint8_t * buf, size_t len, bool verifySignature); - bool IsNewer (const uint8_t * buf, size_t len) const; + bool IsPublishedEncrypted () const override { return m_IsPublishedEncrypted; }; + std::shared_ptr GetTransientVerifier () const override { return m_TransientVerifier; }; + void Update (const uint8_t * buf, size_t len, std::shared_ptr dest, bool verifySignature) override; + bool IsNewer (const uint8_t * buf, size_t len) const override; // implements RoutingDestination void Encrypt (const uint8_t * data, uint8_t * encrypted) const; @@ -171,15 +173,17 @@ namespace data private: - void ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity = true, bool verifySignature = true); - void ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret); - size_t ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len); + void ReadFromBuffer (const uint8_t * buf, size_t len, std::shared_ptr dest, + bool readIdentity = true, bool verifySignature = true); + void ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr key, + std::shared_ptr dest, const uint8_t * secret); + size_t ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len, std::shared_ptr dest); size_t ReadMetaLS2TypeSpecificPart (const uint8_t * buf, size_t len); template bool VerifySignature (Verifier& verifier, const uint8_t * buf, size_t len, size_t signatureOffset); - uint64_t ExtractExpirationTimestamp (const uint8_t * buf, size_t len) const; + uint64_t ExtractExpirationTimestamp (const uint8_t * buf, size_t len) const override; uint64_t ExtractPublishedTimestamp (const uint8_t * buf, size_t len, uint64_t& expiration) const; size_t ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const; // subcredential is subcredential + timestamp, return length of autData without flag diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index e53738e5..cab40e43 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -361,7 +361,7 @@ namespace data { if(it->second->GetExpirationTime() < expires) { - it->second->Update (buf, len, false); // signature is verified already + it->second->Update (buf, len, nullptr, false); // signature is verified already if (CheckLogLevel (eLogInfo)) LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase32()); updated = true; From 46154dabd563852b332d97f98c8b35f960362315 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 8 Jun 2025 07:19:03 -0400 Subject: [PATCH 506/527] fixed warnings --- libi2pd/LeaseSet.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index f6f5f6da..46f40cb5 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -168,8 +168,8 @@ namespace data bool IsNewer (const uint8_t * buf, size_t len) const override; // implements RoutingDestination - void Encrypt (const uint8_t * data, uint8_t * encrypted) const; - CryptoKeyType GetEncryptionType () const { return m_EncryptionType; }; + void Encrypt (const uint8_t * data, uint8_t * encrypted) const override; + CryptoKeyType GetEncryptionType () const override { return m_EncryptionType; }; private: From 4828d93257769536aa6cacfc0013a61748f3385a Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 9 Jun 2025 16:05:56 -0400 Subject: [PATCH 507/527] implemented ssu2.firewalled4 and ssu2.firewalled6 params --- libi2pd/Config.cpp | 2 ++ libi2pd/SSU2.cpp | 5 ++++- libi2pd/SSU2.h | 2 ++ libi2pd/SSU2OutOfSession.cpp | 3 +++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 939cd9ff..3d88ff21 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -305,6 +305,8 @@ namespace config { ("ssu2.mtu4", value()->default_value(0), "MTU for ipv4 address (default: detect)") ("ssu2.mtu6", value()->default_value(0), "MTU for ipv6 address (default: detect)") ("ssu2.proxy", value()->default_value(""), "Socks5 proxy URL for SSU2 transport") + ("ssu2.firewalled4", value()->default_value(false), "Set ipv4 network status to Firewalled even if OK (default: disabled)") + ("ssu2.firewalled6", value()->default_value(false), "Set ipv6 network status to Firewalled even if OK (default: disabled)") ; options_description nettime("Time sync options"); diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index fc2355a5..4540b4d2 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -25,7 +25,8 @@ namespace transport m_TerminationTimer (GetService ()), m_CleanupTimer (GetService ()), m_ResendTimer (GetService ()), m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()), m_IsPublished (true), m_IsSyncClockFromPeers (true), m_PendingTimeOffset (0), - m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL), m_IsThroughProxy (false) + m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL), m_IsForcedFirewalled4 (false), + m_IsForcedFirewalled6 (false), m_IsThroughProxy (false) { } @@ -79,6 +80,7 @@ namespace transport if (address->IsV4 ()) { found = true; + i2p::config::GetOption ("ssu2.firewalled4", m_IsForcedFirewalled4); LogPrint (eLogDebug, "SSU2: Opening IPv4 socket at Start"); OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV4, port)); boost::asio::post (m_ReceiveService.GetService (), @@ -91,6 +93,7 @@ namespace transport if (address->IsV6 ()) { found = true; + i2p::config::GetOption ("ssu2.firewalled6", m_IsForcedFirewalled6); LogPrint (eLogDebug, "SSU2: Opening IPv6 socket at Start"); OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV6, port)); boost::asio::post (m_ReceiveService.GetService (), diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index a8598ce3..b7214480 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -79,6 +79,7 @@ namespace transport bool UsesProxy () const { return m_IsThroughProxy; }; bool IsSupported (const boost::asio::ip::address& addr) const; uint16_t GetPort (bool v4) const; + bool IsForcedFirewalled (bool v4) const { return v4 ? m_IsForcedFirewalled4 : m_IsForcedFirewalled6; } bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max = true); void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts); std::mt19937& GetRng () { return m_Rng; } @@ -208,6 +209,7 @@ namespace transport i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor; i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor; i2p::crypto::ChaCha20Context m_ChaCha20; + bool m_IsForcedFirewalled4, m_IsForcedFirewalled6; // proxy bool m_IsThroughProxy; diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index 3760e329..dc626b16 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -90,6 +90,9 @@ namespace transport if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ()) { m_PeerTestResendTimer.cancel (); // cancel delayed msg 6 if any + if (GetServer ().IsForcedFirewalled (GetRemoteEndpoint ().address().is_v4())) + // we assume that msg 5 was not received if forced firewalled + return; m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ()); if (GetAddress ()) { From 660dbd27d1bedfc0c9b0741d68d7c27902ccead1 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 11 Jun 2025 21:11:06 -0400 Subject: [PATCH 508/527] use EVP interface for ECDSA signatures if openssl 3 --- libi2pd/Signature.cpp | 174 +++++++++++++++++++++++++++++++++++++++++- libi2pd/Signature.h | 117 ++++++++++++++++++++++++++-- 2 files changed, 285 insertions(+), 6 deletions(-) diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index 3e4b451b..aa712c9a 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -10,6 +10,7 @@ #include #if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 #include +#include #endif #include "Log.h" #include "Signature.h" @@ -174,7 +175,178 @@ namespace crypto DSA_free (dsa); } #endif - + +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + ECDSAVerifier::ECDSAVerifier (int curve, size_t keyLen, const EVP_MD * hash): + m_Curve(curve), m_KeyLen (keyLen), m_Hash (hash), m_PublicKey (nullptr) + { + } + + ECDSAVerifier::~ECDSAVerifier () + { + if (m_PublicKey) + EVP_PKEY_free (m_PublicKey); + } + + void ECDSAVerifier::SetPublicKey (const uint8_t * signingKey) + { + if (m_PublicKey) + { + EVP_PKEY_free (m_PublicKey); + m_PublicKey = nullptr; + } + auto plen = GetPublicKeyLen (); + std::vector pub(plen + 1); + pub[0] = POINT_CONVERSION_UNCOMPRESSED; + memcpy (pub.data() + 1, signingKey, plen); // 0x04|x|y + OSSL_PARAM_BLD * paramBld = OSSL_PARAM_BLD_new (); + OSSL_PARAM_BLD_push_utf8_string (paramBld, OSSL_PKEY_PARAM_GROUP_NAME, OBJ_nid2ln(m_Curve), 0); + OSSL_PARAM_BLD_push_octet_string (paramBld, OSSL_PKEY_PARAM_PUB_KEY, pub.data (), pub.size ()); + OSSL_PARAM * params = OSSL_PARAM_BLD_to_param(paramBld); + + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "EC", NULL); + if (ctx) + { + if (EVP_PKEY_fromdata_init (ctx) <= 0 || + EVP_PKEY_fromdata (ctx, &m_PublicKey, EVP_PKEY_PUBLIC_KEY, params) <= 0) + LogPrint (eLogError, "ECDSA can't create PKEY from params"); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "ECDSA can't create PKEY context"); + + OSSL_PARAM_free (params); + OSSL_PARAM_BLD_free (paramBld); + } + + bool ECDSAVerifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const + { + bool ret = false; + EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new (m_PublicKey, NULL); + if (!ctx) + { + LogPrint (eLogError, "ECDSA can't create verification context"); + return false; + } + // digest + unsigned int digestLen = EVP_MD_size(m_Hash); + std::vector digest(digestLen), sign(GetSignatureLen () + 8); + EVP_MD_CTX * mdCtx = EVP_MD_CTX_create (); + EVP_DigestInit (mdCtx, m_Hash); + EVP_DigestUpdate (mdCtx, buf, len); + EVP_DigestFinal (mdCtx, digest.data (), &digestLen); + EVP_MD_CTX_destroy (mdCtx); + // signature + ECDSA_SIG * sig = ECDSA_SIG_new(); + ECDSA_SIG_set0 (sig, BN_bin2bn (signature, GetSignatureLen ()/2, NULL), + BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL)); + // to DER format + uint8_t * s = sign.data (); + auto l = i2d_ECDSA_SIG (sig, &s); + ECDSA_SIG_free(sig); + //verify + if (EVP_PKEY_verify_init (ctx) > 0 && EVP_PKEY_public_check (ctx) > 0) + { + if (EVP_PKEY_CTX_set_signature_md (ctx, m_Hash) > 0) + ret = EVP_PKEY_verify (ctx, sign.data (), l, digest.data (), digestLen); + else + LogPrint (eLogError, "ECDSA can't set signature md"); + } + else + LogPrint (eLogError, "ECDSA invalid public key"); + EVP_PKEY_CTX_free (ctx); + return ret; + } + + ECDSASigner::ECDSASigner (int curve, size_t keyLen, const EVP_MD * hash, const uint8_t * signingPrivateKey): + m_KeyLen (keyLen), m_Hash(hash), m_PrivateKey (nullptr) + { + BIGNUM * priv = BN_bin2bn (signingPrivateKey, keyLen/2, NULL); + OSSL_PARAM_BLD * paramBld = OSSL_PARAM_BLD_new (); + OSSL_PARAM_BLD_push_utf8_string (paramBld, OSSL_PKEY_PARAM_GROUP_NAME, OBJ_nid2ln(curve), 0); + OSSL_PARAM_BLD_push_BN (paramBld, OSSL_PKEY_PARAM_PRIV_KEY, priv); + OSSL_PARAM * params = OSSL_PARAM_BLD_to_param(paramBld); + + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "EC", NULL); + if (ctx) + { + if (EVP_PKEY_fromdata_init (ctx) <= 0 || + EVP_PKEY_fromdata (ctx, &m_PrivateKey, EVP_PKEY_KEYPAIR, params) <= 0) + LogPrint (eLogError, "ECDSA can't create PKEY from params"); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "ECDSA can't create PKEY context"); + + OSSL_PARAM_free (params); + OSSL_PARAM_BLD_free (paramBld); + BN_free (priv); + } + + ECDSASigner::~ECDSASigner () + { + if (m_PrivateKey) + EVP_PKEY_free (m_PrivateKey); + } + + void ECDSASigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const + { + unsigned int digestLen = EVP_MD_size(m_Hash); + std::vector digest(digestLen), sign(m_KeyLen + 8); + EVP_MD_CTX * mdCtx = EVP_MD_CTX_create (); + EVP_DigestInit (mdCtx, m_Hash); + EVP_DigestUpdate (mdCtx, buf, len); + EVP_DigestFinal (mdCtx, digest.data (), &digestLen); + EVP_MD_CTX_destroy (mdCtx); + + EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new (m_PrivateKey, NULL); + if (!ctx) + { + LogPrint (eLogError, "ECDSA can't create signing context"); + return; + } + if (EVP_PKEY_sign_init (ctx) > 0 && EVP_PKEY_private_check (ctx) > 0) + { + if (EVP_PKEY_CTX_set_signature_md (ctx, m_Hash) > 0) + { + size_t l = sign.size (); + EVP_PKEY_sign (ctx, sign.data (), &l, digest.data (), digest.size ()); + const uint8_t * s1 = sign.data (); + ECDSA_SIG * sig = d2i_ECDSA_SIG (NULL, &s1, l); + const BIGNUM * r, * s; + ECDSA_SIG_get0 (sig, &r, &s); + bn2buf (r, signature, m_KeyLen/2); + bn2buf (s, signature + m_KeyLen/2, m_KeyLen/2); + ECDSA_SIG_free(sig); + } + else + LogPrint (eLogError, "ECDSA can't set signature md"); + } + else + LogPrint (eLogError, "ECDSA invalid private key"); + EVP_PKEY_CTX_free (ctx); + } + + void CreateECDSARandomKeys (int curve, size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + EVP_PKEY * pkey = EVP_EC_gen (OBJ_nid2ln(curve)); + // private + BIGNUM * priv = BN_new (); + EVP_PKEY_get_bn_param (pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv); + bn2buf (priv, signingPrivateKey, keyLen/2); + BN_free (priv); + // public + BIGNUM * x = BN_new (), * y = BN_new (); + EVP_PKEY_get_bn_param (pkey, OSSL_PKEY_PARAM_EC_PUB_X, &x); + EVP_PKEY_get_bn_param (pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &y); + bn2buf (x, signingPublicKey, keyLen/2); + bn2buf (y, signingPublicKey + keyLen/2, keyLen/2); + BN_free (x); BN_free (y); + EVP_PKEY_free (pkey); + } + +#endif + #if OPENSSL_EDDSA EDDSA25519Verifier::EDDSA25519Verifier (): m_Pkey (nullptr) diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index 20c7e11b..bd704738 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -91,7 +91,116 @@ namespace crypto void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey); - // ECDSA + // ECDSA + constexpr size_t ECDSAP256_KEY_LENGTH = 64; + constexpr size_t ECDSAP384_KEY_LENGTH = 96; + constexpr size_t ECDSAP521_KEY_LENGTH = 132; + +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + class ECDSAVerifier: public Verifier + { + public: + + ECDSAVerifier (int curve, size_t keyLen, const EVP_MD * hash); + ~ECDSAVerifier (); + + void SetPublicKey (const uint8_t * signingKey); + bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; + + size_t GetPublicKeyLen () const { return m_KeyLen; }; + size_t GetSignatureLen () const { return m_KeyLen; }; // signature length = key length + + private: + + int m_Curve; + size_t m_KeyLen; + const EVP_MD * m_Hash; + EVP_PKEY * m_PublicKey; + }; + + class ECDSASigner: public Signer + { + public: + + ECDSASigner (int curve, size_t keyLen, const EVP_MD * hash, const uint8_t * signingPrivateKey); + ~ECDSASigner (); + + void Sign (const uint8_t * buf, int len, uint8_t * signature) const; + + private: + + size_t m_KeyLen; + const EVP_MD * m_Hash; + EVP_PKEY * m_PrivateKey; + }; + + void CreateECDSARandomKeys (int curve, size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey); + +// ECDSA_SHA256_P256 + class ECDSAP256Verifier: public ECDSAVerifier + { + public: + + ECDSAP256Verifier (): ECDSAVerifier (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, EVP_sha256()) {}; + }; + + class ECDSAP256Signer: public ECDSASigner + { + public: + + ECDSAP256Signer (const uint8_t * signingPrivateKey): + ECDSASigner (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, EVP_sha256(), signingPrivateKey) {}; + }; + + inline void CreateECDSAP256RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + CreateECDSARandomKeys (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey); + } + +// ECDSA_SHA384_P384 + class ECDSAP384Verifier: public ECDSAVerifier + { + public: + + ECDSAP384Verifier (): ECDSAVerifier (NID_secp384r1, ECDSAP384_KEY_LENGTH, EVP_sha384()) {}; + }; + + class ECDSAP384Signer: public ECDSASigner + { + public: + + ECDSAP384Signer (const uint8_t * signingPrivateKey): + ECDSASigner (NID_secp384r1, ECDSAP384_KEY_LENGTH, EVP_sha384(), signingPrivateKey) {}; + }; + + inline void CreateECDSAP384RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + CreateECDSARandomKeys (NID_secp384r1, ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey); + } + +// ECDSA_SHA512_P521 + class ECDSAP521Verifier: public ECDSAVerifier + { + public: + + ECDSAP521Verifier (): ECDSAVerifier (NID_secp521r1, ECDSAP521_KEY_LENGTH, EVP_sha512()) {}; + }; + + class ECDSAP521Signer: public ECDSASigner + { + public: + + ECDSAP521Signer (const uint8_t * signingPrivateKey): + ECDSASigner (NID_secp521r1, ECDSAP521_KEY_LENGTH, EVP_sha512(), signingPrivateKey) {}; + }; + + inline void CreateECDSAP521RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + CreateECDSARandomKeys (NID_secp521r1, ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey); + } + +#else + struct SHA256Hash { static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) @@ -217,7 +326,6 @@ namespace crypto } // ECDSA_SHA256_P256 - const size_t ECDSAP256_KEY_LENGTH = 64; typedef ECDSAVerifier ECDSAP256Verifier; typedef ECDSASigner ECDSAP256Signer; @@ -227,7 +335,6 @@ namespace crypto } // ECDSA_SHA384_P384 - const size_t ECDSAP384_KEY_LENGTH = 96; typedef ECDSAVerifier ECDSAP384Verifier; typedef ECDSASigner ECDSAP384Signer; @@ -237,7 +344,6 @@ namespace crypto } // ECDSA_SHA512_P521 - const size_t ECDSAP521_KEY_LENGTH = 132; typedef ECDSAVerifier ECDSAP521Verifier; typedef ECDSASigner ECDSAP521Signer; @@ -245,7 +351,8 @@ namespace crypto { CreateECDSARandomKeys (NID_secp521r1, ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey); } - + +#endif // EdDSA class EDDSA25519Verifier: public Verifier From d2296f81ad77bbf1c7742cefe5a1d750e0f6765f Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Jun 2025 09:44:55 -0400 Subject: [PATCH 509/527] use EVP functions to extract RSA keys if openssl 3 --- libi2pd/Reseed.cpp | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/libi2pd/Reseed.cpp b/libi2pd/Reseed.cpp index e58e898b..23dae8ff 100644 --- a/libi2pd/Reseed.cpp +++ b/libi2pd/Reseed.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,9 @@ #include #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 +#include +#endif #include #include "Crypto.h" @@ -480,15 +483,31 @@ namespace data if (terminator) terminator[0] = 0; } // extract RSA key (we need n only, e = 65537) - const RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert)); - const BIGNUM * n, * e, * d; + EVP_PKEY * pubKey = X509_get_pubkey (cert); + const BIGNUM * n = nullptr; +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + BIGNUM * n1 = BN_new (); + if (EVP_PKEY_get_bn_param (pubKey, OSSL_PKEY_PARAM_RSA_N, &n1) > 0) + n = n1; +#else + const RSA * key = EVP_PKEY_get0_RSA (pubKey); + const BIGNUM * e, * d; RSA_get0_key(key, &n, &e, &d); - PublicKey value; - i2p::crypto::bn2buf (n, value, 512); - if (cn) - m_SigningKeys[cn] = value; +#endif + if (n) + { + PublicKey value; + i2p::crypto::bn2buf (n, value, 512); + if (cn) + m_SigningKeys[cn] = value; + else + LogPrint (eLogError, "Reseed: Can't find CN field in ", filename); + } else - LogPrint (eLogError, "Reseed: Can't find CN field in ", filename); + LogPrint (eLogError, "Reseed: Can't extract RSA key from ", filename); +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + BN_free (n1); +#endif } SSL_free (ssl); } From 5bef9875292f15c08b9d2155f8b308dbeac70f78 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Jun 2025 11:22:39 -0400 Subject: [PATCH 510/527] stop suporting openssl below 1.1.1 --- libi2pd/Crypto.cpp | 15 --------------- libi2pd/Crypto.h | 14 +++++--------- libi2pd/Signature.cpp | 34 ---------------------------------- libi2pd/Signature.h | 18 ------------------ 4 files changed, 5 insertions(+), 76 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index c41b4c10..94f47ca9 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -16,9 +16,7 @@ #include #include "TunnelBase.h" #include -#if OPENSSL_HKDF #include -#endif #if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 #include #include @@ -784,7 +782,6 @@ namespace crypto void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out, size_t outLen) { -#if OPENSSL_HKDF EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, nullptr); EVP_PKEY_derive_init (pctx); EVP_PKEY_CTX_set_hkdf_md (pctx, EVP_sha256()); @@ -805,18 +802,6 @@ namespace crypto EVP_PKEY_CTX_add1_hkdf_info (pctx, (const uint8_t *)info.c_str (), info.length ()); EVP_PKEY_derive (pctx, out, &outLen); EVP_PKEY_CTX_free (pctx); -#else - uint8_t prk[32]; unsigned int len; - HMAC(EVP_sha256(), salt, 32, key, keyLen, prk, &len); - auto l = info.length (); - memcpy (out, info.c_str (), l); out[l] = 0x01; - HMAC(EVP_sha256(), prk, 32, out, l + 1, out, &len); - if (outLen > 32) // 64 - { - memcpy (out + 32, info.c_str (), l); out[l + 32] = 0x02; - HMAC(EVP_sha256(), prk, 32, out, l + 33, out + 32, &len); - } -#endif } // Noise diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 125a217c..5bf4d534 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -27,15 +27,11 @@ #include "Tag.h" // recognize openssl version and features -#if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1 -# define OPENSSL_HKDF 1 -# define OPENSSL_EDDSA 1 -# if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL -# define OPENSSL_SIPHASH 1 -# endif -# if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0 -# define OPENSSL_PQ 1 -# endif +#if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL +# define OPENSSL_SIPHASH 1 +#endif +#if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0 +# define OPENSSL_PQ 1 #endif namespace i2p diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index aa712c9a..24374e5b 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -347,7 +347,6 @@ namespace crypto #endif -#if OPENSSL_EDDSA EDDSA25519Verifier::EDDSA25519Verifier (): m_Pkey (nullptr) { @@ -379,37 +378,6 @@ namespace crypto return false; } -#else - EDDSA25519Verifier::EDDSA25519Verifier () - { - } - - EDDSA25519Verifier::~EDDSA25519Verifier () - { - } - - void EDDSA25519Verifier::SetPublicKey (const uint8_t * signingKey) - { - memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH); - BN_CTX * ctx = BN_CTX_new (); - m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx); - BN_CTX_free (ctx); - } - - bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const - { - uint8_t digest[64]; - SHA512_CTX ctx; - SHA512_Init (&ctx); - SHA512_Update (&ctx, signature, EDDSA25519_SIGNATURE_LENGTH/2); // R - SHA512_Update (&ctx, m_PublicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key - SHA512_Update (&ctx, buf, len); // data - SHA512_Final (digest, &ctx); - - return GetEd25519 ()->Verify (m_PublicKey, digest, signature); - } -#endif - EDDSA25519SignerCompat::EDDSA25519SignerCompat (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey) { // expand key @@ -439,7 +407,6 @@ namespace crypto GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature); } -#if OPENSSL_EDDSA EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey): m_Pkey (nullptr), m_Fallback (nullptr) { @@ -481,7 +448,6 @@ namespace crypto else LogPrint (eLogError, "EdDSA signing key is not set"); } -#endif #if (OPENSSL_VERSION_NUMBER >= 0x030000000) static const OSSL_PARAM EDDSA25519phParams[] = diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index bd704738..b1942d0c 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -369,18 +369,12 @@ namespace crypto size_t GetSignatureLen () const { return EDDSA25519_SIGNATURE_LENGTH; }; private: - -#if OPENSSL_EDDSA EVP_PKEY * m_Pkey; protected: EVP_PKEY * GetPkey () const { return m_Pkey; }; -#else - EDDSAPoint m_PublicKey; - uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; -#endif }; #if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 @@ -409,7 +403,6 @@ namespace crypto uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; }; -#if OPENSSL_EDDSA class EDDSA25519Signer: public Signer { public: @@ -429,11 +422,6 @@ namespace crypto EVP_PKEY * m_Pkey; EDDSA25519SignerCompat * m_Fallback; }; -#else - - typedef EDDSA25519SignerCompat EDDSA25519Signer; - -#endif #if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 class EDDSA25519phSigner: public EDDSA25519Signer @@ -449,7 +437,6 @@ namespace crypto inline void CreateEDDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) { -#if OPENSSL_EDDSA EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_ED25519, NULL); EVP_PKEY_keygen_init (pctx); @@ -460,11 +447,6 @@ namespace crypto len = EDDSA25519_PRIVATE_KEY_LENGTH; EVP_PKEY_get_raw_private_key (pkey, signingPrivateKey, &len); EVP_PKEY_free (pkey); -#else - RAND_bytes (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH); - EDDSA25519Signer signer (signingPrivateKey); - memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH); -#endif } From 5974d2b5ac65222560499d2680880afdb160cc85 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Jun 2025 13:35:47 -0400 Subject: [PATCH 511/527] use EVP_DigestVerify/EVP_DigestSign for ECDSA and DSA signatures if openssl 3 --- libi2pd/Signature.cpp | 108 +++++++++++++----------------------------- 1 file changed, 32 insertions(+), 76 deletions(-) diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index 24374e5b..b8cfaf2c 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -42,22 +42,19 @@ namespace crypto 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 sign[DSA_SIGNATURE_LENGTH + 8]; 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); + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestVerifyInit (ctx, NULL, EVP_sha1(), NULL, m_PublicKey); + auto ret = EVP_DigestVerify (ctx, sign, l, buf, len); + EVP_MD_CTX_destroy (ctx); return ret; } @@ -76,13 +73,13 @@ namespace crypto 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); + uint8_t sign[DSA_SIGNATURE_LENGTH + 8]; + size_t l = DSA_SIGNATURE_LENGTH + 8; + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestSignInit (ctx, NULL, EVP_sha1(), NULL, m_PrivateKey); + EVP_DigestSign (ctx, sign, &l, buf, len); + EVP_MD_CTX_destroy (ctx); + // decode r and s const uint8_t * s1 = sign; DSA_SIG * sig = d2i_DSA_SIG (NULL, &s1, l); const BIGNUM * r, * s; @@ -90,7 +87,6 @@ namespace crypto 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) @@ -221,40 +217,20 @@ namespace crypto bool ECDSAVerifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const { - bool ret = false; - EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new (m_PublicKey, NULL); - if (!ctx) - { - LogPrint (eLogError, "ECDSA can't create verification context"); - return false; - } - // digest - unsigned int digestLen = EVP_MD_size(m_Hash); - std::vector digest(digestLen), sign(GetSignatureLen () + 8); - EVP_MD_CTX * mdCtx = EVP_MD_CTX_create (); - EVP_DigestInit (mdCtx, m_Hash); - EVP_DigestUpdate (mdCtx, buf, len); - EVP_DigestFinal (mdCtx, digest.data (), &digestLen); - EVP_MD_CTX_destroy (mdCtx); // signature ECDSA_SIG * sig = ECDSA_SIG_new(); ECDSA_SIG_set0 (sig, BN_bin2bn (signature, GetSignatureLen ()/2, NULL), BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL)); // to DER format + std::vector sign(GetSignatureLen () + 8); uint8_t * s = sign.data (); auto l = i2d_ECDSA_SIG (sig, &s); ECDSA_SIG_free(sig); - //verify - if (EVP_PKEY_verify_init (ctx) > 0 && EVP_PKEY_public_check (ctx) > 0) - { - if (EVP_PKEY_CTX_set_signature_md (ctx, m_Hash) > 0) - ret = EVP_PKEY_verify (ctx, sign.data (), l, digest.data (), digestLen); - else - LogPrint (eLogError, "ECDSA can't set signature md"); - } - else - LogPrint (eLogError, "ECDSA invalid public key"); - EVP_PKEY_CTX_free (ctx); + // verify + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestVerifyInit (ctx, NULL, m_Hash, NULL, m_PublicKey); + auto ret = EVP_DigestVerify (ctx, sign.data (), l, buf, len); + EVP_MD_CTX_destroy (ctx); return ret; } @@ -291,40 +267,20 @@ namespace crypto void ECDSASigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const { - unsigned int digestLen = EVP_MD_size(m_Hash); - std::vector digest(digestLen), sign(m_KeyLen + 8); - EVP_MD_CTX * mdCtx = EVP_MD_CTX_create (); - EVP_DigestInit (mdCtx, m_Hash); - EVP_DigestUpdate (mdCtx, buf, len); - EVP_DigestFinal (mdCtx, digest.data (), &digestLen); - EVP_MD_CTX_destroy (mdCtx); - - EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new (m_PrivateKey, NULL); - if (!ctx) - { - LogPrint (eLogError, "ECDSA can't create signing context"); - return; - } - if (EVP_PKEY_sign_init (ctx) > 0 && EVP_PKEY_private_check (ctx) > 0) - { - if (EVP_PKEY_CTX_set_signature_md (ctx, m_Hash) > 0) - { - size_t l = sign.size (); - EVP_PKEY_sign (ctx, sign.data (), &l, digest.data (), digest.size ()); - const uint8_t * s1 = sign.data (); - ECDSA_SIG * sig = d2i_ECDSA_SIG (NULL, &s1, l); - const BIGNUM * r, * s; - ECDSA_SIG_get0 (sig, &r, &s); - bn2buf (r, signature, m_KeyLen/2); - bn2buf (s, signature + m_KeyLen/2, m_KeyLen/2); - ECDSA_SIG_free(sig); - } - else - LogPrint (eLogError, "ECDSA can't set signature md"); - } - else - LogPrint (eLogError, "ECDSA invalid private key"); - EVP_PKEY_CTX_free (ctx); + std::vector sign(m_KeyLen + 8); + size_t l = sign.size (); + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestSignInit (ctx, NULL, m_Hash, NULL, m_PrivateKey); + EVP_DigestSign (ctx, sign.data(), &l, buf, len); + EVP_MD_CTX_destroy (ctx); + // decode r and s + const uint8_t * s1 = sign.data (); + ECDSA_SIG * sig = d2i_ECDSA_SIG (NULL, &s1, l); + const BIGNUM * r, * s; + ECDSA_SIG_get0 (sig, &r, &s); + bn2buf (r, signature, m_KeyLen/2); + bn2buf (s, signature + m_KeyLen/2, m_KeyLen/2); + ECDSA_SIG_free(sig); } void CreateECDSARandomKeys (int curve, size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) From bb2b34ff4fd186ac55bd3654f265415a1691b7ab Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Jun 2025 16:05:17 -0400 Subject: [PATCH 512/527] check more precise result of EVP_DigestVerify --- libi2pd/Signature.cpp | 10 +++++----- libi2pd/Signature.h | 2 +- tests/test-eddsa.cpp | 2 -- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index b8cfaf2c..cad7d484 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -53,7 +53,7 @@ namespace crypto // verify EVP_MD_CTX * ctx = EVP_MD_CTX_create (); EVP_DigestVerifyInit (ctx, NULL, EVP_sha1(), NULL, m_PublicKey); - auto ret = EVP_DigestVerify (ctx, sign, l, buf, len); + auto ret = EVP_DigestVerify (ctx, sign, l, buf, len) == 1; EVP_MD_CTX_destroy (ctx); return ret; } @@ -132,7 +132,7 @@ namespace crypto 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); + int ret = DSA_do_verify (digest, 20, sig, m_PublicKey) == 1; DSA_SIG_free(sig); return ret; } @@ -229,7 +229,7 @@ namespace crypto // verify EVP_MD_CTX * ctx = EVP_MD_CTX_create (); EVP_DigestVerifyInit (ctx, NULL, m_Hash, NULL, m_PublicKey); - auto ret = EVP_DigestVerify (ctx, sign.data (), l, buf, len); + auto ret = EVP_DigestVerify (ctx, sign.data (), l, buf, len) == 1; EVP_MD_CTX_destroy (ctx); return ret; } @@ -325,7 +325,7 @@ namespace crypto { EVP_MD_CTX * ctx = EVP_MD_CTX_create (); EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, m_Pkey); - auto ret = EVP_DigestVerify (ctx, signature, 64, buf, len); + auto ret = EVP_DigestVerify (ctx, signature, 64, buf, len) == 1; EVP_MD_CTX_destroy (ctx); return ret; } @@ -509,7 +509,7 @@ namespace crypto OSSL_PARAM_END }; EVP_PKEY_verify_message_init (vctx, sig, params); - ret = EVP_PKEY_verify (vctx, signature, GetSignatureLen (), buf, len); + ret = EVP_PKEY_verify (vctx, signature, GetSignatureLen (), buf, len) == 1; EVP_SIGNATURE_free (sig); } EVP_PKEY_CTX_free (vctx); diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index b1942d0c..43f706bd 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -263,7 +263,7 @@ namespace crypto auto s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL); ECDSA_SIG_set0(sig, r, s); // ECDSA verification - int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey); + int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey) == 1; ECDSA_SIG_free(sig); return ret; } diff --git a/tests/test-eddsa.cpp b/tests/test-eddsa.cpp index b3895e2b..9de2c088 100644 --- a/tests/test-eddsa.cpp +++ b/tests/test-eddsa.cpp @@ -58,9 +58,7 @@ int main () uint8_t s[64]; i2p::crypto::EDDSA25519Signer signer (key); signer.Sign (msg, 1023, s); -#if OPENSSL_EDDSA assert(memcmp (s, sig, 64) == 0); -#endif i2p::crypto::EDDSA25519Verifier verifier; verifier.SetPublicKey (pub); From 06c9a255fb4f5dbb5670f3872f77cb525a0a1211 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Jun 2025 18:58:37 -0400 Subject: [PATCH 513/527] use EVP_DigestSign/EVP_DigestVerify for family signatures --- libi2pd/Family.cpp | 90 ++++++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 30 deletions(-) diff --git a/libi2pd/Family.cpp b/libi2pd/Family.cpp index 300a50ab..3a4e8890 100644 --- a/libi2pd/Family.cpp +++ b/libi2pd/Family.cpp @@ -51,11 +51,24 @@ namespace data auto pkey = X509_get_pubkey (cert); if (pkey) { - if (!m_SigningKeys.emplace (cn, std::make_pair(pkey, (int)m_SigningKeys.size () + 1)).second) - { - EVP_PKEY_free (pkey); - LogPrint (eLogError, "Family: Duplicated family name ", cn); - } + int curve = 0; +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + char groupName[20]; + if (EVP_PKEY_get_group_name(pkey, groupName, sizeof(groupName), NULL) == 1) + curve = OBJ_txt2nid (groupName); + else + curve = -1; +#endif + if (!curve || curve == NID_X9_62_prime256v1) + { + if (!m_SigningKeys.emplace (cn, std::make_pair(pkey, (int)m_SigningKeys.size () + 1)).second) + { + EVP_PKEY_free (pkey); + LogPrint (eLogError, "Family: Duplicated family name ", cn); + } + } + else + LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); } } } @@ -106,11 +119,17 @@ namespace data memcpy (buf + len, (const uint8_t *)ident, 32); len += 32; auto signatureBufLen = Base64ToByteStream (signature, signatureBuf, 64); - if (signatureBufLen) + if (signatureBufLen == 64) { + ECDSA_SIG * sig = ECDSA_SIG_new(); + ECDSA_SIG_set0 (sig, BN_bin2bn (signatureBuf, 32, NULL), BN_bin2bn (signatureBuf + 32, 32, NULL)); + uint8_t sign[72]; + uint8_t * s = sign; + auto l = i2d_ECDSA_SIG (sig, &s); + ECDSA_SIG_free(sig); EVP_MD_CTX * ctx = EVP_MD_CTX_create (); - EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, it->second.first); - auto ret = EVP_DigestVerify (ctx, signatureBuf, signatureBufLen, buf, len); + EVP_DigestVerifyInit (ctx, NULL, EVP_sha256(), NULL, it->second.first); + auto ret = EVP_DigestVerify (ctx, sign, l, buf, len) == 1; EVP_MD_CTX_destroy (ctx); return ret; } @@ -137,29 +156,40 @@ namespace data { SSL * ssl = SSL_new (ctx); EVP_PKEY * pkey = SSL_get_privatekey (ssl); - EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey); - if (ecKey) + int curve = 0; +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + char groupName[20]; + if (EVP_PKEY_get_group_name(pkey, groupName, sizeof(groupName), NULL) == 1) + curve = OBJ_txt2nid (groupName); + else + curve = -1; +#endif + if (!curve || curve == NID_X9_62_prime256v1) { - auto group = EC_KEY_get0_group (ecKey); - if (group) - { - int curve = EC_GROUP_get_curve_name (group); - if (curve == NID_X9_62_prime256v1) - { - uint8_t signingPrivateKey[32], buf[50], signature[64]; - i2p::crypto::bn2buf (EC_KEY_get0_private_key (ecKey), signingPrivateKey, 32); - i2p::crypto::ECDSAP256Signer signer (signingPrivateKey); - size_t len = family.length (); - memcpy (buf, family.c_str (), len); - memcpy (buf + len, (const uint8_t *)ident, 32); - len += 32; - signer.Sign (buf, len, signature); - sig = ByteStreamToBase64 (signature, 64); - } - else - LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); - } - } + uint8_t buf[100], sign[72], signature[64]; + size_t len = family.length (); + memcpy (buf, family.c_str (), len); + memcpy (buf + len, (const uint8_t *)ident, 32); + len += 32; + + size_t l = 72; + EVP_MD_CTX * mdctx = EVP_MD_CTX_create (); + EVP_DigestSignInit (mdctx, NULL, EVP_sha256(), NULL, pkey); + EVP_DigestSign (mdctx, sign, &l, buf, len); + EVP_MD_CTX_destroy (mdctx); + + const uint8_t * s1 = sign; + ECDSA_SIG * sig1 = d2i_ECDSA_SIG (NULL, &s1, l); + const BIGNUM * r, * s; + ECDSA_SIG_get0 (sig1, &r, &s); + i2p::crypto::bn2buf (r, signature, 32); + i2p::crypto::bn2buf (s, signature + 32, 32); + ECDSA_SIG_free(sig1); + sig = ByteStreamToBase64 (signature, 64); + } + else + LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); + SSL_free (ssl); } else From 588108d7d0e19516eadbd8f22e16df6a4608d146 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 13 Jun 2025 12:48:25 -0400 Subject: [PATCH 514/527] use EVP_RSA_gen if openssl 3 --- daemon/I2PControl.cpp | 78 +++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 6261a14c..9babce93 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -437,48 +437,54 @@ namespace client void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path) { FILE *f = NULL; +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0 + EVP_PKEY * pkey = EVP_RSA_gen(4096); // e = 65537 +#else EVP_PKEY * pkey = EVP_PKEY_new (); RSA * rsa = RSA_new (); BIGNUM * e = BN_dup (i2p::crypto::GetRSAE ()); RSA_generate_key_ex (rsa, 4096, e, NULL); - BN_free (e); - if (rsa) - { - EVP_PKEY_assign_RSA (pkey, rsa); - X509 * x509 = X509_new (); - ASN1_INTEGER_set (X509_get_serialNumber (x509), 1); - X509_gmtime_adj (X509_getm_notBefore (x509), 0); - X509_gmtime_adj (X509_getm_notAfter (x509), I2P_CONTROL_CERTIFICATE_VALIDITY*24*60*60); // expiration - X509_set_pubkey (x509, pkey); // public key - X509_NAME * name = X509_get_subject_name (x509); - X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *)"A1", -1, -1, 0); // country (Anonymous proxy) - X509_NAME_add_entry_by_txt (name, "O", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_ORGANIZATION, -1, -1, 0); // organization - X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name - X509_set_issuer_name (x509, name); // set issuer to ourselves - X509_sign (x509, pkey, EVP_sha1 ()); // sign, last param must be NULL for EdDSA - - // save cert - if ((f = fopen (crt_path, "wb")) != NULL) { - LogPrint (eLogInfo, "I2PControl: Saving new cert to ", crt_path); - PEM_write_X509 (f, x509); - fclose (f); - } else { - LogPrint (eLogError, "I2PControl: Can't write cert: ", strerror(errno)); - } - - // save key - if ((f = fopen (key_path, "wb")) != NULL) { - LogPrint (eLogInfo, "I2PControl: saving cert key to ", key_path); - PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL); - fclose (f); - } else { - LogPrint (eLogError, "I2PControl: Can't write key: ", strerror(errno)); - } - - X509_free (x509); - } else { + BN_free (e); + if (rsa) EVP_PKEY_assign_RSA (pkey, rsa); + else + { LogPrint (eLogError, "I2PControl: Can't create RSA key for certificate"); + EVP_PKEY_free (pkey); + return; + } +#endif + X509 * x509 = X509_new (); + ASN1_INTEGER_set (X509_get_serialNumber (x509), 1); + X509_gmtime_adj (X509_getm_notBefore (x509), 0); + X509_gmtime_adj (X509_getm_notAfter (x509), I2P_CONTROL_CERTIFICATE_VALIDITY*24*60*60); // expiration + X509_set_pubkey (x509, pkey); // public key + X509_NAME * name = X509_get_subject_name (x509); + X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *)"A1", -1, -1, 0); // country (Anonymous proxy) + X509_NAME_add_entry_by_txt (name, "O", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_ORGANIZATION, -1, -1, 0); // organization + X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name + X509_set_issuer_name (x509, name); // set issuer to ourselves + X509_sign (x509, pkey, EVP_sha1 ()); // sign, last param must be NULL for EdDSA + + // save cert + if ((f = fopen (crt_path, "wb")) != NULL) + { + LogPrint (eLogInfo, "I2PControl: Saving new cert to ", crt_path); + PEM_write_X509 (f, x509); + fclose (f); + } + else + LogPrint (eLogError, "I2PControl: Can't write cert: ", strerror(errno)); + X509_free (x509); + + // save key + if ((f = fopen (key_path, "wb")) != NULL) + { + LogPrint (eLogInfo, "I2PControl: saving cert key to ", key_path); + PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL); + fclose (f); } + else + LogPrint (eLogError, "I2PControl: Can't write key: ", strerror(errno)); EVP_PKEY_free (pkey); } } From 61588777beb8b2bc3865476ee8670ddb93572c64 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 15 Jun 2025 08:06:34 -0400 Subject: [PATCH 515/527] set default transit tunnels limit to 10000 --- contrib/i2pd.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index c26f8af0..fa6b1f8b 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -246,9 +246,9 @@ verify = true # subscriptions = http://reg.i2p/hosts.txt,http://identiguy.i2p/hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt [limits] -## Maximum active transit sessions (default: 5000) +## Maximum active transit sessions (default: 10000) ## This value is doubled if floodfill mode is enabled! -# transittunnels = 5000 +# transittunnels = 10000 ## Limit number of open file descriptors (0 - use system limit) # openfiles = 0 ## Maximum size of corefile in Kb (0 - use system limit) From 5f0262ea2f60cf50dc600929ae6db738a0a19020 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jun 2025 13:19:49 -0400 Subject: [PATCH 516/527] use EVP_Digest_ insted deprecated SHA512_ functions --- libi2pd/Ed25519.cpp | 56 ++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 47edb755..55d7711d 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -1,12 +1,12 @@ /* -* 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 * * See full license text in LICENSE file at top of project tree */ -#include +#include #include "Log.h" #include "Crypto.h" #include "Ed25519.h" @@ -134,22 +134,27 @@ namespace crypto { BN_CTX * bnCtx = BN_CTX_new (); // calculate r - SHA512_CTX ctx; - SHA512_Init (&ctx); - SHA512_Update (&ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key - SHA512_Update (&ctx, buf, len); // data + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestInit_ex (ctx, EVP_sha512(), NULL); + EVP_DigestUpdate (ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key + EVP_DigestUpdate (ctx, buf, len); // data uint8_t digest[64]; - SHA512_Final (digest, &ctx); + unsigned int dl = 64; + EVP_DigestFinal_ex (ctx, digest, &dl); + EVP_MD_CTX_destroy (ctx); BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors // calculate R uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors // calculate S - SHA512_Init (&ctx); - SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R - SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key - SHA512_Update (&ctx, buf, len); // data - SHA512_Final (digest, &ctx); + ctx = EVP_MD_CTX_create (); + EVP_DigestInit_ex (ctx, EVP_sha512(), NULL); + EVP_DigestUpdate (ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R + EVP_DigestUpdate (ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key + EVP_DigestUpdate (ctx, buf, len); // data + dl = 64; + EVP_DigestFinal_ex (ctx, digest, &dl); + EVP_MD_CTX_destroy (ctx); BIGNUM * h = DecodeBN<64> (digest); // S = (r + h*a) % l BIGNUM * a = DecodeBN (expandedPrivateKey); // left half of expanded key @@ -169,13 +174,15 @@ namespace crypto uint8_t T[80]; RAND_bytes (T, 80); // calculate r = H*(T || publickey || data) - SHA512_CTX ctx; - SHA512_Init (&ctx); - SHA512_Update (&ctx, T, 80); - SHA512_Update (&ctx, publicKeyEncoded, 32); - SHA512_Update (&ctx, buf, len); // data + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestInit_ex (ctx, EVP_sha512(), NULL); + EVP_DigestUpdate (ctx, T, 80); + EVP_DigestUpdate (ctx, publicKeyEncoded, 32); + EVP_DigestUpdate (ctx, buf, len); // data uint8_t digest[64]; - SHA512_Final (digest, &ctx); + unsigned int dl = 64; + EVP_DigestFinal_ex (ctx, digest, &dl); + EVP_MD_CTX_destroy (ctx); BIGNUM * r = DecodeBN<64> (digest); BN_mod (r, r, l, bnCtx); // % l EncodeBN (r, digest, 32); @@ -183,11 +190,14 @@ namespace crypto uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // calculate S - SHA512_Init (&ctx); - SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R - SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key - SHA512_Update (&ctx, buf, len); // data - SHA512_Final (digest, &ctx); + ctx = EVP_MD_CTX_create (); + EVP_DigestInit_ex (ctx, EVP_sha512(), NULL); + EVP_DigestUpdate (ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R + EVP_DigestUpdate (ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key + EVP_DigestUpdate (ctx, buf, len); // data + dl = 64; + EVP_DigestFinal_ex (ctx, digest, &dl); + EVP_MD_CTX_destroy (ctx); BIGNUM * h = DecodeBN<64> (digest); // S = (r + h*a) % l BIGNUM * a = DecodeBN (privateKey); From 78357c23d22f8a62290b02f745e97f9e987cb166 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jun 2025 20:39:48 -0400 Subject: [PATCH 517/527] don't verify signature in incoming SYN packet if came from ECIESx25519 session. Compare static key instead --- libi2pd/Destination.cpp | 7 ++-- libi2pd/Destination.h | 4 +- libi2pd/Streaming.cpp | 83 ++++++++++++++++++++++++++++------------- libi2pd/Streaming.h | 6 ++- libi2pd_client/I2CP.cpp | 3 +- libi2pd_client/I2CP.h | 2 +- 6 files changed, 70 insertions(+), 35 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 52418471..e1ccbc92 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -388,7 +388,7 @@ namespace client switch (typeID) { case eI2NPData: - HandleDataMessage (payload, len); + HandleDataMessage (payload, len, from); break; case eI2NPDeliveryStatus: HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET)); @@ -1158,7 +1158,8 @@ namespace client LogPrint(eLogDebug, "Destination: -> Stopping done"); } - void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len) + void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len, + i2p::garlic::ECIESX25519AEADRatchetSession * from) { uint32_t length = bufbe32toh (buf); if(length > len - 4) @@ -1183,7 +1184,7 @@ namespace client m_LastPort = toPort; } if (m_LastStreamingDestination) - m_LastStreamingDestination->HandleDataMessagePayload (buf, length); + m_LastStreamingDestination->HandleDataMessagePayload (buf, length, from); else LogPrint (eLogError, "Destination: Missing streaming destination"); } diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 35557859..f2bef491 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -174,7 +174,7 @@ namespace client 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 HandleDataMessage (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) = 0; virtual void CreateNewLeaseSet (const std::vector >& tunnels) = 0; private: @@ -288,7 +288,7 @@ namespace client void CleanupDestination () override; i2p::data::CryptoKeyType GetPreferredCryptoType () const override { return m_PreferredCryptoType; } // I2CP - void HandleDataMessage (const uint8_t * buf, size_t len) override; + void HandleDataMessage (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) override; void CreateNewLeaseSet (const std::vector >& tunnels) override; private: diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 8d125e6f..cb401b06 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -397,6 +397,7 @@ namespace stream optionData += 2; } + bool sessionVerified = false; if (flags & PACKET_FLAG_FROM_INCLUDED) { if (m_RemoteLeaseSet) m_RemoteIdentity = m_RemoteLeaseSet->GetIdentity (); @@ -409,7 +410,29 @@ namespace stream } optionData += m_RemoteIdentity->GetFullLen (); if (!m_RemoteLeaseSet) - LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); + { + LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase32 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); + if (packet->from) + { + // stream came from ratchets session and static key must match one from LeaseSet + m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ()); + if (!m_RemoteLeaseSet) + { + LogPrint (eLogInfo, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase32 (), + " without LeaseSet. sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); + return false; + } + uint8_t staticKey[32]; + m_RemoteLeaseSet->Encrypt (nullptr, staticKey); + if (memcmp (packet->from->GetRemoteStaticKey (), staticKey, 32)) + { + LogPrint (eLogError, "Streaming: Remote LeaseSet static key mismatch for incoming stream from ", + m_RemoteIdentity->GetIdentHash ().ToBase32 ()); + return false; + } + sessionVerified = true; + } + } } if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED) @@ -451,35 +474,39 @@ namespace stream if (flags & PACKET_FLAG_SIGNATURE_INCLUDED) { - bool verified = false; auto signatureLen = m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : m_RemoteIdentity->GetSignatureLen (); 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 ()); - } + bool verified = sessionVerified; + if (!verified) // packet was not verified through session + { + // verify actual signature + 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 @@ -812,7 +839,7 @@ namespace stream { // initial packet m_Status = eStreamStatusOpen; - if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());; + if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ()); if (m_RemoteLeaseSet) { m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true, !m_IsIncoming); @@ -2054,14 +2081,18 @@ namespace stream } } - void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len) + void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len, + i2p::garlic::ECIESX25519AEADRatchetSession * from) { // unzip it Packet * uncompressed = NewPacket (); uncompressed->offset = 0; uncompressed->len = m_Inflator.Inflate (buf, len, uncompressed->buf, MAX_PACKET_SIZE); if (uncompressed->len) + { + uncompressed->from = from; HandleNextPacket (uncompressed); + } else DeletePacket (uncompressed); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 9fbcb178..eae43c0e 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -27,6 +27,7 @@ #include "Garlic.h" #include "Tunnel.h" #include "util.h" // MemoryPool +#include "ECIESX25519AEADRatchetSession.h" namespace i2p { @@ -88,8 +89,9 @@ namespace stream uint8_t buf[MAX_PACKET_SIZE]; uint64_t sendTime; bool resent; + i2p::garlic::ECIESX25519AEADRatchetSession * from; - Packet (): len (0), offset (0), sendTime (0), resent (false) {}; + Packet (): len (0), offset (0), sendTime (0), resent (false), from (nullptr) {}; uint8_t * GetBuffer () { return buf + offset; }; size_t GetLength () const { return len > offset ? len - offset : 0; }; @@ -340,7 +342,7 @@ namespace stream void SetOwner (std::shared_ptr owner) { m_Owner = owner; }; uint16_t GetLocalPort () const { return m_LocalPort; }; - void HandleDataMessagePayload (const uint8_t * buf, size_t len); + void HandleDataMessagePayload (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from); std::shared_ptr CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort, bool checksum = true, bool gzip = false); Packet * NewPacket () { return m_PacketsPool.Acquire(); } diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 11278e7a..f2e9be57 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -86,7 +86,8 @@ namespace client return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL; } - void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len) + void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len, + i2p::garlic::ECIESX25519AEADRatchetSession * from) { uint32_t length = bufbe32toh (buf); if (length > len - 4) length = len - 4; diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 37c14dbb..0bfa49f2 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -117,7 +117,7 @@ namespace client void CleanupDestination () override; i2p::data::CryptoKeyType GetPreferredCryptoType () const override; // I2CP - void HandleDataMessage (const uint8_t * buf, size_t len) override; + void HandleDataMessage (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) override; void CreateNewLeaseSet (const std::vector >& tunnels) override; private: From a6bf6baf1ba8ebecda82001fdcab0d1422caded4 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Jun 2025 18:32:43 -0400 Subject: [PATCH 518/527] don't verify signature for SYN-ACK if comes from ECIESx25519 session --- libi2pd/Streaming.cpp | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index cb401b06..ae14a38d 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -412,26 +412,21 @@ namespace stream if (!m_RemoteLeaseSet) { LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase32 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); - if (packet->from) - { - // stream came from ratchets session and static key must match one from LeaseSet + if (packet->from) // try to obtain LeaseSet if came from ratchets session m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ()); - if (!m_RemoteLeaseSet) - { - LogPrint (eLogInfo, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase32 (), - " without LeaseSet. sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); - return false; - } - uint8_t staticKey[32]; - m_RemoteLeaseSet->Encrypt (nullptr, staticKey); - if (memcmp (packet->from->GetRemoteStaticKey (), staticKey, 32)) - { - LogPrint (eLogError, "Streaming: Remote LeaseSet static key mismatch for incoming stream from ", - m_RemoteIdentity->GetIdentHash ().ToBase32 ()); - return false; - } - sessionVerified = true; + } + if (packet->from && m_RemoteLeaseSet) + { + // stream came from ratchets session and static key must match one from LeaseSet + uint8_t staticKey[32]; + m_RemoteLeaseSet->Encrypt (nullptr, staticKey); + if (memcmp (packet->from->GetRemoteStaticKey (), staticKey, 32)) + { + LogPrint (eLogError, "Streaming: Remote LeaseSet static key mismatch for stream from ", + m_RemoteIdentity->GetIdentHash ().ToBase32 ()); + return false; } + sessionVerified = true; } } From 6b519c36c5f1f2f47286d9625af4a37760478fcf Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 20 Jun 2025 13:34:20 -0400 Subject: [PATCH 519/527] increased number of floodfills threshold --- libi2pd/NetDb.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index f2a7019b..8d17628f 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -41,7 +41,7 @@ namespace data const int NETDB_MIN_ROUTERS = 90; const int NETDB_MIN_FLOODFILLS = 5; const int NETDB_MIN_TRANSPORTS = 10 ; // otherwise assume offline - const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1200; + const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1500; const int NETDB_NUM_ROUTERS_THRESHOLD = 4*NETDB_NUM_FLOODFILLS_THRESHOLD; const int NETDB_TUNNEL_CREATION_RATE_THRESHOLD = 10; // in % const int NETDB_CHECK_FOR_EXPIRATION_UPTIME = 600; // 10 minutes, in seconds From 9efdc230a912f51fafe577d4a2cb91d216870685 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 21 Jun 2025 22:07:59 -0400 Subject: [PATCH 520/527] don't check destination if first packet comes from ECIESx25519 session --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index ae14a38d..e2790288 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -187,7 +187,7 @@ namespace stream if (!m_SendStreamID) { m_SendStreamID = packet->GetReceiveStreamID (); - if (!m_RemoteIdentity && packet->GetNACKCount () == 8 && // first incoming packet + if (!m_RemoteIdentity && !packet->from && packet->GetNACKCount () == 8 && // first incoming packet memcmp (packet->GetNACKs (), m_LocalDestination.GetOwner ()->GetIdentHash (), 32)) { LogPrint (eLogWarning, "Streaming: Destination mismatch for ", m_LocalDestination.GetOwner ()->GetIdentHash ().ToBase32 ()); From 75dd0d72c66c9c86d71ee6efbd2b58103bea7589 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Jun 2025 21:53:44 -0400 Subject: [PATCH 521/527] skip transient signature verification if verified through ECIESx25519 session --- libi2pd/Streaming.cpp | 47 +++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index e2790288..66c8919d 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -444,27 +444,44 @@ namespace stream LogPrint (eLogInfo, "Streaming: offline signature without identity"); return false; } - // if we have it in LeaseSet already we don't need to parse it again - if (m_RemoteLeaseSet) m_TransientVerifier = m_RemoteLeaseSet->GetTransientVerifier (); - if (m_TransientVerifier) + if (sessionVerified) { - // skip option data - optionData += 6; // timestamp and key type - optionData += m_TransientVerifier->GetPublicKeyLen (); // public key + // skip offline signature + optionData += 4; // timestamp + uint16_t keyType = bufbe16toh (optionData); optionData += 2; // key type + std::unique_ptr transientVerifier (i2p::data::IdentityEx::CreateVerifier (keyType)); + if (!transientVerifier) + { + LogPrint (eLogInfo, "Streaming: Unknown offline signature key type ", (int)keyType); + return false; + } + optionData += transientVerifier->GetPublicKeyLen (); // public key optionData += m_RemoteIdentity->GetSignatureLen (); // signature } else - { - // transient key - size_t offset = 0; - m_TransientVerifier = i2p::data::ProcessOfflineSignature (m_RemoteIdentity, optionData, optionSize - (optionData - packet->GetOptionData ()), offset); - optionData += offset; - if (!m_TransientVerifier) + { + // if we have it in LeaseSet already we don't need to parse it again + if (m_RemoteLeaseSet) m_TransientVerifier = m_RemoteLeaseSet->GetTransientVerifier (); + if (m_TransientVerifier) { - LogPrint (eLogError, "Streaming: offline signature failed"); - return false; + // skip option data + optionData += 6; // timestamp and key type + optionData += m_TransientVerifier->GetPublicKeyLen (); // public key + optionData += m_RemoteIdentity->GetSignatureLen (); // signature } - } + else + { + // transient key + size_t offset = 0; + m_TransientVerifier = i2p::data::ProcessOfflineSignature (m_RemoteIdentity, optionData, optionSize - (optionData - packet->GetOptionData ()), offset); + optionData += offset; + if (!m_TransientVerifier) + { + LogPrint (eLogError, "Streaming: offline signature failed"); + return false; + } + } + } } if (flags & PACKET_FLAG_SIGNATURE_INCLUDED) From 40b90ccea4750f579b02289fae0a6fbce3e9eb48 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 24 Jun 2025 18:00:02 -0400 Subject: [PATCH 522/527] recognize and verify datagram3 --- libi2pd/Datagram.cpp | 52 +++++++++++++++++++++++++++++++++++++---- libi2pd/Datagram.h | 12 ++++++---- libi2pd/Destination.cpp | 12 ++++------ libi2pd/Destination.h | 2 ++ 4 files changed, 61 insertions(+), 17 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 732efca7..1903f7ae 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -126,6 +126,34 @@ namespace datagram LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram"); } + void DatagramDestination::HandleDatagram3 (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, + i2p::garlic::ECIESX25519AEADRatchetSession * from) + { + if (from) + { + i2p::data::IdentHash ident(buf); + auto ls = m_Owner->FindLeaseSet (ident); + if (ls) + { + uint8_t staticKey[32]; + ls->Encrypt (nullptr, staticKey); + if (!memcmp (from->GetRemoteStaticKey (), staticKey, 32)) + { + auto session = ObtainSession (ident); + session->SetRemoteLeaseSet (ls); + session->Ack (); + // TODO: + } + else + LogPrint (eLogError, "Datagram: Remote LeaseSet static key mismatch for datagram3 from ", ident.ToBase32 ()); + } + else + LogPrint (eLogError, "Datagram: No remote LeaseSet for ", ident.ToBase32 ()); + } + else + LogPrint (eLogInfo, "Datagram: datagram3 received from non-ratchets session"); + } + void DatagramDestination::SetReceiver (const Receiver& receiver, uint16_t port) { std::lock_guard lock(m_ReceiversMutex); @@ -194,17 +222,31 @@ namespace datagram return r; } - void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw) + void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, + const uint8_t * buf, size_t len, uint8_t protocolType, i2p::garlic::ECIESX25519AEADRatchetSession * from) { // unzip it uint8_t uncompressed[MAX_DATAGRAM_SIZE]; size_t uncompressedLen = m_Inflator.Inflate (buf, len, uncompressed, MAX_DATAGRAM_SIZE); if (uncompressedLen) { - if (isRaw) - HandleRawDatagram (fromPort, toPort, uncompressed, uncompressedLen); - else - HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen); + switch (protocolType) + { + case i2p::client::PROTOCOL_TYPE_RAW: + HandleRawDatagram (fromPort, toPort, uncompressed, uncompressedLen); + break; + case i2p::client::PROTOCOL_TYPE_DATAGRAM3: + HandleDatagram3 (fromPort, toPort, uncompressed, uncompressedLen, from); + break; + case i2p::client::PROTOCOL_TYPE_DATAGRAM: + HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen); + break; + case i2p::client::PROTOCOL_TYPE_DATAGRAM2: + // TODO: + break; + default: + LogPrint (eLogInfo, "Datagram: unknown protocol type ", protocolType); + }; } else LogPrint (eLogWarning, "Datagram: decompression failed"); diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index dd358434..d68bdd07 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -20,6 +20,7 @@ #include "LeaseSet.h" #include "I2NPProtocol.h" #include "Garlic.h" +#include "ECIESX25519AEADRatchetSession.h" namespace i2p { @@ -64,8 +65,9 @@ namespace datagram /** get the last time in milliseconds for when we used this datagram session */ uint64_t LastActivity() const { return m_LastUse; } - bool IsRatchets () const { return m_RoutingSession && m_RoutingSession->IsRatchets (); } - + bool IsRatchets () const { return m_RoutingSession && m_RoutingSession->IsRatchets (); } + void SetRemoteLeaseSet (std::shared_ptr ls) { m_RemoteLeaseSet = ls; } + struct Info { std::shared_ptr IBGW; @@ -124,8 +126,8 @@ namespace datagram void SendRawDatagram (std::shared_ptr session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); void FlushSendQueue (std::shared_ptr session); - void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false); - + void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, + const uint8_t * buf, size_t len, uint8_t protocolType, i2p::garlic::ECIESX25519AEADRatchetSession * from); void SetReceiver (const Receiver& receiver, uint16_t port); void ResetReceiver (uint16_t port); @@ -147,6 +149,8 @@ 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); + void HandleDatagram3 (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, + i2p::garlic::ECIESX25519AEADRatchetSession * from); Receiver FindReceiver(uint16_t port); RawReceiver FindRawReceiver(uint16_t port); diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index e1ccbc92..4ce825a6 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1190,19 +1190,15 @@ namespace client } break; case PROTOCOL_TYPE_DATAGRAM: + case PROTOCOL_TYPE_RAW: + case PROTOCOL_TYPE_DATAGRAM2: + case PROTOCOL_TYPE_DATAGRAM3: // datagram protocol if (m_DatagramDestination) - m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length); + m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length, buf[9], from); else LogPrint (eLogError, "Destination: Missing datagram destination"); break; - case PROTOCOL_TYPE_RAW: - // raw datagram - if (m_DatagramDestination) - m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length, true); - else - LogPrint (eLogError, "Destination: Missing raw datagram destination"); - break; default: LogPrint (eLogError, "Destination: Data: Unexpected protocol ", buf[9]); } diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index f2bef491..717f35ce 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -37,6 +37,8 @@ namespace client const uint8_t PROTOCOL_TYPE_STREAMING = 6; const uint8_t PROTOCOL_TYPE_DATAGRAM = 17; const uint8_t PROTOCOL_TYPE_RAW = 18; + const uint8_t PROTOCOL_TYPE_DATAGRAM2 = 19; + const uint8_t PROTOCOL_TYPE_DATAGRAM3 = 20; const int PUBLISH_CONFIRMATION_TIMEOUT = 1800; // in milliseconds const int PUBLISH_VERIFICATION_TIMEOUT = 5; // in seconds after successful publish const int PUBLISH_VERIFICATION_TIMEOUT_VARIANCE = 3; // in seconds From 8c89c8368af4d8739024956f5d63096f2e6f637b Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 24 Jun 2025 22:06:36 -0400 Subject: [PATCH 523/527] handle Datagram3 --- libi2pd/Datagram.cpp | 22 +++++++++++++++++++++- libi2pd/Datagram.h | 2 ++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 1903f7ae..de4b5674 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -129,6 +129,11 @@ namespace datagram void DatagramDestination::HandleDatagram3 (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) { + if (len < 34) + { + LogPrint (eLogWarning, "Datagram: datagram3 is too short ", len); + return; + } if (from) { i2p::data::IdentHash ident(buf); @@ -142,7 +147,22 @@ namespace datagram auto session = ObtainSession (ident); session->SetRemoteLeaseSet (ls); session->Ack (); - // TODO: + auto r = FindReceiver(toPort); + if (r) + { + uint16_t flags = bufbe16toh (buf + 32); + size_t offset = 34; + if (flags & DATAGRAM3_FLAG_OPTIONS) + offset += bufbe16toh (buf + offset) + 2; + if (offset > len) + { + LogPrint (eLogWarning, "Datagram: datagram3 is too short ", len, " expected ", offset); + return; + } + r(*ls->GetIdentity (), fromPort, toPort, buf + offset, len - offset); + } + else + LogPrint (eLogWarning, "Datagram: no receiver for port ", toPort); } else LogPrint (eLogError, "Datagram: Remote LeaseSet static key mismatch for datagram3 from ", ident.ToBase32 ()); diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index d68bdd07..a293c84b 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -45,6 +45,8 @@ namespace datagram const uint64_t DATAGRAM_MAX_FLUSH_INTERVAL = 5; // in milliseconds const int DATAGRAM_SESSION_ACK_REQUEST_INTERVAL = 5500; // in milliseconds + constexpr uint16_t DATAGRAM3_FLAG_OPTIONS = 0x10; + class DatagramSession : public std::enable_shared_from_this { From 31b6f07b788e6813ca128149cb25878f2edef72c Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 26 Jun 2025 18:01:03 -0400 Subject: [PATCH 524/527] set ECIESx25519 session's destination from LeaseSet --- libi2pd/Destination.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 4ce825a6..394435c5 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -489,7 +489,9 @@ namespace client if (leaseSet->GetIdentHash () != GetIdentHash ()) { LogPrint (eLogDebug, "Destination: New remote LeaseSet added"); - m_RemoteLeaseSets[key] = leaseSet; + m_RemoteLeaseSets.insert_or_assign (key, leaseSet); + if (from) + from->SetDestination (key); } else LogPrint (eLogDebug, "Destination: Own remote LeaseSet dropped"); From 0445a5d775ec9c5cfb140baef5e47d393826ac16 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Jun 2025 15:47:19 -0400 Subject: [PATCH 525/527] send actual version in SetDate --- libi2pd_client/I2CP.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index f2e9be57..5603697d 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -624,17 +624,14 @@ namespace client void I2CPSession::GetDateMessageHandler (const uint8_t * buf, size_t len) { - // get version - auto version = ExtractString (buf, len); - auto l = version.length () + 1 + 8; - uint8_t * payload = new uint8_t[l]; + constexpr std::string_view version(I2P_VERSION); + std::array payload; // set date auto ts = i2p::util::GetMillisecondsSinceEpoch (); - htobe64buf (payload, ts); - // echo vesrion back - PutString (payload + 8, l - 8, version); - SendI2CPMessage (I2CP_SET_DATE_MESSAGE, payload, l); - delete[] payload; + htobe64buf (payload.data(), ts); + // send our version back + PutString (payload.data() + 8, payload.size() - 8, version); + SendI2CPMessage (I2CP_SET_DATE_MESSAGE, payload.data(), payload.size()); } void I2CPSession::CreateSessionMessageHandler (const uint8_t * buf, size_t len) From f230c110aa25bebe63be175ccb9825c8d6bfa0bf Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Jun 2025 15:49:42 -0400 Subject: [PATCH 526/527] send actual version in SetDate --- libi2pd_client/I2CP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 5603697d..85c58c48 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -625,7 +625,7 @@ namespace client void I2CPSession::GetDateMessageHandler (const uint8_t * buf, size_t len) { constexpr std::string_view version(I2P_VERSION); - std::array payload; + std::array payload; // set date auto ts = i2p::util::GetMillisecondsSinceEpoch (); htobe64buf (payload.data(), ts); From a5631bd1b5169a8fd60fc30ddfc8b18cf8bb6e50 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Jun 2025 15:57:17 -0400 Subject: [PATCH 527/527] send Datagram3 --- libi2pd/Datagram.cpp | 38 ++++++++++++++++++++++++-------------- libi2pd/Datagram.h | 13 ++++++++++++- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index de4b5674..2f3d5eef 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -58,25 +58,35 @@ namespace datagram { if (session) { - if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) + if (session->GetVersion () == eDatagramV3) { - uint8_t hash[32]; - SHA256(payload, len, hash); - m_Owner->Sign (hash, 32, m_Signature.data ()); + constexpr uint8_t flags[] = { 0x00, 0x03 }; // datagram3, no options + auto msg = CreateDataMessage ({{m_Owner->GetIdentity ()->GetIdentHash (), 32}, + {flags, 2}, {payload, len}}, fromPort, toPort, i2p::client::PROTOCOL_TYPE_DATAGRAM3, false); // datagram3 + session->SendMsg(msg); } else - m_Owner->Sign (payload, len, m_Signature.data ()); + { + if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) + { + uint8_t hash[32]; + SHA256(payload, len, hash); + m_Owner->Sign (hash, 32, m_Signature.data ()); + } + else + m_Owner->Sign (payload, len, m_Signature.data ()); - auto msg = CreateDataMessage ({{m_From.data (), m_From.size ()}, {m_Signature.data (), m_Signature.size ()}, {payload, len}}, - fromPort, toPort, false, !session->IsRatchets ()); // datagram - session->SendMsg(msg); + auto msg = CreateDataMessage ({{m_From.data (), m_From.size ()}, {m_Signature.data (), m_Signature.size ()}, {payload, len}}, + fromPort, toPort, i2p::client::PROTOCOL_TYPE_DATAGRAM, !session->IsRatchets ()); // datagram1 + session->SendMsg(msg); + } } } void DatagramDestination::SendRawDatagram (std::shared_ptr session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort) { if (session) - session->SendMsg(CreateDataMessage ({{payload, len}}, fromPort, toPort, true, !session->IsRatchets ())); // raw + session->SendMsg(CreateDataMessage ({{payload, len}}, fromPort, toPort, i2p::client::PROTOCOL_TYPE_RAW, !session->IsRatchets ())); // raw } void DatagramDestination::FlushSendQueue (std::shared_ptr session) @@ -145,6 +155,7 @@ namespace datagram if (!memcmp (from->GetRemoteStaticKey (), staticKey, 32)) { auto session = ObtainSession (ident); + session->SetVersion (eDatagramV3); session->SetRemoteLeaseSet (ls); session->Ack (); auto r = FindReceiver(toPort); @@ -274,7 +285,7 @@ namespace datagram std::shared_ptr DatagramDestination::CreateDataMessage ( const std::vector >& payloads, - uint16_t fromPort, uint16_t toPort, bool isRaw, bool checksum) + uint16_t fromPort, uint16_t toPort, uint8_t protocolType, bool checksum) { size_t size; auto msg = m_I2NPMsgsPool.AcquireShared (); @@ -290,8 +301,8 @@ namespace datagram { htobe32buf (msg->GetPayload (), size); // length htobe16buf (buf + 4, fromPort); // source port - htobe16buf (buf + 6, toPort); // destination port - buf[9] = isRaw ? i2p::client::PROTOCOL_TYPE_RAW : i2p::client::PROTOCOL_TYPE_DATAGRAM; // raw or datagram protocol + htobe16buf (buf + 6, toPort); // destination port + buf[9] = protocolType; // raw or datagram protocol msg->len += size + 4; msg->FillI2NPMessageHeader (eI2NPData, 0, checksum); } @@ -350,8 +361,7 @@ namespace datagram DatagramSession::DatagramSession(std::shared_ptr localDestination, const i2p::data::IdentHash & remoteIdent) : m_LocalDestination(localDestination), m_RemoteIdent(remoteIdent), - m_LastUse (0), m_LastFlush (0), - m_RequestingLS(false) + m_LastUse (0), m_LastFlush (0), m_RequestingLS (false), m_Version (eDatagramV1) { } diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index a293c84b..a6fc130d 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -45,6 +45,13 @@ namespace datagram const uint64_t DATAGRAM_MAX_FLUSH_INTERVAL = 5; // in milliseconds const int DATAGRAM_SESSION_ACK_REQUEST_INTERVAL = 5500; // in milliseconds + enum DatagramVersion + { + eDatagramV1 = 1, + eDatagramV2 = 2, + eDatagramV3 = 3, + }; + constexpr uint16_t DATAGRAM3_FLAG_OPTIONS = 0x10; class DatagramSession : public std::enable_shared_from_this @@ -69,6 +76,9 @@ namespace datagram bool IsRatchets () const { return m_RoutingSession && m_RoutingSession->IsRatchets (); } void SetRemoteLeaseSet (std::shared_ptr ls) { m_RemoteLeaseSet = ls; } + + DatagramVersion GetVersion () const { return m_Version; } + void SetVersion (DatagramVersion version) { m_Version = version; } struct Info { @@ -104,6 +114,7 @@ namespace datagram std::vector > m_SendQueue; uint64_t m_LastUse, m_LastFlush; // milliseconds bool m_RequestingLS; + DatagramVersion m_Version; }; typedef std::shared_ptr DatagramSession_ptr; @@ -147,7 +158,7 @@ namespace datagram std::shared_ptr ObtainSession(const i2p::data::IdentHash & ident); std::shared_ptr CreateDataMessage (const std::vector >& payloads, - uint16_t fromPort, uint16_t toPort, bool isRaw = false, bool checksum = true); + uint16_t fromPort, uint16_t toPort, uint8_t protocolType, bool checksum = true); 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);