From 3f0534134dc30c878b2e15279d2bc1d52bbfda18 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 4 Jul 2019 13:05:39 -0400 Subject: [PATCH 01/36] check for malformed b33 --- libi2pd/Blinding.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libi2pd/Blinding.cpp b/libi2pd/Blinding.cpp index 14852340..e51c0fcc 100644 --- a/libi2pd/Blinding.cpp +++ b/libi2pd/Blinding.cpp @@ -139,6 +139,11 @@ namespace data { uint8_t addr[40]; // TODO: define length from b33 size_t l = i2p::data::Base32ToByteStream (b33.c_str (), b33.length (), addr, 40); + if (l < 32) + { + LogPrint (eLogError, "Blinding: malformed b33 ", b33); + return; + } uint32_t checksum = crc32 (0, addr + 3, l - 3); // checksum is Little Endian addr[0] ^= checksum; addr[1] ^= (checksum >> 8); addr[2] ^= (checksum >> 16); From a605e4bab6206c1d710aa1a2c58dcb69a100c2f2 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 9 Jul 2019 21:33:55 -0400 Subject: [PATCH 02/36] send and recieve raw datagrams --- libi2pd/Datagram.cpp | 43 +++++++++++++++++++++++++++++------------ libi2pd/Datagram.h | 26 ++++++++++++++++--------- libi2pd/Destination.cpp | 7 +++++++ 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index ed87a054..d971a83b 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -12,10 +12,8 @@ namespace i2p namespace datagram { DatagramDestination::DatagramDestination (std::shared_ptr owner): - m_Owner (owner.get()), - m_Receiver (nullptr) + m_Owner (owner), m_Receiver (nullptr), m_RawReceiver (nullptr) { - m_Identity.FromBase64 (owner->GetIdentity()->ToBase64()); } DatagramDestination::~DatagramDestination () @@ -28,14 +26,15 @@ namespace datagram auto owner = m_Owner; std::vector v(MAX_DATAGRAM_SIZE); uint8_t * buf = v.data(); - auto identityLen = m_Identity.ToBuffer (buf, MAX_DATAGRAM_SIZE); + auto localIdentity = m_Owner->GetIdentity (); + auto identityLen = localIdentity->ToBuffer (buf, MAX_DATAGRAM_SIZE); uint8_t * signature = buf + identityLen; - auto signatureLen = m_Identity.GetSignatureLen (); + auto signatureLen = localIdentity->GetSignatureLen (); uint8_t * buf1 = signature + signatureLen; size_t headerLen = identityLen + signatureLen; memcpy (buf1, payload, len); - if (m_Identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) + if (localIdentity->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) { uint8_t hash[32]; SHA256(buf1, len, hash); @@ -49,7 +48,13 @@ namespace datagram session->SendMsg(msg); } - + void DatagramDestination::SendRawDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort) + { + auto msg = CreateDataMessage (payload, len, fromPort, toPort, true); // raw + auto session = ObtainSession(identity); + session->SendMsg(msg); + } + void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort,uint8_t * const &buf, size_t len) { i2p::data::IdentityEx identity; @@ -82,6 +87,14 @@ namespace datagram LogPrint (eLogWarning, "Datagram signature verification failed"); } + void DatagramDestination::HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + { + if (m_RawReceiver) + m_RawReceiver (fromPort, toPort, buf, len); + else + LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram"); + } + DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port) { std::lock_guard lock(m_ReceiversMutex); @@ -92,18 +105,24 @@ namespace datagram return r; } - void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw) { // unzip it uint8_t uncompressed[MAX_DATAGRAM_SIZE]; size_t uncompressedLen = m_Inflator.Inflate (buf, len, uncompressed, MAX_DATAGRAM_SIZE); if (uncompressedLen) - HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen); + { + if (isRaw) + HandleRawDatagram (fromPort, toPort, uncompressed, uncompressedLen); + else + HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen); + } else LogPrint (eLogWarning, "Datagram: decompression failed"); } - std::shared_ptr DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort) + + std::shared_ptr DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort, bool isRaw) { auto msg = NewI2NPMessage (); uint8_t * buf = msg->GetPayload (); @@ -114,7 +133,7 @@ namespace datagram htobe32buf (msg->GetPayload (), size); // length htobe16buf (buf + 4, fromPort); // source port htobe16buf (buf + 6, toPort); // destination port - buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol + buf[9] = isRaw ? i2p::client::PROTOCOL_TYPE_DATAGRAM : i2p::client::PROTOCOL_TYPE_DATAGRAM; // raw or datagram protocol msg->len += size + 4; msg->FillI2NPMessageHeader (eI2NPData); } @@ -170,7 +189,7 @@ namespace datagram return nullptr; } - DatagramSession::DatagramSession(i2p::client::ClientDestination * localDestination, + DatagramSession::DatagramSession(std::shared_ptr localDestination, const i2p::data::IdentHash & remoteIdent) : m_LocalDestination(localDestination), m_RemoteIdent(remoteIdent), diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index 039417ea..0cfec838 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -37,7 +37,7 @@ namespace datagram class DatagramSession : public std::enable_shared_from_this { public: - DatagramSession(i2p::client::ClientDestination * localDestination, const i2p::data::IdentHash & remoteIdent); + DatagramSession(std::shared_ptr localDestination, const i2p::data::IdentHash & remoteIdent); void Start (); void Stop (); @@ -81,7 +81,7 @@ namespace datagram void HandleLeaseSetUpdated(std::shared_ptr ls); private: - i2p::client::ClientDestination * m_LocalDestination; + std::shared_ptr m_LocalDestination; i2p::data::IdentHash m_RemoteIdent; std::shared_ptr m_RemoteLeaseSet; std::shared_ptr m_RoutingSession; @@ -99,22 +99,28 @@ namespace datagram class DatagramDestination { typedef std::function Receiver; + typedef std::function RawReceiver; + public: DatagramDestination (std::shared_ptr owner); ~DatagramDestination (); - void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); - void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); - + void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); + void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); + void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false); + void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; }; void ResetReceiver () { m_Receiver = nullptr; }; void SetReceiver (const Receiver& receiver, uint16_t port) { std::lock_guard lock(m_ReceiversMutex); m_ReceiversByPorts[port] = receiver; }; void ResetReceiver (uint16_t port) { std::lock_guard lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); }; + void SetRawReceiver (const RawReceiver& receiver) { m_RawReceiver = receiver; }; + void ResetRawReceiver () { m_RawReceiver = nullptr; }; + std::shared_ptr GetInfoForRemote(const i2p::data::IdentHash & remote); // clean up stale sessions @@ -124,17 +130,19 @@ namespace datagram std::shared_ptr ObtainSession(const i2p::data::IdentHash & ident); - std::shared_ptr CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); + std::shared_ptr CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort, bool isRaw = false); void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len); - + void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + /** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */ Receiver FindReceiver(uint16_t port); private: - i2p::client::ClientDestination * m_Owner; - i2p::data::IdentityEx m_Identity; + + std::shared_ptr m_Owner; Receiver m_Receiver; // default + RawReceiver m_RawReceiver; // default std::mutex m_SessionsMutex; std::map m_Sessions; std::mutex m_ReceiversMutex; diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 5187fedc..ef7c7d21 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -977,6 +977,13 @@ namespace client 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]); } From cc451809cca87842a8431eafe8bee601fa0bb5a8 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 10 Jul 2019 11:32:56 -0400 Subject: [PATCH 03/36] send/receive raw datagrams through the SAM --- libi2pd_client/SAM.cpp | 77 +++++++++++++++++++++++++++++++++++------- libi2pd_client/SAM.h | 15 ++++++-- 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index acb9ea80..24e28c73 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -337,8 +337,20 @@ namespace client return; } + SAMSessionType type = eSAMSessionTypeUnknown; + if (style == SAM_VALUE_STREAM) type = eSAMSessionTypeStream; + else if (style == SAM_VALUE_DATAGRAM) type = eSAMSessionTypeDatagram; + else if (style == SAM_VALUE_RAW) type = eSAMSessionTypeRaw; + if (type == eSAMSessionTypeUnknown) + { + // unknown style + SendI2PError("Unknown STYLE"); + return; + } + std::shared_ptr forward = nullptr; - if (style == SAM_VALUE_DATAGRAM && params.find(SAM_VALUE_HOST) != params.end() && params.find(SAM_VALUE_PORT) != params.end()) + if ((type == eSAMSessionTypeDatagram || type == eSAMSessionTypeRaw) && + params.find(SAM_VALUE_HOST) != params.end() && params.find(SAM_VALUE_PORT) != params.end()) { // udp forward selected boost::system::error_code e; @@ -379,16 +391,20 @@ namespace client } // create destination - auto session = m_Owner.CreateSession (id, destination == SAM_VALUE_TRANSIENT ? "" : destination, ¶ms); + auto session = m_Owner.CreateSession (id, type, destination == SAM_VALUE_TRANSIENT ? "" : destination, ¶ms); if (session) { m_SocketType = eSAMSocketTypeSession; - if (style == SAM_VALUE_DATAGRAM) + if (type == eSAMSessionTypeDatagram || type == eSAMSessionTypeRaw) { session->UDPEndpoint = forward; auto dest = session->localDestination->CreateDatagramDestination (); - dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (), - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); + 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)); + else // raw + dest->SetRawReceiver (std::bind (&SAMSocket::HandleI2PRawDatagramReceive, shared_from_this (), + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); } if (session->localDestination->IsReady ()) @@ -550,7 +566,10 @@ namespace client { i2p::data::IdentityEx dest; dest.FromBase64 (params[SAM_PARAM_DESTINATION]); - d->SendDatagramTo ((const uint8_t *)data, size, dest.GetIdentHash ()); + if (session->Type == eSAMSessionTypeDatagram) + d->SendDatagramTo ((const uint8_t *)data, size, dest.GetIdentHash ()); + else // raw + d->SendRawDatagramTo ((const uint8_t *)data, size, dest.GetIdentHash ()); } else LogPrint (eLogError, "SAM: missing datagram destination"); @@ -926,16 +945,44 @@ namespace client } } + void SAMSocket::HandleI2PRawDatagramReceive (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + { + LogPrint (eLogDebug, "SAM: raw datagram received ", len); + auto session = m_Owner.FindSession(m_ID); + if(session) + { + auto ep = session->UDPEndpoint; + if (ep) + // udp forward enabled + m_Owner.SendTo(buf, len, ep); + else + { +#ifdef _MSC_VER + size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_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); +#endif + if (len < SAM_SOCKET_BUFFER_SIZE - l) + { + memcpy (m_StreamBuffer + l, buf, len); + WriteI2PData(len + l); + } + else + LogPrint (eLogWarning, "SAM: received raw datagram size ", len," exceeds buffer"); + } + } + } + void SAMSocket::HandleStreamSend(const boost::system::error_code & ec) { m_Owner.GetService ().post (std::bind( !ec ? &SAMSocket::Receive : &SAMSocket::TerminateClose, shared_from_this())); } - SAMSession::SAMSession (SAMBridge & parent, const std::string & id, std::shared_ptr dest): + SAMSession::SAMSession (SAMBridge & parent, const std::string & id, SAMSessionType type, std::shared_ptr dest): m_Bridge(parent), localDestination (dest), UDPEndpoint(nullptr), - Name(id) + Name(id), Type (type) { } @@ -1061,8 +1108,8 @@ namespace client Accept (); } - std::shared_ptr SAMBridge::CreateSession (const std::string& id, const std::string& destination, - const std::map * params) + std::shared_ptr SAMBridge::CreateSession (const std::string& id, SAMSessionType type, + const std::string& destination, const std::map * params) { std::shared_ptr localDestination = nullptr; if (destination != "") @@ -1102,7 +1149,7 @@ namespace client if (localDestination) { localDestination->Acquire (); - auto session = std::make_shared(*this, id, localDestination); + auto session = std::make_shared(*this, id, type, localDestination); std::unique_lock l(m_SessionsMutex); auto ret = m_Sessions.insert (std::make_pair(id, session)); if (!ret.second) @@ -1193,8 +1240,12 @@ namespace client { i2p::data::IdentityEx dest; dest.FromBase64 (destination); - session->localDestination->GetDatagramDestination ()-> - SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); + if (session->Type == eSAMSessionTypeDatagram) + session->localDestination->GetDatagramDestination ()-> + SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); + else // raw + session->localDestination->GetDatagramDestination ()-> + SendRawDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); } else LogPrint (eLogError, "SAM: Session ", sessionID, " not found"); diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 7cd3fd4c..44ad752d 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -46,6 +46,7 @@ namespace client const char SAM_NAMING_LOOKUP[] = "NAMING LOOKUP"; const char SAM_NAMING_REPLY[] = "NAMING REPLY RESULT=OK NAME=ME VALUE=%s\n"; const char SAM_DATAGRAM_RECEIVED[] = "DATAGRAM RECEIVED DESTINATION=%s SIZE=%lu\n"; + const char SAM_RAW_RECEIVED[] = "RAW RECEIVED SIZE=%lu\n"; const char SAM_NAMING_REPLY_INVALID_KEY[] = "NAMING REPLY RESULT=INVALID_KEY NAME=%s\n"; const char SAM_NAMING_REPLY_KEY_NOT_FOUND[] = "NAMING REPLY RESULT=KEY_NOT_FOUND NAME=%s\n"; const char SAM_PARAM_MIN[] = "MIN"; @@ -111,6 +112,7 @@ namespace client void HandleI2PAccept (std::shared_ptr stream); 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 HandleI2PRawDatagramReceive (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void ProcessSessionCreate (char * buf, size_t len); void ProcessStreamConnect (char * buf, size_t len, size_t rem); @@ -149,14 +151,23 @@ namespace client std::shared_ptr m_Stream; }; + enum SAMSessionType + { + eSAMSessionTypeUnknown, + eSAMSessionTypeStream, + eSAMSessionTypeDatagram, + eSAMSessionTypeRaw + }; + struct SAMSession { SAMBridge & m_Bridge; std::shared_ptr localDestination; std::shared_ptr UDPEndpoint; std::string Name; + SAMSessionType Type; - SAMSession (SAMBridge & parent, const std::string & name, std::shared_ptr dest); + SAMSession (SAMBridge & parent, const std::string & name, SAMSessionType type, std::shared_ptr dest); ~SAMSession (); void CloseStreams (); @@ -173,7 +184,7 @@ namespace client void Stop (); boost::asio::io_service& GetService () { return m_Service; }; - std::shared_ptr CreateSession (const std::string& id, const std::string& destination, // empty string means transient + std::shared_ptr CreateSession (const std::string& id, SAMSessionType type, const std::string& destination, // empty string means transient const std::map * params); void CloseSession (const std::string& id); std::shared_ptr FindSession (const std::string& id) const; From a204841abbe5f2c2c73bfdf9787d800dd974a060 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 10 Jul 2019 13:30:31 -0400 Subject: [PATCH 04/36] handle RAW SEND --- libi2pd_client/SAM.cpp | 2 +- libi2pd_client/SAM.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 24e28c73..224d84e8 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -259,7 +259,7 @@ namespace client ProcessDestGenerate (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); else if (!strcmp (m_Buffer, SAM_NAMING_LOOKUP)) ProcessNamingLookup (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); - else if (!strcmp (m_Buffer, SAM_DATAGRAM_SEND)) + else if (!strcmp (m_Buffer, SAM_DATAGRAM_SEND) || !strcmp (m_Buffer, SAM_RAW_SEND)) { size_t len = bytes_transferred - (separator - m_Buffer) - 1; size_t processed = ProcessDatagramSend (separator + 1, len, eol + 1); diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 44ad752d..aebdccb6 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -40,6 +40,7 @@ namespace client const char SAM_STREAM_STATUS_I2P_ERROR[] = "STREAM STATUS RESULT=I2P_ERROR\n"; const char SAM_STREAM_ACCEPT[] = "STREAM ACCEPT"; const char SAM_DATAGRAM_SEND[] = "DATAGRAM SEND"; + const char SAM_RAW_SEND[] = "RAW SEND"; const char SAM_DEST_GENERATE[] = "DEST GENERATE"; const char SAM_DEST_REPLY[] = "DEST REPLY PUB=%s PRIV=%s\n"; const char SAM_DEST_REPLY_I2P_ERROR[] = "DEST REPLY RESULT=I2P_ERROR\n"; From a090114066e94a3686f465ad94b89928315f7f56 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 10 Jul 2019 13:31:49 -0400 Subject: [PATCH 05/36] send data message wih raw type fpr raw datagrams --- libi2pd/Datagram.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index d971a83b..7e04fce8 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -133,7 +133,7 @@ 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_DATAGRAM : i2p::client::PROTOCOL_TYPE_DATAGRAM; // raw or datagram protocol + buf[9] = isRaw ? i2p::client::PROTOCOL_TYPE_RAW : i2p::client::PROTOCOL_TYPE_DATAGRAM; // raw or datagram protocol msg->len += size + 4; msg->FillI2NPMessageHeader (eI2NPData); } From 7d68ccca53edf5213e469dc8861f77f2a598ee3d Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 12 Jul 2019 15:37:32 -0400 Subject: [PATCH 06/36] create encrypted LeaseSet2 with authentication --- libi2pd/LeaseSet.cpp | 69 ++++++++++++++++++++++++++++++++++++++++---- libi2pd/LeaseSet.h | 17 ++++++++++- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 69a29377..46629d37 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -809,12 +809,20 @@ namespace data m_Buffer[0] = storeType; } - LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr ls, const i2p::data::PrivateKeys& keys, i2p::data::SigningKeyType blindedKeyType): + LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr ls, const i2p::data::PrivateKeys& keys, + LeaseSetAuthType authType, std::shared_ptr > authKeys): LocalLeaseSet2 (ls->GetIdentity ()), m_InnerLeaseSet (ls) { size_t lenInnerPlaintext = ls->GetBufferLen () + 1, lenOuterPlaintext = lenInnerPlaintext + 32 + 1, lenOuterCiphertext = lenOuterPlaintext + 32; m_BufferLen = 2/*blinded sig type*/ + 32/*blinded pub key*/ + 4/*published*/ + 2/*expires*/ + 2/*flags*/ + 2/*lenOuterCiphertext*/ + lenOuterCiphertext + 64/*signature*/; + uint8_t layer1Flags = 0; + if (authKeys) + { + if (authType == eLeaseSetAuthTypeDH) layer1Flags |= 0x01; // DH, authentication scheme 0, auth bit 1 + else if (authType == eLeaseSetAuthTypePSK) layer1Flags |= 0x03; // PSK, authentication scheme 1, auth bit 1 + m_BufferLen += authKeys->size ()*40 + 2; // auth data len + } m_Buffer = new uint8_t[m_BufferLen + 1]; m_Buffer[0] = NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; BlindedPublicKey blindedKey (ls->GetIdentity ()); @@ -823,9 +831,9 @@ namespace data i2p::util::GetDateString (timestamp, date); uint8_t blindedPriv[64], blindedPub[128]; // 64 and 128 max size_t publicKeyLen = blindedKey.BlindPrivateKey (keys.GetSigningPrivateKey (), date, blindedPriv, blindedPub); - std::unique_ptr blindedSigner (i2p::data::PrivateKeys::CreateSigner (blindedKeyType, blindedPriv)); + std::unique_ptr blindedSigner (i2p::data::PrivateKeys::CreateSigner (blindedKey.GetBlindedSigType (), blindedPriv)); auto offset = 1; - htobe16buf (m_Buffer + offset, blindedKeyType); offset += 2; // Blinded Public Key Sig Type + htobe16buf (m_Buffer + offset, blindedKey.GetBlindedSigType ()); offset += 2; // Blinded Public Key Sig Type memcpy (m_Buffer + offset, blindedPub, publicKeyLen); offset += publicKeyLen; // Blinded Public Key htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds) auto nextMidnight = (timestamp/86400LL + 1)*86400LL; // 86400 = 24*3600 seconds @@ -847,12 +855,27 @@ namespace data i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L1K", keys1); offset += 32; // outerSalt uint8_t * outerPlainText = m_Buffer + offset; - m_Buffer[offset] = 0; offset++; // flag + m_Buffer[offset] = layer1Flags; offset++; // layer 1 flags + // auth data + uint8_t innerInput[68]; // authCookie || subcredential || publishedTimestamp + if (layer1Flags) + { + RAND_bytes (innerInput, 32); // authCookie + htobe16buf (m_Buffer + offset, authKeys->size ()); offset += 2; // num clients + CreateClientAuthData (subcredential, authType, authKeys, innerInput, m_Buffer); + offset += authKeys->size ()*40; // auth clients + } // Layer 2 // keys = HKDF(outerSalt, outerInput, "ELS2_L2K", 44) uint8_t keys2[64]; // 44 bytes actual data RAND_bytes (m_Buffer + offset, 32); // innerSalt = CSRNG(32) - i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L2K", keys2); + if (layer1Flags) + { + memcpy (innerInput + 32, subcredential, 36); // + subcredential || publishedTimestamp + i2p::crypto::HKDF (m_Buffer + offset, innerInput, 68, "ELS2_L2K", keys2); + } + else + i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L2K", keys2); // no authCookie offset += 32; // innerSalt m_Buffer[offset] = ls->GetStoreType (); memcpy (m_Buffer + offset + 1, ls->GetBuffer (), ls->GetBufferLen ()); @@ -879,6 +902,40 @@ namespace data else LogPrint (eLogError, "LeaseSet2: couldn't extract inner layer"); } - + + void LocalEncryptedLeaseSet2::CreateClientAuthData (const uint8_t * subcredential, LeaseSetAuthType authType, std::shared_ptr > authKeys, const uint8_t * authCookie, uint8_t * authClients) const + { + if (authType == eLeaseSetAuthTypeDH) + { + i2p::crypto::X25519Keys ek; + ek.GenerateKeys (); // esk and epk + uint8_t authInput[100]; // sharedSecret || cpk_i || subcredential || publishedTimestamp + memcpy (authInput + 64, subcredential, 36); + for (auto& it: *authKeys) + { + ek.Agree (it, authInput); // sharedSecret = DH(esk, cpk_i) + memcpy (authInput + 32, it, 32); + uint8_t okm[64]; // 52 actual data + i2p::crypto::HKDF (ek.GetPublicKey (), authInput, 100, "ELS2_XCA", okm); + memcpy (authClients, okm + 44, 8); authClients += 8; // clientID_i + i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authClients); authClients += 32; // clientCookie_i + } + } + else // assume PSK + { + uint8_t authSalt[32]; + RAND_bytes (authSalt, 32); + uint8_t authInput[68]; // authInput = psk_i || subcredential || publishedTimestamp + memcpy (authInput + 32, subcredential, 36); + for (auto& it: *authKeys) + { + memcpy (authInput, it, 32); + uint8_t okm[64]; // 52 actual data + i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm); + memcpy (authClients, okm + 44, 8); authClients += 8; // clientID_i + i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authClients); authClients += 32; // clientCookie_i + } + } + } } } diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index a2ed6fba..c2b88da6 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -247,17 +247,32 @@ namespace data size_t m_BufferLen; }; + class LocalEncryptedLeaseSet2: public LocalLeaseSet2 { public: - LocalEncryptedLeaseSet2 (std::shared_ptr ls, const i2p::data::PrivateKeys& keys, i2p::data::SigningKeyType blindedKeyType = i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519); + enum LeaseSetAuthType + { + eLeaseSetAuthTypeNone = 0, + eLeaseSetAuthTypeDH = 1, + eLeaseSetAuthTypePSK = 2 + }; + typedef i2p::data::Tag<32> AuthPublicKey; + + public: + + LocalEncryptedLeaseSet2 (std::shared_ptr ls, const i2p::data::PrivateKeys& keys, LeaseSetAuthType authType = eLeaseSetAuthTypeNone, std::shared_ptr > authKeys = nullptr); LocalEncryptedLeaseSet2 (std::shared_ptr identity, const uint8_t * buf, size_t len); // from I2CP const IdentHash& GetStoreHash () const { return m_StoreHash; }; std::shared_ptr GetInnerLeaseSet () const { return m_InnerLeaseSet; }; + private: + + void CreateClientAuthData (const uint8_t * subcredential, LeaseSetAuthType authType, std::shared_ptr > authKeys, const uint8_t * authCookie, uint8_t * authClients) const; + private: IdentHash m_StoreHash; From 99e1b740236ee64d166b0e4c7fdd50d25ea76913 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 12 Jul 2019 15:40:59 -0400 Subject: [PATCH 07/36] create encrypted LeaseSet2 with authentication --- libi2pd/LeaseSet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 46629d37..d0eafd1d 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -821,7 +821,7 @@ namespace data { if (authType == eLeaseSetAuthTypeDH) layer1Flags |= 0x01; // DH, authentication scheme 0, auth bit 1 else if (authType == eLeaseSetAuthTypePSK) layer1Flags |= 0x03; // PSK, authentication scheme 1, auth bit 1 - m_BufferLen += authKeys->size ()*40 + 2; // auth data len + if (layer1Flags) m_BufferLen += authKeys->size ()*40 + 2; // auth data len } m_Buffer = new uint8_t[m_BufferLen + 1]; m_Buffer[0] = NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; From 925e8316c782485601417a273239b5f3d969cd30 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 12 Jul 2019 20:58:17 -0400 Subject: [PATCH 08/36] read i2cp.leaseSetAuthType, i2cp.leaseSetClient.dh.nnn and i2cp.leaseSetClient.psk.nnn from tunnel config --- libi2pd/Destination.h | 5 ++++- libi2pd_client/ClientContext.cpp | 19 +++++++++++++++++++ libi2pd_client/ClientContext.h | 2 ++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 35a9dbae..25f2f1c1 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -56,7 +56,10 @@ namespace client const int DEFAULT_LEASESET_TYPE = 1; const char I2CP_PARAM_LEASESET_ENCRYPTION_TYPE[] = "i2cp.leaseSetEncType"; const char I2CP_PARAM_LEASESET_PRIV_KEY[] = "i2cp.leaseSetPrivKey"; // PSK decryption key, base64 - + const char I2CP_PARAM_LEASESET_AUTH_TYPE[] = "i2cp.leaseSetAuthType"; + const char I2CP_PARAM_LEASESET_CLIENT_DH[] = "i2cp.leaseSetClient.dh"; // group of i2cp.leaseSetClient.dh.nnn + const char I2CP_PARAM_LEASESET_CLIENT_PSK[] = "i2cp.leaseSetClient.psk"; // group of i2cp.leaseSetClient.psk.nnn + // latency const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min"; const int DEFAULT_MIN_TUNNEL_LATENCY = 0; diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index c286007c..e10c1e07 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -381,6 +381,16 @@ namespace client return section.second.get (boost::property_tree::ptree::path_type (name, '/'), value); } + template + void ClientContext::ReadI2CPOptionsGroup (const Section& section, const std::string& group, std::map& options) const + { + for (auto it: section.second) + { + if (it.first.length () >= group.length () && !it.first.compare (0, group.length (), group)) + options[it.first] = it.second.get_value (""); + } + } + template void ClientContext::ReadI2CPOptions (const Section& section, std::map& options) const { @@ -397,6 +407,15 @@ namespace client 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; + auto authType = GetI2CPOption(section, I2CP_PARAM_LEASESET_AUTH_TYPE, 0); + if (authType != "0") // auth is set + { + options[I2CP_PARAM_LEASESET_TYPE] = authType; + if (authType == "1") // DH + ReadI2CPOptionsGroup (section, I2CP_PARAM_LEASESET_CLIENT_DH, options); + else if (authType == "2") // PSK + ReadI2CPOptionsGroup (section, I2CP_PARAM_LEASESET_CLIENT_PSK, options); + } } void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map& options) const diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index 71e052c3..94aa8594 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.h @@ -95,6 +95,8 @@ namespace client template std::string GetI2CPStringOption (const Section& section, const std::string& name, const std::string& value) const; // GetI2CPOption with string default value template + void ReadI2CPOptionsGroup (const Section& section, const std::string& group, std::map& options) const; + template void ReadI2CPOptions (const Section& section, std::map& options) const; // for tunnels void ReadI2CPOptionsFromConfig (const std::string& prefix, std::map& options) const; // for HTTP and SOCKS proxy From 54071b0e5dbc3b3296f64a6ed98f372945db477f Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 16 Jul 2019 11:48:30 -0400 Subject: [PATCH 09/36] set and handle unpublished LeaseSet flag --- libi2pd/Destination.cpp | 2 +- libi2pd/Destination.h | 1 + libi2pd/LeaseSet.cpp | 4 +++- libi2pd/LeaseSet.h | 7 +++++-- libi2pd/NetDb.cpp | 16 ++++++++++++---- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index ef7c7d21..ea884aa4 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1147,7 +1147,7 @@ namespace client // standard LS2 (type 3) first auto keyLen = m_Decryptor ? m_Decryptor->GetPublicKeyLen () : 256; auto ls2 = std::make_shared (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2, - m_Keys, m_EncryptionKeyType, keyLen, m_EncryptionPublicKey, tunnels); + m_Keys, m_EncryptionKeyType, keyLen, m_EncryptionPublicKey, tunnels, IsPublic ()); if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) // encrypt if type 5 ls2 = std::make_shared (ls2, m_Keys); leaseSet = ls2; diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 25f2f1c1..dcbe9768 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -134,6 +134,7 @@ namespace client void SetLeaseSet (std::shared_ptr newLeaseSet); int GetLeaseSetType () const { return m_LeaseSetType; }; void SetLeaseSetType (int leaseSetType) { m_LeaseSetType = leaseSetType; }; + bool IsPublic () const { return m_IsPublic; }; virtual void CleanupDestination () {}; // additional clean up in derived classes // I2CP virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0; diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index d0eafd1d..bd2fca75 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -302,6 +302,7 @@ namespace data return; } } + if (flags & LEASESET2_FLAG_UNPUBLISHED_LEASESET) m_IsPublic = false; // type specific part size_t s = 0; switch (m_StoreType) @@ -741,7 +742,7 @@ namespace data LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey, - std::vector > tunnels): + std::vector > tunnels, bool isPublic): LocalLeaseSet (keys.GetPublic (), nullptr, 0) { auto identity = keys.GetPublic (); @@ -756,6 +757,7 @@ namespace data flags |= LEASESET2_FLAG_OFFLINE_KEYS; m_BufferLen += keys.GetOfflineSignature ().size (); } + if (!isPublic) flags |= LEASESET2_FLAG_UNPUBLISHED_LEASESET; m_Buffer = new uint8_t[m_BufferLen + 1]; m_Buffer[0] = storeType; diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index c2b88da6..03e0e543 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -129,7 +129,8 @@ namespace data const uint8_t NETDB_STORE_TYPE_META_LEASESET2 = 7; const uint16_t LEASESET2_FLAG_OFFLINE_KEYS = 0x0001; - + const uint16_t LEASESET2_FLAG_UNPUBLISHED_LEASESET = 0x0002; + class LeaseSet2: public LeaseSet { public: @@ -139,6 +140,7 @@ namespace data uint8_t GetStoreType () const { return m_StoreType; }; uint8_t GetOrigStoreType () const { return m_OrigStoreType; }; uint32_t GetPublishedTimestamp () const { return m_PublishedTimestamp; }; + bool IsPublic () const { return m_IsPublic; }; std::shared_ptr GetTransientVerifier () const { return m_TransientVerifier; }; void Update (const uint8_t * buf, size_t len, bool verifySignature); @@ -162,6 +164,7 @@ namespace data uint8_t m_StoreType, m_OrigStoreType; uint32_t m_PublishedTimestamp = 0; + bool m_IsPublic = true; std::shared_ptr m_TransientVerifier; std::shared_ptr m_Encryptor; // for standardLS2 }; @@ -227,7 +230,7 @@ namespace data LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey, - std::vector > tunnels); + std::vector > tunnels, bool isPublic); LocalLeaseSet2 (uint8_t storeType, std::shared_ptr identity, const uint8_t * buf, size_t len); // from I2CP virtual ~LocalLeaseSet2 () { delete[] m_Buffer; }; diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index b7479744..4461c094 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -307,10 +307,18 @@ namespace data if (it == m_LeaseSets.end () || it->second->GetStoreType () != storeType || leaseSet->GetPublishedTimestamp () > it->second->GetPublishedTimestamp ()) { - // TODO: implement actual update - LogPrint (eLogInfo, "NetDb: LeaseSet2 updated: ", ident.ToBase32()); - m_LeaseSets[ident] = leaseSet; - return true; + if (leaseSet->IsPublic ()) + { + // TODO: implement actual update + LogPrint (eLogInfo, "NetDb: LeaseSet2 updated: ", ident.ToBase32()); + m_LeaseSets[ident] = leaseSet; + return true; + } + else + { + LogPrint (eLogWarning, "NetDb: Unpublished LeaseSet2 received: ", ident.ToBase32()); + m_LeaseSets.erase (ident); + } } } else From 97d9795fc9a2c672e2e97a31b3da9141364f1814 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 16 Jul 2019 16:31:17 -0400 Subject: [PATCH 10/36] pass encrepted LeaseSet auth keys --- libi2pd/Destination.cpp | 65 ++++++++++++++++++++++++++++++++++++----- libi2pd/Destination.h | 6 ++++ libi2pd/LeaseSet.cpp | 10 +++---- libi2pd/LeaseSet.h | 20 +++++-------- 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index ea884aa4..9355e75d 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -846,7 +846,7 @@ namespace client ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): LeaseSetDestination (isPublic, params), m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_DatagramDestination (nullptr), m_RefCounter (0), - m_ReadyChecker(GetService()) + m_ReadyChecker(GetService()), m_AuthType (i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_NONE) { if (keys.IsOfflineSignature () && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // offline keys can be published with LS2 only @@ -868,12 +868,46 @@ namespace client if (isPublic) LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); - // extract streaming params - if (params) + try + { + if (params) + { + // extract streaming params + auto it = params->find (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY); + if (it != params->end ()) + m_StreamingAckDelay = std::stoi(it->second); + + if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) + { + // authentication for encrypted LeaseSet + it = params->find (I2CP_PARAM_LEASESET_AUTH_TYPE); + m_AuthType = std::stoi (it->second); + if (m_AuthType > 0) + { + m_AuthKeys = std::make_shared >(); + if (m_AuthType == i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_DH) + ReadAuthKey (I2CP_PARAM_LEASESET_CLIENT_DH, params); + else if (m_AuthType == i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK) + ReadAuthKey (I2CP_PARAM_LEASESET_CLIENT_PSK, params); + else + { + LogPrint (eLogError, "Destination: Unexpected auth type ", m_AuthType); + m_AuthType = 0; + } + if (m_AuthKeys->size ()) + LogPrint (eLogInfo, "Destination: ", m_AuthKeys->size (), " auth keys read"); + else + { + LogPrint (eLogError, "Destination: No auth keys read for auth type ", m_AuthType); + m_AuthKeys = nullptr; + } + } + } + } + } + catch (std::exception & ex) { - auto it = params->find (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY); - if (it != params->end ()) - m_StreamingAckDelay = std::stoi(it->second); + LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what()); } } @@ -1149,7 +1183,7 @@ namespace client auto ls2 = std::make_shared (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2, m_Keys, m_EncryptionKeyType, keyLen, m_EncryptionPublicKey, tunnels, IsPublic ()); if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) // encrypt if type 5 - ls2 = std::make_shared (ls2, m_Keys); + ls2 = std::make_shared (ls2, m_Keys, m_AuthType, m_AuthKeys); leaseSet = ls2; } SetLeaseSet (leaseSet); @@ -1168,5 +1202,22 @@ namespace client LogPrint (eLogError, "Destinations: decryptor is not set"); return false; } + + void ClientDestination::ReadAuthKey (const std::string& group, const std::map * params) + { + for (auto it: *params) + if (it.first.length () >= group.length () && !it.first.compare (0, group.length (), group)) + { + auto pos = it.second.find (':'); + if (pos != std::string::npos) + { + i2p::data::AuthPublicKey pubKey; + if (pubKey.FromBase64 (it.second.substr (pos+1))) + m_AuthKeys->push_back (pubKey); + else + LogPrint (eLogError, "Destination: Unexpected auth key ", it.second.substr (pos+1)); + } + } + } } } diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index dcbe9768..148a6101 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -252,6 +252,9 @@ namespace client void ScheduleCheckForReady(ReadyPromise * p); void HandleCheckForReady(const boost::system::error_code & ecode, ReadyPromise * p); #endif + + void ReadAuthKey (const std::string& group, const std::map * params); + private: i2p::data::PrivateKeys m_Keys; @@ -267,6 +270,9 @@ namespace client boost::asio::deadline_timer m_ReadyChecker; + int m_AuthType; + std::shared_ptr > m_AuthKeys; + public: // for HTTP only diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index bd2fca75..bc50e013 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -812,7 +812,7 @@ namespace data } LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr ls, const i2p::data::PrivateKeys& keys, - LeaseSetAuthType authType, std::shared_ptr > authKeys): + int authType, std::shared_ptr > authKeys): LocalLeaseSet2 (ls->GetIdentity ()), m_InnerLeaseSet (ls) { size_t lenInnerPlaintext = ls->GetBufferLen () + 1, lenOuterPlaintext = lenInnerPlaintext + 32 + 1, @@ -821,8 +821,8 @@ namespace data uint8_t layer1Flags = 0; if (authKeys) { - if (authType == eLeaseSetAuthTypeDH) layer1Flags |= 0x01; // DH, authentication scheme 0, auth bit 1 - else if (authType == eLeaseSetAuthTypePSK) layer1Flags |= 0x03; // PSK, authentication scheme 1, auth bit 1 + if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH) layer1Flags |= 0x01; // DH, authentication scheme 0, auth bit 1 + else if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_PSK) layer1Flags |= 0x03; // PSK, authentication scheme 1, auth bit 1 if (layer1Flags) m_BufferLen += authKeys->size ()*40 + 2; // auth data len } m_Buffer = new uint8_t[m_BufferLen + 1]; @@ -905,9 +905,9 @@ namespace data LogPrint (eLogError, "LeaseSet2: couldn't extract inner layer"); } - void LocalEncryptedLeaseSet2::CreateClientAuthData (const uint8_t * subcredential, LeaseSetAuthType authType, std::shared_ptr > authKeys, const uint8_t * authCookie, uint8_t * authClients) const + void LocalEncryptedLeaseSet2::CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr > authKeys, const uint8_t * authCookie, uint8_t * authClients) const { - if (authType == eLeaseSetAuthTypeDH) + if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH) { i2p::crypto::X25519Keys ek; ek.GenerateKeys (); // esk and epk diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index 03e0e543..b9979e00 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -251,21 +251,17 @@ namespace data }; + const int ENCRYPTED_LEASESET_AUTH_TYPE_NONE = 0; + const int ENCRYPTED_LEASESET_AUTH_TYPE_DH = 1; + const int ENCRYPTED_LEASESET_AUTH_TYPE_PSK = 2; + + typedef i2p::data::Tag<32> AuthPublicKey; + class LocalEncryptedLeaseSet2: public LocalLeaseSet2 { public: - enum LeaseSetAuthType - { - eLeaseSetAuthTypeNone = 0, - eLeaseSetAuthTypeDH = 1, - eLeaseSetAuthTypePSK = 2 - }; - typedef i2p::data::Tag<32> AuthPublicKey; - - public: - - LocalEncryptedLeaseSet2 (std::shared_ptr ls, const i2p::data::PrivateKeys& keys, LeaseSetAuthType authType = eLeaseSetAuthTypeNone, std::shared_ptr > authKeys = nullptr); + LocalEncryptedLeaseSet2 (std::shared_ptr ls, const i2p::data::PrivateKeys& keys, int authType = ENCRYPTED_LEASESET_AUTH_TYPE_NONE, std::shared_ptr > authKeys = nullptr); LocalEncryptedLeaseSet2 (std::shared_ptr identity, const uint8_t * buf, size_t len); // from I2CP @@ -274,7 +270,7 @@ namespace data private: - void CreateClientAuthData (const uint8_t * subcredential, LeaseSetAuthType authType, std::shared_ptr > authKeys, const uint8_t * authCookie, uint8_t * authClients) const; + void CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr > authKeys, const uint8_t * authCookie, uint8_t * authClients) const; private: From 254d2b82b3e9613514c21eaaac97a3c39f550620 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 26 Jul 2019 14:23:21 -0400 Subject: [PATCH 11/36] fixed #1393. store streams by recvStreamID --- libi2pd/Streaming.cpp | 30 ++++++++++++++---------------- libi2pd/Streaming.h | 6 ++++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 7b1f187b..b8ce8167 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -964,7 +964,6 @@ namespace stream StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort, bool gzip): m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), - m_LastIncomingReceiveStreamID (0), m_PendingIncomingTimer (m_Owner->GetService ()) { } @@ -1013,18 +1012,17 @@ namespace stream if (packet->IsSYN () && !packet->GetSeqn ()) // new incoming stream { uint32_t receiveStreamID = packet->GetReceiveStreamID (); - if (receiveStreamID == m_LastIncomingReceiveStreamID) + auto it1 = m_IncomingStreams.find (receiveStreamID); + if (it1 != m_IncomingStreams.end ()) { // already pending LogPrint(eLogWarning, "Streaming: Incoming streaming with rSID=", receiveStreamID, " already exists"); DeletePacket (packet); // drop it, because previous should be connected return; } - auto incomingStream = CreateNewIncomingStream (); + auto incomingStream = CreateNewIncomingStream (receiveStreamID); incomingStream->HandleNextPacket (packet); // SYN auto ident = incomingStream->GetRemoteIdentity(); - - m_LastIncomingReceiveStreamID = receiveStreamID; // handle saved packets if any { @@ -1062,13 +1060,13 @@ namespace stream else // follow on packet without SYN { uint32_t receiveStreamID = packet->GetReceiveStreamID (); - for (auto& it: m_Streams) - if (it.second->GetSendStreamID () == receiveStreamID) - { - // found - it.second->HandleNextPacket (packet); - return; - } + auto it1 = m_IncomingStreams.find (receiveStreamID); + if (it1 != m_IncomingStreams.end ()) + { + // found + it1->second->HandleNextPacket (packet); + return; + } // save follow on packet auto it = m_SavedPackets.find (receiveStreamID); if (it != m_SavedPackets.end ()) @@ -1105,11 +1103,12 @@ namespace stream return s; } - std::shared_ptr StreamingDestination::CreateNewIncomingStream () + std::shared_ptr StreamingDestination::CreateNewIncomingStream (uint32_t receiveStreamID) { auto s = std::make_shared (m_Owner->GetService (), *this); std::unique_lock l(m_StreamsMutex); m_Streams[s->GetRecvStreamID ()] = s; + m_IncomingStreams[receiveStreamID] = s; return s; } @@ -1118,9 +1117,8 @@ namespace stream if (stream) { std::unique_lock l(m_StreamsMutex); - auto it = m_Streams.find (stream->GetRecvStreamID ()); - if (it != m_Streams.end ()) - m_Streams.erase (it); + m_Streams.erase (stream->GetRecvStreamID ()); + m_IncomingStreams.erase (stream->GetSendStreamID ()); } } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index ba52464f..49962507 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -269,8 +269,10 @@ namespace stream void AcceptOnceAcceptor (std::shared_ptr stream, Acceptor acceptor, Acceptor prev); + private: + void HandleNextPacket (Packet * packet); - std::shared_ptr CreateNewIncomingStream (); + std::shared_ptr CreateNewIncomingStream (uint32_t receiveStreamID); void HandlePendingIncomingTimer (const boost::system::error_code& ecode); private: @@ -280,8 +282,8 @@ namespace stream bool m_Gzip; // gzip compression of data messages std::mutex m_StreamsMutex; std::map > m_Streams; // sendStreamID->stream + std::map > m_IncomingStreams; // receiveStreamID->stream Acceptor m_Acceptor; - uint32_t m_LastIncomingReceiveStreamID; std::list > m_PendingIncomingStreams; boost::asio::deadline_timer m_PendingIncomingTimer; std::map > m_SavedPackets; // receiveStreamID->packets, arrived before SYN From a6558a61a7d36809a0943713e0ed07ad26c3cfcd Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 2 Aug 2019 12:54:24 -0400 Subject: [PATCH 12/36] Recognize RedDSA_SHA512_Ed25519 signature type --- libi2pd_client/SAM.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 224d84e8..dda566c9 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -1011,7 +1011,8 @@ namespace client {"ECDSA_SHA256_P521", i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521}, {"EdDSA_SHA512_Ed25519", i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519}, {"GOST_GOSTR3411256_GOSTR3410CRYPTOPROA", i2p::data::SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256}, - {"GOST_GOSTR3411512_GOSTR3410TC26A512", i2p::data::SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512} + {"GOST_GOSTR3411512_GOSTR3410TC26A512", i2p::data::SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512}, + {"RedDSA_SHA512_Ed25519", i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519}, } { } From db107602bdc3913efdfd14b409e62ac0468fcf8c Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 2 Aug 2019 13:48:39 -0400 Subject: [PATCH 13/36] handle messages with \r\n --- libi2pd_client/SAM.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index dda566c9..766a1940 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -239,6 +239,7 @@ namespace client char * eol = (char *)memchr (m_Buffer, '\n', bytes_transferred); if (eol) { + if (eol > m_Buffer && eol[-1] == '\r') eol--; *eol = 0; char * separator = strchr (m_Buffer, ' '); if (separator) From e6a09b49c936180e6bd7ad9add6be658a21eb02e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 7 Aug 2019 15:43:03 -0400 Subject: [PATCH 14/36] published encrypted flag --- libi2pd/Destination.cpp | 5 +++-- libi2pd/LeaseSet.cpp | 13 ++++++++++++- libi2pd/LeaseSet.h | 8 ++++++-- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 9355e75d..34ff374f 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1180,9 +1180,10 @@ namespace client { // standard LS2 (type 3) first auto keyLen = m_Decryptor ? m_Decryptor->GetPublicKeyLen () : 256; + bool isPublishedEncrypted = GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; auto ls2 = std::make_shared (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2, - m_Keys, m_EncryptionKeyType, keyLen, m_EncryptionPublicKey, tunnels, IsPublic ()); - if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) // encrypt if type 5 + m_Keys, m_EncryptionKeyType, keyLen, m_EncryptionPublicKey, tunnels, IsPublic (), isPublishedEncrypted); + if (isPublishedEncrypted) // encrypt if type 5 ls2 = std::make_shared (ls2, m_Keys, m_AuthType, m_AuthKeys); leaseSet = ls2; } diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index bc50e013..8cbb3341 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -303,6 +303,11 @@ namespace data } } if (flags & LEASESET2_FLAG_UNPUBLISHED_LEASESET) m_IsPublic = false; + if (flags & LEASESET2_FLAG_PUBLISHED_ENCRYPTED) + { + m_IsPublishedEncrypted = true; + m_IsPublic = true; + } // type specific part size_t s = 0; switch (m_StoreType) @@ -742,7 +747,8 @@ namespace data LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey, - std::vector > tunnels, bool isPublic): + std::vector > tunnels, + bool isPublic, bool isPublishedEncrypted): LocalLeaseSet (keys.GetPublic (), nullptr, 0) { auto identity = keys.GetPublic (); @@ -757,6 +763,11 @@ namespace data flags |= LEASESET2_FLAG_OFFLINE_KEYS; m_BufferLen += keys.GetOfflineSignature ().size (); } + if (isPublishedEncrypted) + { + flags |= LEASESET2_FLAG_PUBLISHED_ENCRYPTED; + isPublic = true; + } if (!isPublic) flags |= LEASESET2_FLAG_UNPUBLISHED_LEASESET; m_Buffer = new uint8_t[m_BufferLen + 1]; diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index b9979e00..2199ac32 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -82,6 +82,7 @@ namespace data virtual uint8_t GetOrigStoreType () const { return NETDB_STORE_TYPE_LEASESET; }; virtual uint32_t GetPublishedTimestamp () const { return 0; }; // should be set for LeaseSet2 only virtual std::shared_ptr GetTransientVerifier () const { return nullptr; }; + virtual bool IsPublishedEncrypted () const { return false; }; // implements RoutingDestination std::shared_ptr GetIdentity () const { return m_Identity; }; @@ -130,6 +131,7 @@ namespace data const uint16_t LEASESET2_FLAG_OFFLINE_KEYS = 0x0001; const uint16_t LEASESET2_FLAG_UNPUBLISHED_LEASESET = 0x0002; + const uint16_t LEASESET2_FLAG_PUBLISHED_ENCRYPTED = 0x0004; class LeaseSet2: public LeaseSet { @@ -141,6 +143,7 @@ namespace data uint8_t GetOrigStoreType () const { return m_OrigStoreType; }; uint32_t GetPublishedTimestamp () const { 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); @@ -164,7 +167,7 @@ namespace data uint8_t m_StoreType, m_OrigStoreType; uint32_t m_PublishedTimestamp = 0; - bool m_IsPublic = true; + bool m_IsPublic = true, m_IsPublishedEncrypted = false; std::shared_ptr m_TransientVerifier; std::shared_ptr m_Encryptor; // for standardLS2 }; @@ -230,7 +233,8 @@ namespace data LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey, - std::vector > tunnels, bool isPublic); + std::vector > tunnels, + bool isPublic, bool isPublishedEncrypted = false); LocalLeaseSet2 (uint8_t storeType, std::shared_ptr identity, const uint8_t * buf, size_t len); // from I2CP virtual ~LocalLeaseSet2 () { delete[] m_Buffer; }; From 3872c2a3f55f634971b51f6a0edbb7002e746488 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 7 Aug 2019 16:18:00 -0400 Subject: [PATCH 15/36] use published encrypted instead orig type --- libi2pd/LeaseSet.cpp | 4 ++-- libi2pd/LeaseSet.h | 4 +--- libi2pd/Streaming.cpp | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 8cbb3341..008a4594 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -252,7 +252,7 @@ namespace data } LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases): - LeaseSet (storeLeases), m_StoreType (storeType), m_OrigStoreType (storeType) + LeaseSet (storeLeases), m_StoreType (storeType) { SetBuffer (buf, len); if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) @@ -262,7 +262,7 @@ namespace data } LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret): - LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_OrigStoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) + LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) { ReadFromBufferEncrypted (buf, len, key, secret); } diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index 2199ac32..935aca37 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -79,7 +79,6 @@ namespace data bool operator== (const LeaseSet& other) const { return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); }; virtual uint8_t GetStoreType () const { return NETDB_STORE_TYPE_LEASESET; }; - virtual uint8_t GetOrigStoreType () const { return NETDB_STORE_TYPE_LEASESET; }; virtual uint32_t GetPublishedTimestamp () const { return 0; }; // should be set for LeaseSet2 only virtual std::shared_ptr GetTransientVerifier () const { return nullptr; }; virtual bool IsPublishedEncrypted () const { return false; }; @@ -140,7 +139,6 @@ namespace data LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true); LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret = nullptr); // store type 5, called from local netdb only uint8_t GetStoreType () const { return m_StoreType; }; - uint8_t GetOrigStoreType () const { return m_OrigStoreType; }; uint32_t GetPublishedTimestamp () const { return m_PublishedTimestamp; }; bool IsPublic () const { return m_IsPublic; }; bool IsPublishedEncrypted () const { return m_IsPublishedEncrypted; }; @@ -165,7 +163,7 @@ namespace data private: - uint8_t m_StoreType, m_OrigStoreType; + uint8_t m_StoreType; uint32_t m_PublishedTimestamp = 0; bool m_IsPublic = true, m_IsPublishedEncrypted = false; std::shared_ptr m_TransientVerifier; diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index b8ce8167..c8ccdcdb 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -918,7 +918,7 @@ namespace stream { expired = false; // time to request - if (m_RemoteLeaseSet->GetOrigStoreType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) + if (m_RemoteLeaseSet->IsPublishedEncrypted ()) m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet ( std::make_shared(m_RemoteIdentity)); else From ad9c11cd9242272c1629bf494bae6bfe89902c78 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 10 Aug 2019 22:16:26 -0400 Subject: [PATCH 16/36] correct parsing of addreses containing # --- libi2pd_client/AddressBook.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index 75d95da1..14ed89a7 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -422,9 +422,9 @@ namespace client std::string name = s.substr(0, pos++); std::string addr = s.substr(pos); - size_t pos = s.find('#'); + size_t pos = addr.find('#'); if (pos != std::string::npos) - addr = addr.substr(pos); // remove comments + addr = addr.substr(0, pos); // remove comments auto ident = std::make_shared (); if (!ident->FromBase64(addr)) { From c8cbf425ac5d52304ce5f268639c65e4def7ee30 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 13 Aug 2019 14:55:18 -0400 Subject: [PATCH 17/36] check and send netid for NTCP2 and SSU --- libi2pd/NTCP2.cpp | 6 ++++++ libi2pd/SSUSession.cpp | 10 +++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 368f1b3e..6d235abe 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -161,6 +161,7 @@ namespace transport // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); + options[0] = i2p::context.GetNetID (); // network ID options[1] = 2; // ver htobe16buf (options + 2, paddingLength); // padLen // m3p2Len @@ -248,6 +249,11 @@ namespace transport if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_H, 32, m_K, nonce, options, 16, false)) // decrypt { // options + if (options[0] && options[0] != i2p::context.GetNetID ()) + { + LogPrint (eLogWarning, "NTCP2: SessionRequest networkID ", (int)options[0], " mismatch. Expected ", i2p::context.GetNetID ()); + return false; + } if (options[1] == 2) // ver is always 2 { paddingLen = bufbe16toh (options + 2); diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index a7497fd1..88dbcf04 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -1,4 +1,5 @@ #include +#include "version.h" #include "Crypto.h" #include "Log.h" #include "Timestamp.h" @@ -729,7 +730,8 @@ namespace transport encryption.Encrypt (encrypted, encryptedLen, encrypted); // assume actual buffer size is 18 (16 + 2) bytes more memcpy (buf + len, iv, 16); - htobe16buf (buf + len + 16, encryptedLen); + uint16_t netid = i2p::context.GetNetID (); + htobe16buf (buf + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8)); i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, header->mac); } @@ -750,7 +752,8 @@ namespace transport m_SessionKeyEncryption.Encrypt (encrypted, encryptedLen, encrypted); // assume actual buffer size is 18 (16 + 2) bytes more memcpy (buf + len, header->iv, 16); - htobe16buf (buf + len + 16, encryptedLen); + uint16_t netid = i2p::context.GetNetID (); + htobe16buf (buf + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8)); i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac); } @@ -799,7 +802,8 @@ namespace transport uint16_t encryptedLen = len - (encrypted - buf); // assume actual buffer size is 18 (16 + 2) bytes more memcpy (buf + len, header->iv, 16); - htobe16buf (buf + len + 16, encryptedLen); + uint16_t netid = i2p::context.GetNetID (); + htobe16buf (buf + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8)); uint8_t digest[16]; i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, digest); return !memcmp (header->mac, digest, 16); From 099adab9ed64f3b428ad30671942c0cb7b26741a Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 16 Aug 2019 21:45:44 +0300 Subject: [PATCH 18/36] Update README.md update head badges links, add snapcraft badge --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 540e3bed..b5fb8f7e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -![GitHub release](https://img.shields.io/github/release/PurpleI2P/i2pd.svg?label=latest%20release) -![GitHub](https://img.shields.io/github/license/PurpleI2P/i2pd.svg) +[![GitHub release](https://img.shields.io/github/release/PurpleI2P/i2pd.svg?label=latest%20release)](https://github.com/PurpleI2P/i2pd/releases/latest) +[![Snapcraft release](https://snapcraft.io/i2pd/badge.svg)](https://snapcraft.io/i2pd) +[![License](https://img.shields.io/github/license/PurpleI2P/i2pd.svg)](https://github.com/PurpleI2P/i2pd/blob/openssl/LICENSE) i2pd ==== @@ -66,6 +67,7 @@ Build instructions: * Mac OS X - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd) * CentOS / Fedora / Mageia - [![Build Status](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/) * Docker image - [![Build Status](https://dockerbuildbadges.quelltext.eu/status.svg?organization=meeh&repository=i2pd)](https://hub.docker.com/r/meeh/i2pd/builds/) +* Snap - [![Snap Status](https://build.snapcraft.io/badge/PurpleI2P/i2pd-snap.svg)](https://build.snapcraft.io/user/PurpleI2P/i2pd-snap) * FreeBSD * Android * iOS From 9bbce5dba6980cb87859e1128406f66c8f8bddc8 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 21 Aug 2019 20:26:19 -0400 Subject: [PATCH 19/36] fixed typo --- libi2pd_client/ClientContext.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index e10c1e07..d14491b2 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -410,7 +410,7 @@ namespace client auto authType = GetI2CPOption(section, I2CP_PARAM_LEASESET_AUTH_TYPE, 0); if (authType != "0") // auth is set { - options[I2CP_PARAM_LEASESET_TYPE] = authType; + options[I2CP_PARAM_LEASESET_AUTH_TYPE] = authType; if (authType == "1") // DH ReadI2CPOptionsGroup (section, I2CP_PARAM_LEASESET_CLIENT_DH, options); else if (authType == "2") // PSK @@ -629,8 +629,8 @@ namespace client // I2CP std::map options; - ReadI2CPOptions (section, options); - + ReadI2CPOptions (section, options); + std::shared_ptr localDestination = nullptr; i2p::data::PrivateKeys k; if(!LoadPrivateKeys (k, keys, sigType, cryptoType)) From 8f82d563c1115a819ca982b428b1dece029a5a69 Mon Sep 17 00:00:00 2001 From: kote Date: Thu, 22 Aug 2019 10:00:50 +0800 Subject: [PATCH 20/36] various Android stuff. Fixed #1400 --- android/.gitignore | 3 +- android/AndroidManifest.xml | 1 + android/build.gradle | 13 +- android/gradle.properties | 2 + .../gradle/wrapper/gradle-wrapper.properties | 4 +- android/res/values/strings.xml | 5 + .../org/purplei2p/i2pd/ForegroundService.java | 22 +- .../src/org/purplei2p/i2pd/I2PDActivity.java | 334 +++++++++++------- 8 files changed, 245 insertions(+), 139 deletions(-) diff --git a/android/.gitignore b/android/.gitignore index 297d122f..c1f63742 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -12,5 +12,4 @@ local.properties build.sh android.iml build - - +*.iml diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 2ae14711..757b35bb 100755 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -9,6 +9,7 @@ + remaining Prompt SD card write permission denied, you need to allow this to continue + Battery optimizations enabled + Your device is doing some heavy battery optimizations on I2PD that might lead to daemon closing with no other reason.\nIt is recommended to disable those battery optimizations. + Your device is doing some heavy battery optimizations on I2PD that might lead to daemon closing with no other reason.\n\nYou will now be asked to disable those. + Next + Your device does not support opting out of battery optimizations diff --git a/android/src/org/purplei2p/i2pd/ForegroundService.java b/android/src/org/purplei2p/i2pd/ForegroundService.java index 5c10e138..c1b1cc26 100644 --- a/android/src/org/purplei2p/i2pd/ForegroundService.java +++ b/android/src/org/purplei2p/i2pd/ForegroundService.java @@ -1,6 +1,5 @@ package org.purplei2p.i2pd; -import android.annotation.TargetApi; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -11,10 +10,9 @@ import android.content.Intent; import android.os.Binder; import android.os.Build; import android.os.IBinder; -import android.support.annotation.RequiresApi; -import android.support.v4.app.NotificationCompat; +import androidx.annotation.RequiresApi; +import androidx.core.app.NotificationCompat; import android.util.Log; -import android.widget.Toast; public class ForegroundService extends Service { private static final String TAG="FgService"; @@ -112,14 +110,15 @@ public class ForegroundService extends Service { // If earlier version channel ID is not used // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context) - String channelId = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) ? createNotificationChannel() : ""; + String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : ""; // Set the info for the views that show in the notification panel. - Notification notification = new NotificationCompat.Builder(this, channelId) + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId) .setOngoing(true) - .setSmallIcon(R.drawable.itoopie_notification_icon) // the status icon - .setPriority(Notification.PRIORITY_DEFAULT) - .setCategory(Notification.CATEGORY_SERVICE) + .setSmallIcon(R.drawable.itoopie_notification_icon); // the status icon + if(Build.VERSION.SDK_INT >= 16) builder = builder.setPriority(Notification.PRIORITY_DEFAULT); + if(Build.VERSION.SDK_INT >= 21) builder = builder.setCategory(Notification.CATEGORY_SERVICE); + Notification notification = builder .setTicker(text) // the status text .setWhen(System.currentTimeMillis()) // the time stamp .setContentTitle(getText(R.string.app_name)) // the label of the entry @@ -141,9 +140,10 @@ public class ForegroundService extends Service { //chan.setLightColor(Color.PURPLE); chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); NotificationManager service = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); - service.createNotificationChannel(chan); + if(service!=null)service.createNotificationChannel(chan); + else Log.e(TAG, "error: NOTIFICATION_SERVICE is null"); return channelId; } - private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); + private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); } diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index b5f85c5b..d97df833 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -14,24 +14,34 @@ import java.util.Timer; import java.util.TimerTask; import android.Manifest; +import android.annotation.SuppressLint; import android.app.Activity; +import android.app.AlertDialog; +import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.SharedPreferences; import android.content.res.AssetManager; import android.content.pm.PackageManager; +import android.net.Uri; import android.os.Bundle; import android.os.Build; import android.os.Environment; import android.os.IBinder; +import android.os.PowerManager; +import android.preference.PreferenceManager; +import android.provider.Settings; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; import android.widget.Toast; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; + +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; // For future package update checking import org.purplei2p.i2pd.BuildConfig; @@ -40,6 +50,7 @@ public class I2PDActivity extends Activity { private static final String TAG = "i2pdActvt"; private static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 1; public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; + public static final String PACKAGE_URI_SCHEME = "package:"; private TextView textView; private boolean assetsCopied; @@ -53,28 +64,22 @@ public class I2PDActivity extends Activity { public void daemonStateUpdate() { processAssets(); - runOnUiThread(new Runnable(){ - - @Override - public void run() { - try { - if(textView==null) return; - Throwable tr = daemon.getLastThrowable(); - if(tr!=null) { - textView.setText(throwableToString(tr)); - return; - } - DaemonSingleton.State state = daemon.getState(); - textView.setText( - String.valueOf(getText(state.getStatusStringResourceId()))+ - (DaemonSingleton.State.startFailed.equals(state) ? ": "+daemon.getDaemonStartResult() : "")+ - (DaemonSingleton.State.gracefulShutdownInProgress.equals(state) ? ": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining) : "") - ); - } catch (Throwable tr) { - Log.e(TAG,"error ignored",tr); - } - } - }); + runOnUiThread(() -> { + try { + if(textView==null) return; + Throwable tr = daemon.getLastThrowable(); + if(tr!=null) { + textView.setText(throwableToString(tr)); + return; + } + DaemonSingleton.State state = daemon.getState(); + String startResultStr = DaemonSingleton.State.startFailed.equals(state) ? String.format(": %s", daemon.getDaemonStartResult()) : ""; + String graceStr = DaemonSingleton.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", formatGraceTimeRemaining(), getText(R.string.remaining)) : ""; + textView.setText(String.format("%s%s%s", getText(state.getStatusStringResourceId()), startResultStr, graceStr)); + } catch (Throwable tr) { + Log.e(TAG,"error ignored",tr); + } + }); } }; private static volatile long graceStartedMillis; @@ -92,6 +97,7 @@ public class I2PDActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { + Log.i(TAG, "onCreate"); super.onCreate(savedInstanceState); textView = new TextView(this); @@ -121,6 +127,8 @@ public class I2PDActivity extends Activity { } rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis); } + + openBatteryOptimizationDialogIfNeeded(); } @Override @@ -137,21 +145,17 @@ public class I2PDActivity extends Activity { } @Override - public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - switch (requestCode) - { - case MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE: - { - if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) - Log.e(TAG, "Memory permission granted"); - else - Log.e(TAG, "Memory permission declined"); - // TODO: terminate - return; - } - default: ; - } + if (requestCode == MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) + Log.e(TAG, "WR_EXT_STORAGE perm granted"); + else { + Log.e(TAG, "WR_EXT_STORAGE perm declined, stopping i2pd"); + i2pdStop(); + //TODO must work w/o this perm, ask orignal + } + } } private static void cancelGracefulStop() { @@ -229,7 +233,7 @@ public class I2PDActivity extends Activity { } @Override - public boolean onOptionsItemSelected(MenuItem item) { + public boolean onOptionsItemSelected(@NonNull MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. @@ -258,19 +262,15 @@ public class I2PDActivity extends Activity { private void i2pdStop() { cancelGracefulStop(); - new Thread(new Runnable(){ - - @Override - public void run() { - Log.d(TAG, "stopping"); - try{ - daemon.stopDaemon(); - }catch (Throwable tr) { - Log.e(TAG, "", tr); - } - } - - },"stop").start(); + new Thread(() -> { + Log.d(TAG, "stopping"); + try { + daemon.stopDaemon(); + } catch (Throwable tr) { + Log.e(TAG, "", tr); + } + quit(); //TODO make menu items for starting i2pd. On my Android, I need to reboot the OS to restart i2pd. + },"stop").start(); } private static volatile Timer gracefulQuitTimer; @@ -288,55 +288,44 @@ public class I2PDActivity extends Activity { } Toast.makeText(this, R.string.graceful_stop_is_in_progress, Toast.LENGTH_SHORT).show(); - new Thread(new Runnable(){ - - @Override - public void run() { - try { - Log.d(TAG, "grac stopping"); - if(daemon.isStartedOkay()) { - daemon.stopAcceptingTunnels(); - long gracefulStopAtMillis; - synchronized (graceStartedMillis_LOCK) { - graceStartedMillis = System.currentTimeMillis(); - gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; - } - rescheduleGraceStop(null,gracefulStopAtMillis); - } else { - i2pdStop(); - } - } catch(Throwable tr) { - Log.e(TAG,"",tr); - } - } - - },"gracInit").start(); + new Thread(() -> { + try { + Log.d(TAG, "grac stopping"); + if(daemon.isStartedOkay()) { + daemon.stopAcceptingTunnels(); + long gracefulStopAtMillis; + synchronized (graceStartedMillis_LOCK) { + graceStartedMillis = System.currentTimeMillis(); + gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; + } + rescheduleGraceStop(null,gracefulStopAtMillis); + } else { + i2pdStop(); + } + } catch(Throwable tr) { + Log.e(TAG,"",tr); + } + },"gracInit").start(); } private void i2pdCancelGracefulStop() { cancelGracefulStop(); Toast.makeText(this, R.string.startedOkay, Toast.LENGTH_SHORT).show(); - new Thread(new Runnable() - { - @Override - public void run() - { - try - { - Log.d(TAG, "grac stopping cancel"); - if(daemon.isStartedOkay()) - daemon.startAcceptingTunnels(); - else - i2pdStop(); - } - catch(Throwable tr) - { - Log.e(TAG,"",tr); - } - } - - },"gracCancel").start(); + new Thread(() -> { + try + { + Log.d(TAG, "grac stopping cancel"); + if(daemon.isStartedOkay()) + daemon.startAcceptingTunnels(); + else + i2pdStop(); + } + catch(Throwable tr) + { + Log.e(TAG,"",tr); + } + },"gracCancel").start(); } private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) { @@ -393,7 +382,7 @@ public class I2PDActivity extends Activity { // Make the directory. File dir = new File(i2pdpath, path); - dir.mkdirs(); + Log.d(TAG, "dir.mkdirs() returned "+dir.mkdirs()); // Recurse on the contents. for (String entry : contents) { @@ -431,45 +420,69 @@ public class I2PDActivity extends Activity { private void deleteRecursive(File fileOrDirectory) { if (fileOrDirectory.isDirectory()) { - for (File child : fileOrDirectory.listFiles()) { - deleteRecursive(child); + File[] files = fileOrDirectory.listFiles(); + if(files!=null) { + for (File child : files) { + deleteRecursive(child); + } } } - fileOrDirectory.delete(); + boolean deleteResult = fileOrDirectory.delete(); + if(!deleteResult)Log.e(TAG, "fileOrDirectory.delete() returned "+deleteResult+", absolute path='"+fileOrDirectory.getAbsolutePath()+"'"); } private void processAssets() { if (!assetsCopied) try { assetsCopied = true; // prevent from running on every state update - File holderfile = new File(i2pdpath, "assets.ready"); + File holderFile = new File(i2pdpath, "assets.ready"); String versionName = BuildConfig.VERSION_NAME; // here will be app version, like 2.XX.XX StringBuilder text = new StringBuilder(); - if (holderfile.exists()) try { // if holder file exists, read assets version string - BufferedReader br = new BufferedReader(new FileReader(holderfile)); - String line; + if (holderFile.exists()) { + try { // if holder file exists, read assets version string + FileReader fileReader = new FileReader(holderFile); - while ((line = br.readLine()) != null) { - text.append(line); - } - br.close(); - } - catch (IOException e) { - Log.e(TAG, "", e); - } + try { + BufferedReader br = new BufferedReader(fileReader); + + try { + String line; + + while ((line = br.readLine()) != null) { + text.append(line); + } + }finally { + try{ + br.close(); + } catch (IOException e) { + Log.e(TAG, "", e); + } + } + } finally { + try{ + fileReader.close(); + } catch (IOException e) { + Log.e(TAG, "", e); + } + } + } catch (IOException e) { + Log.e(TAG, "", e); + } + } // if version differs from current app version or null, try to delete certificates folder if (!text.toString().contains(versionName)) try { - holderfile.delete(); - File certpath = new File(i2pdpath, "certificates"); - deleteRecursive(certpath); + boolean deleteResult = holderFile.delete(); + if(!deleteResult)Log.e(TAG, "holderFile.delete() returned "+deleteResult+", absolute path='"+holderFile.getAbsolutePath()+"'"); + File certPath = new File(i2pdpath, "certificates"); + deleteRecursive(certPath); } catch (Throwable tr) { Log.e(TAG, "", tr); } - // copy assets. If processed file exists, it won't be overwrited + // copy assets. If processed file exists, it won't be overwritten copyAsset("addressbook"); copyAsset("certificates"); copyAsset("tunnels.d"); @@ -478,14 +491,95 @@ public class I2PDActivity extends Activity { copyAsset("tunnels.conf"); // update holder file about successful copying - FileWriter writer = new FileWriter(holderfile); - writer.append(versionName); - writer.flush(); - writer.close(); + FileWriter writer = new FileWriter(holderFile); + try { + writer.append(versionName); + } finally { + try{ + writer.close(); + }catch (IOException e){ + Log.e(TAG,"on writer close", e); + } + } } catch (Throwable tr) { - Log.e(TAG,"copy assets",tr); + Log.e(TAG,"on assets copying", tr); } } + + @SuppressLint("BatteryLife") + private void openBatteryOptimizationDialogIfNeeded() { + boolean questionEnabled = getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true); + Log.i(TAG,"BATT_OPTIM_questionEnabled=="+questionEnabled); + if (!isKnownIgnoringBatteryOptimizations() + && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M + && questionEnabled) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.battery_optimizations_enabled); + builder.setMessage(R.string.battery_optimizations_enabled_dialog); + builder.setPositiveButton(R.string.next, (dialog, which) -> { + try { + startActivity(new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Uri.parse(PACKAGE_URI_SCHEME + getPackageName()))); + } catch (ActivityNotFoundException e) { + Log.e(TAG,"BATT_OPTIM_ActvtNotFound", e); + Toast.makeText(this, R.string.device_does_not_support_disabling_battery_optimizations, Toast.LENGTH_SHORT).show(); + } + }); + builder.setOnDismissListener(dialog -> setNeverAskForBatteryOptimizationsAgain()); + final AlertDialog dialog = builder.create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + } + } + + private void setNeverAskForBatteryOptimizationsAgain() { + getPreferences().edit().putBoolean(getBatteryOptimizationPreferenceKey(), false).apply(); + } + + protected boolean isKnownIgnoringBatteryOptimizations() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + final PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); + if (pm == null) { + Log.i(TAG, "BATT_OPTIM: POWER_SERVICE==null"); + return false; + } + boolean ignoring = pm.isIgnoringBatteryOptimizations(getPackageName()); + Log.i(TAG, "BATT_OPTIM: ignoring==" + ignoring); + return ignoring; + } else { + Log.i(TAG, "BATT_OPTIM: old sdk version=="+Build.VERSION.SDK_INT); + return false; + } + } + + protected SharedPreferences getPreferences() { + return PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + } + + private String getBatteryOptimizationPreferenceKey() { + @SuppressLint("HardwareIds") String device = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID); + return "show_battery_optimization" + (device == null ? "" : device); + } + + private void quit() { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + finishAndRemoveTask(); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + finishAffinity(); + } else { + //moveTaskToBack(true); + finish(); + } + }catch (Throwable tr) { + Log.e(TAG, "", tr); + } + try{ + daemon.stopDaemon(); + }catch (Throwable tr) { + Log.e(TAG, "", tr); + } + System.exit(0); + } } From 488c2f6d05993ecc676996bfe113a3fe59c6444b Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 22 Aug 2019 09:45:49 -0400 Subject: [PATCH 21/36] bump SDK version --- android/project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/project.properties b/android/project.properties index 919ca9c3..82181932 100644 --- a/android/project.properties +++ b/android/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-28 +target=android-29 From fe45d431d78a3787239227516f8d9caa146decd8 Mon Sep 17 00:00:00 2001 From: Grigory Kotov Date: Fri, 23 Aug 2019 15:40:17 +0300 Subject: [PATCH 22/36] fix dockerfile: remove unmet dependencies --- contrib/docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/docker/Dockerfile b/contrib/docker/Dockerfile index e0c4d26e..322261b8 100644 --- a/contrib/docker/Dockerfile +++ b/contrib/docker/Dockerfile @@ -36,8 +36,8 @@ RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool zlib && cd /usr/local/bin \ && strip i2pd \ && rm -fr /tmp/build && apk --no-cache --purge del build-dependendencies build-base fortify-headers boost-dev zlib-dev openssl-dev \ - boost-python3 python3 gdbm boost-unit_test_framework boost-python linux-headers boost-prg_exec_monitor \ - boost-serialization boost-signals boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre \ + boost-python3 python3 gdbm boost-unit_test_framework linux-headers boost-prg_exec_monitor \ + boost-serialization boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre \ libtool g++ gcc pkgconfig # 2. Adding required libraries to run i2pd to ensure it will run. From 351c89980746e509fedb49595b61bce3387eb4dd Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 23 Aug 2019 10:00:49 -0400 Subject: [PATCH 23/36] cleanup incoming streams on stop --- libi2pd/Streaming.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index c8ccdcdb..4f943912 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -990,6 +990,7 @@ namespace stream { std::unique_lock l(m_StreamsMutex); m_Streams.clear (); + m_IncomingStreams.clear (); } } From 6e4f18543dd48b5723c775ef5b9930fc260dab06 Mon Sep 17 00:00:00 2001 From: kote Date: Thu, 22 Aug 2019 22:09:22 +0800 Subject: [PATCH 24/36] added *.local to android/.gitignore --- android/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/android/.gitignore b/android/.gitignore index c1f63742..666c6694 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -13,3 +13,4 @@ build.sh android.iml build *.iml +*.local From 80f632c19a8c80e9b2fb8c62b90952ef14f7d5c9 Mon Sep 17 00:00:00 2001 From: kote Date: Sat, 24 Aug 2019 17:50:30 +0800 Subject: [PATCH 25/36] show battery optimiz. menu item added; translated all battery stuff into Russian --- android/res/menu/options_main.xml | 25 +++++++++++------- android/res/values-ru/strings.xml | 7 +++++ android/res/values/strings.xml | 10 ++++--- .../src/org/purplei2p/i2pd/I2PDActivity.java | 26 +++++++++++++++++-- 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/android/res/menu/options_main.xml b/android/res/menu/options_main.xml index aef67c51..089c2700 100644 --- a/android/res/menu/options_main.xml +++ b/android/res/menu/options_main.xml @@ -3,14 +3,19 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" tools:context=".I2PDActivity"> - - + + + + + + + diff --git a/android/res/values-ru/strings.xml b/android/res/values-ru/strings.xml index d5dc58e8..318e2180 100755 --- a/android/res/values-ru/strings.xml +++ b/android/res/values-ru/strings.xml @@ -17,4 +17,11 @@ осталось Запрос Права для записи на SD карту отклонены, вам необходимо предоставить их для продолжения + Оптимизации аккумулятора + Оптимизации аккумулятора включены + Ваша версия Андроид не поддерживает отключение оптимизаций аккумулятора + Ваша операционная система осуществляет оптимизации расхода аккумулятора, которые могут приводить к выгрузке I2PD из памяти и прекращению его работы с целью сэкономить заряд аккумулятора.\nРекомендуется отключить эти оптимизации. + Ваша операционная система осуществляет оптимизации расхода аккумулятора, которые могут приводить к выгрузке I2PD из памяти и прекращению его работы с целью сэкономить заряд аккумулятора.\n\nВам сейчас будет предложено разрешить отключение этих оптимизаций. + Продолжить + Ваша версия Андроид не поддерживает показ диалога об оптимизациях аккумулятора для приложений. diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml index 430663d1..43065b77 100755 --- a/android/res/values/strings.xml +++ b/android/res/values/strings.xml @@ -18,8 +18,10 @@ Prompt SD card write permission denied, you need to allow this to continue Battery optimizations enabled - Your device is doing some heavy battery optimizations on I2PD that might lead to daemon closing with no other reason.\nIt is recommended to disable those battery optimizations. - Your device is doing some heavy battery optimizations on I2PD that might lead to daemon closing with no other reason.\n\nYou will now be asked to disable those. - Next - Your device does not support opting out of battery optimizations + Your Android is doing some heavy battery optimizations on I2PD that might lead to daemon closing with no other reason.\nIt is recommended to allow disabling those battery optimizations. + Your Android is doing some heavy battery optimizations on I2PD that might lead to daemon closing with no other reason.\n\nYou will now be asked to allow to disable those. + Continue + Your Android version does not support opting out of battery optimizations + Battery Optimizations + Your Android OS version does not support showing the dialog for battery optimizations for applications. diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index d97df833..13db09fc 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -46,6 +46,8 @@ import androidx.core.content.ContextCompat; // For future package update checking import org.purplei2p.i2pd.BuildConfig; +import static android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS; + public class I2PDActivity extends Activity { private static final String TAG = "i2pdActvt"; private static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 1; @@ -229,9 +231,14 @@ public class I2PDActivity extends Activity { public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.options_main, menu); + menu.findItem(R.id.action_battery_otimizations).setEnabled(isBatteryOptimizationsOpenOsDialogApiAvailable()); return true; } + private boolean isBatteryOptimizationsOpenOsDialogApiAvailable() { + return android.os.Build.VERSION.SDK_INT >= 23; + } + @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { // Handle action bar item clicks here. The action bar will @@ -254,12 +261,26 @@ public class I2PDActivity extends Activity { item.setTitle(R.string.action_cancel_graceful_stop); i2pdGracefulStop(); } - return true; + return true; + case R.id.action_battery_otimizations: + onActionBatteryOptimizations(); + return true; } return super.onOptionsItemSelected(item); } + private void onActionBatteryOptimizations() { + if (isBatteryOptimizationsOpenOsDialogApiAvailable()) { + try { + startActivity(new Intent(ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)); + } catch (ActivityNotFoundException e) { + Log.e(TAG,"BATT_OPTIM_DIALOG_ActvtNotFound", e); + Toast.makeText(this, R.string.os_version_does_not_support_battery_optimizations_show_os_dialog_api, Toast.LENGTH_SHORT).show(); + } + } + } + private void i2pdStop() { cancelGracefulStop(); new Thread(() -> { @@ -389,6 +410,7 @@ public class I2PDActivity extends Activity { copyAsset(path + "/" + entry); } } catch (IOException e) { + Log.e(TAG,"ex ignored", e); copyFileAsset(path); } } @@ -518,7 +540,7 @@ public class I2PDActivity extends Activity { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.battery_optimizations_enabled); builder.setMessage(R.string.battery_optimizations_enabled_dialog); - builder.setPositiveButton(R.string.next, (dialog, which) -> { + builder.setPositiveButton(R.string.continue_str, (dialog, which) -> { try { startActivity(new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Uri.parse(PACKAGE_URI_SCHEME + getPackageName()))); } catch (ActivityNotFoundException e) { From 5eab5f2437009029c24181fc855f4e5ea4e33599 Mon Sep 17 00:00:00 2001 From: kote Date: Sat, 24 Aug 2019 18:00:11 +0800 Subject: [PATCH 26/36] show battery optimiz. menu item now hidden if not supported by os --- android/src/org/purplei2p/i2pd/I2PDActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 13db09fc..ed0ae908 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -231,7 +231,7 @@ public class I2PDActivity extends Activity { public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.options_main, menu); - menu.findItem(R.id.action_battery_otimizations).setEnabled(isBatteryOptimizationsOpenOsDialogApiAvailable()); + menu.findItem(R.id.action_battery_otimizations).setVisible(isBatteryOptimizationsOpenOsDialogApiAvailable()); return true; } From 9d3b38141aea2f5c397efe53bf2d37c0b4cf9827 Mon Sep 17 00:00:00 2001 From: kote Date: Sat, 24 Aug 2019 19:12:11 +0800 Subject: [PATCH 27/36] android various fixes and improv --- android/res/values-ru/strings.xml | 1 + android/res/values/strings.xml | 1 + .../src/org/purplei2p/i2pd/I2PDActivity.java | 89 +++++++++++-------- 3 files changed, 53 insertions(+), 38 deletions(-) diff --git a/android/res/values-ru/strings.xml b/android/res/values-ru/strings.xml index 318e2180..1b0b2113 100755 --- a/android/res/values-ru/strings.xml +++ b/android/res/values-ru/strings.xml @@ -24,4 +24,5 @@ Ваша операционная система осуществляет оптимизации расхода аккумулятора, которые могут приводить к выгрузке I2PD из памяти и прекращению его работы с целью сэкономить заряд аккумулятора.\n\nВам сейчас будет предложено разрешить отключение этих оптимизаций. Продолжить Ваша версия Андроид не поддерживает показ диалога об оптимизациях аккумулятора для приложений. + Плановая остановка отменена diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml index 43065b77..e08c1c46 100755 --- a/android/res/values/strings.xml +++ b/android/res/values/strings.xml @@ -24,4 +24,5 @@ Your Android version does not support opting out of battery optimizations Battery Optimizations Your Android OS version does not support showing the dialog for battery optimizations for applications. + Planned shutdown canceled diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index ed0ae908..89881b42 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -44,7 +44,6 @@ import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; // For future package update checking -import org.purplei2p.i2pd.BuildConfig; import static android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS; @@ -86,6 +85,7 @@ public class I2PDActivity extends Activity { }; private static volatile long graceStartedMillis; private static final Object graceStartedMillis_LOCK=new Object(); + private Menu optionsMenu; private static String formatGraceTimeRemaining() { long remainingSeconds; @@ -138,7 +138,7 @@ public class I2PDActivity extends Activity { super.onDestroy(); textView = null; daemon.removeStateChangeListener(daemonStateUpdatedListener); - //cancelGracefulStop(); + //cancelGracefulStop0(); try{ doUnbindService(); }catch(Throwable tr){ @@ -160,7 +160,7 @@ public class I2PDActivity extends Activity { } } - private static void cancelGracefulStop() { + private void cancelGracefulStop0() { Timer gracefulQuitTimer = getGracefulQuitTimer(); if(gracefulQuitTimer!=null) { gracefulQuitTimer.cancel(); @@ -232,6 +232,7 @@ public class I2PDActivity extends Activity { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.options_main, menu); menu.findItem(R.id.action_battery_otimizations).setVisible(isBatteryOptimizationsOpenOsDialogApiAvailable()); + this.optionsMenu = menu; return true; } @@ -251,15 +252,11 @@ public class I2PDActivity extends Activity { i2pdStop(); return true; case R.id.action_graceful_stop: - if (getGracefulQuitTimer()!= null) - { - item.setTitle(R.string.action_graceful_stop); - i2pdCancelGracefulStop (); - } - else - { - item.setTitle(R.string.action_cancel_graceful_stop); - i2pdGracefulStop(); + synchronized (graceStartedMillis_LOCK) { + if (getGracefulQuitTimer() != null) + cancelGracefulStop(); + else + i2pdGracefulStop(); } return true; case R.id.action_battery_otimizations: @@ -282,7 +279,7 @@ public class I2PDActivity extends Activity { } private void i2pdStop() { - cancelGracefulStop(); + cancelGracefulStop0(); new Thread(() -> { Log.d(TAG, "stopping"); try { @@ -329,16 +326,17 @@ public class I2PDActivity extends Activity { },"gracInit").start(); } - private void i2pdCancelGracefulStop() + private void cancelGracefulStop() { - cancelGracefulStop(); - Toast.makeText(this, R.string.startedOkay, Toast.LENGTH_SHORT).show(); + cancelGracefulStop0(); new Thread(() -> { try { - Log.d(TAG, "grac stopping cancel"); - if(daemon.isStartedOkay()) - daemon.startAcceptingTunnels(); + Log.d(TAG, "canceling grac stop"); + if(daemon.isStartedOkay()) { + daemon.startAcceptingTunnels(); + runOnUiThread(() -> Toast.makeText(this, R.string.shutdown_canceled, Toast.LENGTH_SHORT).show()); + } else i2pdStop(); } @@ -374,8 +372,19 @@ public class I2PDActivity extends Activity { return gracefulQuitTimer; } - private static void setGracefulQuitTimer(Timer gracefulQuitTimer) { + private void setGracefulQuitTimer(Timer gracefulQuitTimer) { I2PDActivity.gracefulQuitTimer = gracefulQuitTimer; + runOnUiThread(()-> { + Menu menu = optionsMenu; + if (menu != null) { + MenuItem item = menu.findItem(R.id.action_graceful_stop); + if (item != null) { + synchronized (graceStartedMillis_LOCK) { + item.setTitle(getGracefulQuitTimer() != null ? R.string.action_cancel_graceful_stop : R.string.action_graceful_stop); + } + } + } + }); } /** @@ -398,20 +407,22 @@ public class I2PDActivity extends Activity { // to a file. That doesn't appear to be the case. If the returned array is // null or has 0 length, we assume the path is to a file. This means empty // directories will get turned into files. - if (contents == null || contents.length == 0) - throw new IOException(); + if (contents == null || contents.length == 0) { + copyFileAsset(path); + return; + } // Make the directory. File dir = new File(i2pdpath, path); - Log.d(TAG, "dir.mkdirs() returned "+dir.mkdirs()); + boolean result = dir.mkdirs(); + Log.d(TAG, "dir.mkdirs() returned " + result); // Recurse on the contents. for (String entry : contents) { - copyAsset(path + "/" + entry); + copyAsset(path + '/' + entry); } } catch (IOException e) { - Log.e(TAG,"ex ignored", e); - copyFileAsset(path); + Log.e(TAG, "ex ignored for path='" + path + "'", e); } } @@ -424,19 +435,21 @@ public class I2PDActivity extends Activity { */ private void copyFileAsset(String path) { File file = new File(i2pdpath, path); - if(!file.exists()) try { - InputStream in = getAssets().open(path); - OutputStream out = new FileOutputStream(file); - byte[] buffer = new byte[1024]; - int read = in.read(buffer); - while (read != -1) { - out.write(buffer, 0, read); - read = in.read(buffer); + if(!file.exists()) { + try { + try (InputStream in = getAssets().open(path) ) { + try (OutputStream out = new FileOutputStream(file)) { + byte[] buffer = new byte[1024]; + int read = in.read(buffer); + while (read != -1) { + out.write(buffer, 0, read); + read = in.read(buffer); + } + } + } + } catch (IOException e) { + Log.e(TAG, "", e); } - out.close(); - in.close(); - } catch (IOException e) { - Log.e(TAG, "", e); } } From 0b5509a1edbb033578b7971f55dca941ef183fde Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 25 Aug 2019 14:54:43 -0400 Subject: [PATCH 28/36] correct authClients offset --- libi2pd/LeaseSet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 008a4594..c44a2f6f 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -875,7 +875,7 @@ namespace data { RAND_bytes (innerInput, 32); // authCookie htobe16buf (m_Buffer + offset, authKeys->size ()); offset += 2; // num clients - CreateClientAuthData (subcredential, authType, authKeys, innerInput, m_Buffer); + CreateClientAuthData (subcredential, authType, authKeys, innerInput, m_Buffer + offset); offset += authKeys->size ()*40; // auth clients } // Layer 2 From 80765a797b4174fc05541ef84c2fb7f3261d40ff Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 25 Aug 2019 19:14:53 -0400 Subject: [PATCH 29/36] correct outer cipher text len --- libi2pd/LeaseSet.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index c44a2f6f..3a4ddd1f 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -834,7 +834,11 @@ namespace data { if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH) layer1Flags |= 0x01; // DH, authentication scheme 0, auth bit 1 else if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_PSK) layer1Flags |= 0x03; // PSK, authentication scheme 1, auth bit 1 - if (layer1Flags) m_BufferLen += authKeys->size ()*40 + 2; // auth data len + if (layer1Flags) + { + m_BufferLen += authKeys->size ()*40 + 2; // auth data len + lenOuterCiphertext += authKeys->size ()*40 + 2; + } } m_Buffer = new uint8_t[m_BufferLen + 1]; m_Buffer[0] = NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; From 9d06aa2f6aa7bc76d7fbf4de41b6a624c1ab13e4 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 25 Aug 2019 20:51:15 -0400 Subject: [PATCH 30/36] pass authSalt or epk --- libi2pd/LeaseSet.cpp | 21 ++++++++++++--------- libi2pd/LeaseSet.h | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 3a4ddd1f..5dacb6d5 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -836,8 +836,8 @@ namespace data else if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_PSK) layer1Flags |= 0x03; // PSK, authentication scheme 1, auth bit 1 if (layer1Flags) { - m_BufferLen += authKeys->size ()*40 + 2; // auth data len - lenOuterCiphertext += authKeys->size ()*40 + 2; + m_BufferLen += 32 + 2 + authKeys->size ()*40; // auth data len + lenOuterCiphertext += 32 + 2 + authKeys->size ()*40; } } m_Buffer = new uint8_t[m_BufferLen + 1]; @@ -878,9 +878,8 @@ namespace data if (layer1Flags) { RAND_bytes (innerInput, 32); // authCookie - htobe16buf (m_Buffer + offset, authKeys->size ()); offset += 2; // num clients CreateClientAuthData (subcredential, authType, authKeys, innerInput, m_Buffer + offset); - offset += authKeys->size ()*40; // auth clients + offset += 32 + 2 + authKeys->size ()*40; // auth clients } // Layer 2 // keys = HKDF(outerSalt, outerInput, "ELS2_L2K", 44) @@ -920,12 +919,14 @@ namespace data LogPrint (eLogError, "LeaseSet2: couldn't extract inner layer"); } - void LocalEncryptedLeaseSet2::CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr > authKeys, const uint8_t * authCookie, uint8_t * authClients) const + void LocalEncryptedLeaseSet2::CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr > authKeys, const uint8_t * authCookie, uint8_t * authData) const { if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH) { i2p::crypto::X25519Keys ek; ek.GenerateKeys (); // esk and epk + memcpy (authData, ek.GetPublicKey (), 32); authData += 32; // epk + htobe16buf (authData, authKeys->size ()); authData += 2; // num clients uint8_t authInput[100]; // sharedSecret || cpk_i || subcredential || publishedTimestamp memcpy (authInput + 64, subcredential, 36); for (auto& it: *authKeys) @@ -934,14 +935,16 @@ namespace data memcpy (authInput + 32, it, 32); uint8_t okm[64]; // 52 actual data i2p::crypto::HKDF (ek.GetPublicKey (), authInput, 100, "ELS2_XCA", okm); - memcpy (authClients, okm + 44, 8); authClients += 8; // clientID_i - i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authClients); authClients += 32; // clientCookie_i + memcpy (authData, okm + 44, 8); authData += 8; // clientID_i + i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authData); authData += 32; // clientCookie_i } } else // assume PSK { uint8_t authSalt[32]; RAND_bytes (authSalt, 32); + memcpy (authData, authSalt, 32); authData += 32; // authSalt + htobe16buf (authData, authKeys->size ()); authData += 2; // num clients uint8_t authInput[68]; // authInput = psk_i || subcredential || publishedTimestamp memcpy (authInput + 32, subcredential, 36); for (auto& it: *authKeys) @@ -949,8 +952,8 @@ namespace data memcpy (authInput, it, 32); uint8_t okm[64]; // 52 actual data i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm); - memcpy (authClients, okm + 44, 8); authClients += 8; // clientID_i - i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authClients); authClients += 32; // clientCookie_i + memcpy (authData, okm + 44, 8); authData += 8; // clientID_i + i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authData); authData += 32; // clientCookie_i } } } diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index 935aca37..70aa7110 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -272,7 +272,7 @@ namespace data private: - void CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr > authKeys, const uint8_t * authCookie, uint8_t * authClients) const; + void CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr > authKeys, const uint8_t * authCookie, uint8_t * authData) const; private: From e42efec220808f4aa04d2e726fd6c80d6404b830 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 26 Aug 2019 07:35:11 -0400 Subject: [PATCH 31/36] correct outet plain text length in case of authKeys --- libi2pd/LeaseSet.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 5dacb6d5..b516f010 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -826,20 +826,18 @@ namespace data int authType, std::shared_ptr > authKeys): LocalLeaseSet2 (ls->GetIdentity ()), m_InnerLeaseSet (ls) { - size_t lenInnerPlaintext = ls->GetBufferLen () + 1, lenOuterPlaintext = lenInnerPlaintext + 32 + 1, - lenOuterCiphertext = lenOuterPlaintext + 32; - m_BufferLen = 2/*blinded sig type*/ + 32/*blinded pub key*/ + 4/*published*/ + 2/*expires*/ + 2/*flags*/ + 2/*lenOuterCiphertext*/ + lenOuterCiphertext + 64/*signature*/; + size_t lenInnerPlaintext = ls->GetBufferLen () + 1, lenOuterPlaintext = lenInnerPlaintext + 32 + 1; uint8_t layer1Flags = 0; if (authKeys) { if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH) layer1Flags |= 0x01; // DH, authentication scheme 0, auth bit 1 else if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_PSK) layer1Flags |= 0x03; // PSK, authentication scheme 1, auth bit 1 if (layer1Flags) - { - m_BufferLen += 32 + 2 + authKeys->size ()*40; // auth data len - lenOuterCiphertext += 32 + 2 + authKeys->size ()*40; - } - } + lenOuterPlaintext += 32 + 2 + authKeys->size ()*40; // auth data len + } + size_t lenOuterCiphertext = lenOuterPlaintext + 32; + + m_BufferLen = 2/*blinded sig type*/ + 32/*blinded pub key*/ + 4/*published*/ + 2/*expires*/ + 2/*flags*/ + 2/*lenOuterCiphertext*/ + lenOuterCiphertext + 64/*signature*/; m_Buffer = new uint8_t[m_BufferLen + 1]; m_Buffer[0] = NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; BlindedPublicKey blindedKey (ls->GetIdentity ()); From b5aa67b491ab3d283165dc3e64dee71e1cf99bb0 Mon Sep 17 00:00:00 2001 From: kote Date: Tue, 27 Aug 2019 17:10:53 +0800 Subject: [PATCH 32/36] tweaked debug logging in i2pd_qt --- qt/i2pd_qt/DaemonQT.cpp | 12 ++++++++++-- qt/i2pd_qt/logviewermanager.cpp | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/qt/i2pd_qt/DaemonQT.cpp b/qt/i2pd_qt/DaemonQT.cpp index f5e6d62b..1e45c583 100644 --- a/qt/i2pd_qt/DaemonQT.cpp +++ b/qt/i2pd_qt/DaemonQT.cpp @@ -11,6 +11,8 @@ #include #include +//#define DEBUG_WITH_DEFAULT_LOGGING (1) + namespace i2p { namespace qt @@ -151,10 +153,16 @@ namespace qt int result; { - std::shared_ptr logstreamptr=std::make_shared(); + std::shared_ptr logstreamptr= +#ifdef DEBUG_WITH_DEFAULT_LOGGING + nullptr +#else + std::make_shared() +#endif + ; //TODO move daemon init deinit to a bg thread DaemonQTImpl daemon; - (*logstreamptr) << "Initialising the daemon..." << std::endl; + if(logstreamptr) (*logstreamptr) << "Initialising the daemon..." << std::endl; bool daemonInitSuccess = daemon.init(argc, argv, logstreamptr); if(!daemonInitSuccess) { diff --git a/qt/i2pd_qt/logviewermanager.cpp b/qt/i2pd_qt/logviewermanager.cpp index 30fc904a..823956b2 100644 --- a/qt/i2pd_qt/logviewermanager.cpp +++ b/qt/i2pd_qt/logviewermanager.cpp @@ -18,7 +18,7 @@ namespace logviewer { QString Worker::pollAndShootATimerForInfiniteRetries() { std::shared_ptr logStream=logViewerManager.getLogStream(); - assert(logStream!=nullptr); + if(!logStream)return ""; std::streamsize MAX_SZ=64*1024; char*buf=(char*)malloc(MAX_SZ*sizeof(char)); if(buf==nullptr)return ""; From 3939ca9eb48e34a82e72f30ee5162df3874dc57c Mon Sep 17 00:00:00 2001 From: kote Date: Tue, 27 Aug 2019 17:51:55 +0800 Subject: [PATCH 33/36] enabled default logging debug option for qt debug builds --- qt/i2pd_qt/i2pd_qt.pro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 9a978731..deb1c805 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -7,6 +7,8 @@ TEMPLATE = app QMAKE_CXXFLAGS *= -std=c++11 -Wno-unused-parameter -Wno-maybe-uninitialized DEFINES += USE_UPNP +debug: DEFINES += DEBUG_WITH_DEFAULT_LOGGING + SOURCES += DaemonQT.cpp mainwindow.cpp \ ../../libi2pd/api.cpp \ ../../libi2pd/Base.cpp \ From 99116ff097a87dcc32ecb978953dc807c2677f66 Mon Sep 17 00:00:00 2001 From: kote Date: Tue, 27 Aug 2019 19:31:28 +0800 Subject: [PATCH 34/36] qt: disabled upnp for now - until upnp fixed --- qt/i2pd_qt/i2pd_qt.pro | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index deb1c805..51aa4246 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -5,7 +5,10 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = i2pd_qt TEMPLATE = app QMAKE_CXXFLAGS *= -std=c++11 -Wno-unused-parameter -Wno-maybe-uninitialized -DEFINES += USE_UPNP + +# For now, disable UPnP which currently crashes on Stop() -- https://github.com/PurpleI2P/i2pd/issues/1387 +#DEFINES += USE_UPNP +DEFINES -= USE_UPNP debug: DEFINES += DEBUG_WITH_DEFAULT_LOGGING From d523f0caddd3b743da91d19638564e2843935c93 Mon Sep 17 00:00:00 2001 From: kote Date: Tue, 27 Aug 2019 19:31:57 +0800 Subject: [PATCH 35/36] gitignored autosave files by qtcreator --- qt/i2pd_qt/.gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qt/i2pd_qt/.gitignore b/qt/i2pd_qt/.gitignore index 3abca1bd..f1d57c58 100644 --- a/qt/i2pd_qt/.gitignore +++ b/qt/i2pd_qt/.gitignore @@ -6,4 +6,6 @@ i2pd_qt Makefile* *.stash object_script.* -i2pd_qt_plugin_import.cpp \ No newline at end of file +i2pd_qt_plugin_import.cpp +i2pd_qt.pro.autosave* + From 44a2549b8199eb392047ff1a79107d0630961546 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 27 Aug 2019 09:46:54 -0400 Subject: [PATCH 36/36] 2.28.0 --- ChangeLog | 12 ++++++++++++ Win32/installer.iss | 2 +- android/build.gradle | 4 ++-- appveyor.yml | 2 +- contrib/rpm/i2pd-git.spec | 5 ++++- contrib/rpm/i2pd.spec | 5 ++++- debian/changelog | 6 ++++++ libi2pd/version.h | 4 ++-- qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml | 1 + 9 files changed, 33 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index d52260ab..89253f5b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,18 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.28.0] - 2019-08-27 +### Added +- RAW datagrams in SAM +- Publishing encrypted LeaseSet2 with DH or PSH authentication +- Ability to disable battery optimization for Android +- Transport Network ID Check +### Changed +- Set and handle published encrypted flag for LeaseSet2 +### Fixed +- ReceiveID changes in the same stream +- "\r\n" command terminator in SAM + ## [2.27.0] - 2019-07-03 ### Added - Support of PSK and DH authentication for encrypted LeaseSet2 diff --git a/Win32/installer.iss b/Win32/installer.iss index b00523da..4c78bb6a 100644 --- a/Win32/installer.iss +++ b/Win32/installer.iss @@ -1,5 +1,5 @@ #define I2Pd_AppName "i2pd" -#define I2Pd_ver "2.27.0" +#define I2Pd_ver "2.28.0" #define I2Pd_Publisher "PurpleI2P" [Setup] diff --git a/android/build.gradle b/android/build.gradle index 12e4b20c..441f6be8 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -30,8 +30,8 @@ android { applicationId "org.purplei2p.i2pd" targetSdkVersion 29 minSdkVersion 14 - versionCode 2270 - versionName "2.27.0" + versionCode 2280 + versionName "2.28.0" ndk { abiFilters 'armeabi-v7a' abiFilters 'x86' diff --git a/appveyor.yml b/appveyor.yml index dfbc656c..67693ac3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.27.0.{build} +version: 2.28.0.{build} pull_requests: do_not_increment_build_number: true branches: diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 1dda44b1..ed4bad86 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.27.0 +Version: 2.28.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -110,6 +110,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Tue Aug 27 2019 orignal - 2.28.0 +- update to 2.28.0 + * Wed Jul 3 2019 orignal - 2.27.0 - update to 2.27.0 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 67c7f4bf..61271680 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.27.0 +Version: 2.28.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git @@ -108,6 +108,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Tue Aug 27 2019 orignal - 2.28.0 +- update to 2.28.0 + * Wed Jul 3 2019 orignal - 2.27.0 - update to 2.27.0 diff --git a/debian/changelog b/debian/changelog index 0f30a066..4a6fbfd8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.28.0-1) unstable; urgency=medium + + * updated to version 2.28.0/0.9.42 + + -- orignal Tue, 27 Aug 2019 16:00:00 +0000 + i2pd (2.27.0-1) unstable; urgency=medium * updated to version 2.27.0/0.9.41 diff --git a/libi2pd/version.h b/libi2pd/version.h index cd96c677..1c08a362 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -7,7 +7,7 @@ #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 27 +#define I2PD_VERSION_MINOR 28 #define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) @@ -21,7 +21,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 41 +#define I2P_VERSION_MICRO 42 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) diff --git a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml index b16d0d5c..65683584 100644 --- a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml +++ b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml @@ -35,6 +35,7 @@ +