From d47ae3012a80867996a289deae703925dc3763d5 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 15 Aug 2024 13:35:51 -0400 Subject: [PATCH] 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; };