diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index eff2533a..7440f6ba 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -165,7 +165,7 @@ namespace datagram session->Ack(); auto r = FindReceiver(toPort); if(r) - r(identity, fromPort, toPort, buf + headerLen, len -headerLen); + r(identity, fromPort, toPort, buf + headerLen, len - headerLen, nullptr); else LogPrint (eLogWarning, "DatagramDestination: no receiver for port ", toPort); } @@ -218,8 +218,20 @@ namespace datagram } uint16_t flags = bufbe16toh (buf + identityLen); size_t offset = identityLen + 2; + bool isOptions = false; if (flags & DATAGRAM2_FLAG_OPTIONS) - offset += bufbe16toh (buf + offset) + 2; + { + isOptions = true; + m_Options.CleanUp (); + auto optionsLen = m_Options.FromBuffer (buf + offset, len - offset); + if (optionsLen) + offset += optionsLen; + else + { + LogPrint (eLogWarning, "Datagram: datagram2 can't read options"); + return; + } + } if (offset > len) { LogPrint (eLogWarning, "Datagram: datagram2 is too short ", len, " expected ", offset); @@ -256,7 +268,7 @@ namespace datagram session->Ack(); auto r = FindReceiver(toPort); if(r) - r(identity, fromPort, toPort, buf + offset, len - offset - signatureLen); + r(identity, fromPort, toPort, buf + offset, len - offset - signatureLen, isOptions ? &m_Options : nullptr); else LogPrint (eLogWarning, "DatagramDestination: no receiver for port ", toPort); } @@ -288,14 +300,26 @@ namespace datagram { uint16_t flags = bufbe16toh (buf + 32); size_t offset = 34; + bool isOptions = false; if (flags & DATAGRAM3_FLAG_OPTIONS) - offset += bufbe16toh (buf + offset) + 2; + { + isOptions = true; + m_Options.CleanUp (); + auto optionsLen = m_Options.FromBuffer (buf + offset, len - offset); + if (optionsLen) + offset += optionsLen; + else + { + LogPrint (eLogWarning, "Datagram: datagram3 can't read options"); + return; + } + } if (offset > len) { LogPrint (eLogWarning, "Datagram: datagram3 is too short ", len, " expected ", offset); return; } - r(*ls->GetIdentity (), fromPort, toPort, buf + offset, len - offset); + r(*ls->GetIdentity (), fromPort, toPort, buf + offset, len - offset, isOptions ? &m_Options : nullptr); } else LogPrint (eLogWarning, "Datagram: no receiver for port ", toPort); diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index f962d402..cbe0e6c3 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -20,6 +20,7 @@ #include "LeaseSet.h" #include "I2NPProtocol.h" #include "Garlic.h" +#include "util.h" #include "ECIESX25519AEADRatchetSession.h" namespace i2p @@ -124,7 +125,8 @@ namespace datagram const size_t MAX_DATAGRAM_SIZE = 32768; class DatagramDestination { - typedef std::function Receiver; + typedef std::function Receiver; typedef std::function RawReceiver; public: @@ -193,6 +195,7 @@ namespace datagram DatagramVersion m_Version; // default for destination i2p::data::GzipInflator m_Inflator; std::unique_ptr m_Deflator; + i2p::util::Mapping m_Options; std::vector m_From, m_Signature; i2p::util::MemoryPool > m_I2NPMsgsPool; }; diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index ac915814..e9eb6f20 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -223,7 +223,7 @@ namespace util size_t Mapping::FromBuffer (size_t size, const uint8_t * buf, size_t len) { - if (len < size) return 0; + if (!size || len < size) return 0; size_t offset = 0; while (offset < size) { diff --git a/libi2pd/util.h b/libi2pd/util.h index 12d96be2..006fbee3 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -239,6 +239,7 @@ namespace util std::string_view operator[](std::string_view param) const; bool Insert (std::string_view param, std::string_view value); void CleanUp (); + bool IsEmpty () const { return m_Options.empty (); } static std::string_view ExtractString (const uint8_t * buf, size_t len); static size_t WriteString (std::string_view str, uint8_t * buf, size_t len); diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 80987c78..6cb48660 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -459,7 +459,8 @@ namespace client } if (type == SAMSessionType::eSAMSessionTypeDatagram) dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (), - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4, std::placeholders::_5, std::placeholders::_6), port ); else // raw @@ -1290,7 +1291,8 @@ namespace client LogPrint (eLogWarning, "SAM: I2P forward acceptor has been reset"); } - void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, + const uint8_t * buf, size_t len, const i2p::util::Mapping * options) { LogPrint (eLogDebug, "SAM: Datagram received ", len); auto base64 = from.ToBase64 (); diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index fd73003f..96b89487 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -145,7 +145,8 @@ namespace client void HandleI2PAccept (std::shared_ptr stream); void HandleI2PForward (std::shared_ptr stream, boost::asio::ip::tcp::endpoint ep); void HandleWriteI2PData (const boost::system::error_code& ecode, size_t sz); - void HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + void HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, + const uint8_t * buf, size_t len, const i2p::util::Mapping * options); void HandleI2PRawDatagramReceive (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void ProcessSessionCreate (std::string_view buf); diff --git a/libi2pd_client/UDPTunnel.cpp b/libi2pd_client/UDPTunnel.cpp index 54c4a21d..12e8e5be 100644 --- a/libi2pd_client/UDPTunnel.cpp +++ b/libi2pd_client/UDPTunnel.cpp @@ -16,7 +16,8 @@ namespace i2p { namespace client { - void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, + const uint8_t * buf, size_t len, const i2p::util::Mapping * options) { if (!m_LastSession || m_LastSession->Identity.GetLL()[0] != from.GetIdentHash ().GetLL()[0] || fromPort != m_LastSession->RemotePort) m_LastSession = ObtainUDPSession(from, toPort, fromPort); @@ -189,7 +190,8 @@ namespace client auto dgram = m_LocalDest->CreateDatagramDestination (m_Gzip); dgram->SetReceiver ( - std::bind (&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), + std::bind (&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6), m_inPort ); dgram->SetRawReceiver ( @@ -259,7 +261,7 @@ namespace client dgram->SetReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, - std::placeholders::_5), + std::placeholders::_5, std::placeholders::_6), RemotePort ); dgram->SetRawReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2PRaw, this, @@ -392,7 +394,8 @@ namespace client LogPrint(eLogInfo, "UDP Tunnel: Resolved ", m_RemoteDest, " to ", m_RemoteAddr->identHash.ToBase32 ()); } - void I2PUDPClientTunnel::HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + void I2PUDPClientTunnel::HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, + const uint8_t * buf, size_t len, const i2p::util::Mapping * options) { if (m_RemoteAddr && from.GetIdentHash() == m_RemoteAddr->identHash) HandleRecvFromI2PRaw (fromPort, toPort, buf, len); diff --git a/libi2pd_client/UDPTunnel.h b/libi2pd_client/UDPTunnel.h index 7303aa9a..f25c5362 100644 --- a/libi2pd_client/UDPTunnel.h +++ b/libi2pd_client/UDPTunnel.h @@ -16,6 +16,7 @@ #include #include #include +#include "util.h" #include "Identity.h" #include "Destination.h" #include "Datagram.h" @@ -101,7 +102,8 @@ namespace client private: - void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, + const uint8_t * buf, size_t len, const i2p::util::Mapping * options); void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); UDPSessionPtr ObtainUDPSession (const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort); uint32_t GetSessionIndex (uint16_t fromPort, uint16_t toPort) const { return ((uint32_t)fromPort << 16) + toPort; } @@ -155,7 +157,8 @@ namespace client typedef std::pair UDPConvo; void RecvFromLocal (); void HandleRecvFromLocal (const boost::system::error_code & e, std::size_t transferred); - void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, + const uint8_t * buf, size_t len, const i2p::util::Mapping * options); void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void TryResolving ();