size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg, bool isDestination) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec size_t size = 0; if (isDestination) { buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination size++; memcpy (buf + size, m_Destination->GetIdentHash (), 32); size += 32; } else { buf[size] = 0;// delivery instructions flag local size++; } memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); size += msg->GetLength (); uint32_t cloveID; RAND_bytes ((uint8_t *)&cloveID, 4); htobe32buf (buf + size, cloveID); // CloveID size += 4; htobe64buf (buf + size, ts); // Expiration of clove size += 8; memset (buf + size, 0, 3); // certificate of clove size += 3; return size; }
size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec uint32_t msgID; RAND_bytes ((uint8_t *)&msgID, 4); size_t size = 0; uint8_t * numCloves = payload + size; *numCloves = 0; size++; if (m_Owner) { // resubmit non-confirmed LeaseSet if (m_LeaseSetUpdateStatus == eLeaseSetSubmitted && i2p::util::GetMillisecondsSinceEpoch () > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT) m_LeaseSetUpdateStatus = eLeaseSetUpdated; // attach DeviveryStatus if necessary if (newTags || m_LeaseSetUpdateStatus == eLeaseSetUpdated) // new tags created or leaseset updated { // clove is DeliveryStatus auto cloveSize = CreateDeliveryStatusClove (payload + size, msgID); if (cloveSize > 0) // successive? { size += cloveSize; (*numCloves)++; if (newTags) // new tags created m_UnconfirmedTagsMsgs[msgID] = newTags; m_Owner->DeliveryStatusSent (shared_from_this (), msgID); } else LogPrint (eLogWarning, "Garlic: DeliveryStatus clove was not created"); } // attach LeaseSet if (m_LeaseSetUpdateStatus == eLeaseSetUpdated) { m_LeaseSetUpdateStatus = eLeaseSetSubmitted; m_LeaseSetUpdateMsgID = msgID; m_LeaseSetSubmissionTime = i2p::util::GetMillisecondsSinceEpoch (); // clove if our leaseSet must be attached auto leaseSet = CreateDatabaseStoreMsg (m_Owner->GetLeaseSet ()); size += CreateGarlicClove (payload + size, leaseSet, false); (*numCloves)++; } } if (msg) // clove message ifself if presented { size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false); (*numCloves)++; } memset (payload + size, 0, 3); // certificate of message size += 3; htobe32buf (payload + size, msgID); // MessageID size += 4; htobe64buf (payload + size, ts); // Expiration of message size += 8; return size; }
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID) { auto m = NewI2NPShortMessage (); uint8_t * buf = m->GetPayload (); if (msgID) { htobe32buf (buf + DELIVERY_STATUS_MSGID_OFFSET, msgID); htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, i2p::util::GetMillisecondsSinceEpoch ()); } else // for SSU establishment { RAND_bytes ((uint8_t *)&msgID, 4); htobe32buf (buf + DELIVERY_STATUS_MSGID_OFFSET, msgID); htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, 2); // netID = 2 } m->len += DELIVERY_STATUS_SIZE; m->FillI2NPMessageHeader (eI2NPDeliveryStatus); return m; }
size_t GarlicRoutingSession::CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID) { size_t size = 0; if (m_Owner) { auto inboundTunnel = m_Owner->GetTunnelPool ()->GetNextInboundTunnel (); if (inboundTunnel) { buf[size] = eGarlicDeliveryTypeTunnel << 5; // delivery instructions flag tunnel size++; // hash and tunnelID sequence is reversed for Garlic memcpy (buf + size, inboundTunnel->GetNextIdentHash (), 32); // To Hash size += 32; htobe32buf (buf + size, inboundTunnel->GetNextTunnelID ()); // tunnelID size += 4; // create msg auto msg = CreateDeliveryStatusMsg (msgID); if (m_Owner) { //encrypt uint8_t key[32], tag[32]; RAND_bytes (key, 32); // random session key RAND_bytes (tag, 32); // random session tag m_Owner->SubmitSessionKey (key, tag); GarlicRoutingSession garlic (key, tag); msg = garlic.WrapSingleMessage (msg); } memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); size += msg->GetLength (); // fill clove uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec uint32_t cloveID; RAND_bytes ((uint8_t *)&cloveID, 4); htobe32buf (buf + size, cloveID); // CloveID size += 4; htobe64buf (buf + size, ts); // Expiration of clove size += 8; memset (buf + size, 0, 3); // certificate of clove size += 3; } else LogPrint (eLogError, "Garlic: No inbound tunnels in the pool for DeliveryStatus"); } else LogPrint (eLogWarning, "Garlic: Missing local LeaseSet"); return size; }
LeaseSet::LeaseSet (std::shared_ptr<const i2p::tunnel::TunnelPool> pool): m_IsValid (true) { if (!pool) return; // header auto localDestination = pool->GetLocalDestination (); if (!localDestination) { m_Buffer = nullptr; m_BufferLen = 0; m_IsValid = false; LogPrint (eLogError, "LeaseSet: Destination for local LeaseSet doesn't exist"); return; } m_Buffer = new uint8_t[MAX_LS_BUFFER_SIZE]; m_BufferLen = localDestination->GetIdentity ()->ToBuffer (m_Buffer, MAX_LS_BUFFER_SIZE); memcpy (m_Buffer + m_BufferLen, localDestination->GetEncryptionPublicKey (), 256); m_BufferLen += 256; auto signingKeyLen = localDestination->GetIdentity ()->GetSigningPublicKeyLen (); memset (m_Buffer + m_BufferLen, 0, signingKeyLen); m_BufferLen += signingKeyLen; auto tunnels = pool->GetInboundTunnels (5); // 5 tunnels maximum m_Buffer[m_BufferLen] = tunnels.size (); // num leases m_BufferLen++; // leases for (auto it: tunnels) { memcpy (m_Buffer + m_BufferLen, it->GetNextIdentHash (), 32); m_BufferLen += 32; // gateway id htobe32buf (m_Buffer + m_BufferLen, it->GetNextTunnelID ()); m_BufferLen += 4; // tunnel id uint64_t ts = it->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration ts *= 1000; // in milliseconds ts += rand () % 6; // + random milliseconds 0-5 htobe64buf (m_Buffer + m_BufferLen, ts); m_BufferLen += 8; // end date } // signature localDestination->Sign (m_Buffer, m_BufferLen, m_Buffer + m_BufferLen); m_BufferLen += localDestination->GetIdentity ()->GetSignatureLen (); LogPrint (eLogDebug, "LeaseSet: Local LeaseSet of ", tunnels.size (), " leases created"); ReadFromBuffer (); }
size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); uint32_t msgID; RAND_bytes ((uint8_t *)&msgID, 4); size_t size = 0; uint8_t * numCloves = payload + size; *numCloves = 0; size++; if (m_Owner) { // resubmit non-confirmed LeaseSet if (m_LeaseSetUpdateStatus == eLeaseSetSubmitted && ts > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT) { m_LeaseSetUpdateStatus = eLeaseSetUpdated; SetSharedRoutingPath (nullptr); // invalidate path since leaseset was not confirmed } // attach DeviveryStatus if necessary if (newTags || m_LeaseSetUpdateStatus == eLeaseSetUpdated) // new tags created or leaseset updated { // clove is DeliveryStatus auto cloveSize = CreateDeliveryStatusClove (payload + size, msgID); if (cloveSize > 0) // successive? { size += cloveSize; (*numCloves)++; if (newTags) // new tags created { newTags->msgID = msgID; m_UnconfirmedTagsMsgs.insert (std::make_pair(msgID, std::unique_ptr<UnconfirmedTags>(newTags))); newTags = nullptr; // got acquired } m_Owner->DeliveryStatusSent (shared_from_this (), msgID); } else LogPrint (eLogWarning, "Garlic: DeliveryStatus clove was not created"); } // attach LeaseSet if (m_LeaseSetUpdateStatus == eLeaseSetUpdated) { if (m_LeaseSetUpdateMsgID) m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); // remove previous m_LeaseSetUpdateStatus = eLeaseSetSubmitted; m_LeaseSetUpdateMsgID = msgID; m_LeaseSetSubmissionTime = ts; // clove if our leaseSet must be attached auto leaseSet = CreateDatabaseStoreMsg (m_Owner->GetLeaseSet ()); size += CreateGarlicClove (payload + size, leaseSet, false); (*numCloves)++; } } if (msg) // clove message ifself if presented { size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false); (*numCloves)++; } memset (payload + size, 0, 3); // certificate of message size += 3; htobe32buf (payload + size, msgID); // MessageID size += 4; htobe64buf (payload + size, ts + 8000); // Expiration of message, 8 sec size += 8; if (newTags) delete newTags; // not acquired, delete return size; }