diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 962f3805..a2f17b13 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -18,6 +18,21 @@ namespace i2p { namespace transport { + void SSU2IncompleteMessage::AttachNextFragment (const uint8_t * fragment, size_t fragmentSize) + { + if (msg->len + fragmentSize > msg->maxLen) + { + LogPrint (eLogInfo, "SSU2: I2NP message size ", msg->maxLen, " is not enough"); + auto newMsg = NewI2NPMessage (); + *newMsg = *msg; + msg = newMsg; + } + if (msg->Concat (fragment, fragmentSize) < fragmentSize) + LogPrint (eLogError, "SSU2: I2NP buffer overflow ", msg->maxLen); + nextFragmentNum++; + } + + SSU2Session::SSU2Session (SSU2Server& server, std::shared_ptr in_RemoteRouter, std::shared_ptr addr): TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT), @@ -1519,7 +1534,7 @@ namespace transport void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len) { uint32_t msgID; memcpy (&msgID, buf + 1, 4); - auto msg = NewI2NPMessage (); + auto msg = NewI2NPShortMessage (); // same format as I2NP message block msg->len = msg->offset + len + 7; memcpy (msg->GetNTCP2Header (), buf, len); @@ -1557,10 +1572,11 @@ namespace transport auto it = m_IncompleteMessages.find (msgID); if (it != m_IncompleteMessages.end ()) { - if (it->second->nextFragmentNum == fragmentNum && it->second->msg) + if (it->second->nextFragmentNum == fragmentNum && fragmentNum < SSU2_MAX_NUM_FRAGMENTS && + it->second->msg) { // in sequence - it->second->msg->Concat (buf + 5, len - 5); + it->second->AttachNextFragment (buf + 5, len - 5); if (isLast) { it->second->msg->FromNTCP2 (); @@ -1569,7 +1585,6 @@ namespace transport } else { - it->second->nextFragmentNum++; if (ConcatOutOfSequenceFragments (it->second)) { m_Handler.PutNextMessage (std::move (it->second->msg)); @@ -1589,6 +1604,11 @@ namespace transport it = m_IncompleteMessages.emplace (msgID, msg).first; } // insert out of sequence fragment + if (fragmentNum >= SSU2_MAX_NUM_FRAGMENTS) + { + LogPrint (eLogWarning, "SSU2: Fragment number ", fragmentNum, " exceeds ", SSU2_MAX_NUM_FRAGMENTS); + return; + } auto fragment = std::make_shared (); memcpy (fragment->buf, buf + 5, len -5); fragment->len = len - 5; @@ -1604,10 +1624,9 @@ namespace transport for (auto it = m->outOfSequenceFragments.begin (); it != m->outOfSequenceFragments.end ();) if (it->first == m->nextFragmentNum) { - m->msg->Concat (it->second->buf, it->second->len); + m->AttachNextFragment (it->second->buf, it->second->len); isLast = it->second->isLast; it = m->outOfSequenceFragments.erase (it); - m->nextFragmentNum++; } else break; diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index eae593c2..299c79f1 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -45,6 +45,7 @@ namespace transport const float SSU2_kAPPA = 1.8; const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 500; // in messages const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send + const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64; enum SSU2MessageType { @@ -167,6 +168,8 @@ namespace transport int nextFragmentNum; uint32_t lastFragmentInsertTime; // in seconds std::map > outOfSequenceFragments; + + void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize); }; // RouterInfo flags