void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg) { if (msg) { uint8_t typeID = msg->GetTypeID (); LogPrint (eLogDebug, "I2NP: Handling message with type ", (int)typeID); switch (typeID) { case eI2NPTunnelData: i2p::tunnel::tunnels.PostTunnelData (msg); break; case eI2NPTunnelGateway: i2p::tunnel::tunnels.PostTunnelData (msg); break; case eI2NPGarlic: { if (msg->from) { if (msg->from->GetTunnelPool ()) msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg); else LogPrint (eLogInfo, "I2NP: Local destination for garlic doesn't exist anymore"); } else i2p::context.ProcessGarlicMessage (msg); break; } case eI2NPDatabaseStore: case eI2NPDatabaseSearchReply: case eI2NPDatabaseLookup: // forward to netDb i2p::data::netdb.PostI2NPMsg (msg); break; case eI2NPDeliveryStatus: { if (msg->from && msg->from->GetTunnelPool ()) msg->from->GetTunnelPool ()->ProcessDeliveryStatus (msg); else i2p::context.ProcessDeliveryStatusMessage (msg); break; } case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuildReply: case eI2NPTunnelBuild: case eI2NPTunnelBuildReply: // forward to tunnel thread i2p::tunnel::tunnels.PostTunnelData (msg); break; default: HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); } } }
void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage> msg) { if (msg) { switch (msg->GetTypeID ()) { case eI2NPTunnelData: m_TunnelMsgs.push_back (msg); break; case eI2NPTunnelGateway: m_TunnelGatewayMsgs.push_back (msg); break; default: HandleI2NPMessage (msg); } } }
void HandleI2NPMessage (I2NPMessage * msg) { if (msg) { switch (msg->GetHeader ()->typeID) { case eI2NPTunnelData: LogPrint ("TunnelData"); i2p::tunnel::tunnels.PostTunnelData (msg); break; case eI2NPTunnelGateway: LogPrint ("TunnelGateway"); HandleTunnelGatewayMsg (msg); break; case eI2NPGarlic: LogPrint ("Garlic"); if (msg->from && msg->from->GetTunnelPool ()) msg->from->GetTunnelPool ()->GetLocalDestination ().ProcessGarlicMessage (msg); else i2p::context.ProcessGarlicMessage (msg); break; case eI2NPDatabaseStore: case eI2NPDatabaseSearchReply: case eI2NPDatabaseLookup: // forward to netDb i2p::data::netdb.PostI2NPMsg (msg); break; case eI2NPDeliveryStatus: LogPrint ("DeliveryStatus"); if (msg->from && msg->from->GetTunnelPool ()) msg->from->GetTunnelPool ()->ProcessDeliveryStatus (msg); else i2p::context.ProcessDeliveryStatusMessage (msg); break; default: HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); DeleteI2NPMessage (msg); } } }
void GarlicDestination::HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) { if (len < 1) { LogPrint (eLogError, "Garlic: payload is too short"); return; } int numCloves = buf[0]; LogPrint (eLogDebug, "Garlic: ", numCloves," cloves"); buf++; len--; for (int i = 0; i < numCloves; i++) { const uint8_t * buf1 = buf; // delivery instructions uint8_t flag = buf[0]; buf++; // flag if (flag & 0x80) // encrypted? { // TODO: implement LogPrint (eLogWarning, "Garlic: clove encrypted"); buf += 32; } ptrdiff_t offset = buf - buf1; GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03); switch (deliveryType) { case eGarlicDeliveryTypeLocal: LogPrint (eLogDebug, "Garlic: type local"); if (offset > (int)len) { LogPrint (eLogError, "Garlic: message is too short"); break; } HandleI2NPMessage (buf, len - offset, from); break; case eGarlicDeliveryTypeDestination: LogPrint (eLogDebug, "Garlic: type destination"); buf += 32; // destination. check it later or for multiple destinations offset = buf - buf1; if (offset > (int)len) { LogPrint (eLogError, "Garlic: message is too short"); break; } HandleI2NPMessage (buf, len - offset, from); break; case eGarlicDeliveryTypeTunnel: { LogPrint (eLogDebug, "Garlic: type tunnel"); // gwHash and gwTunnel sequence is reverted uint8_t * gwHash = buf; buf += 32; offset = buf - buf1; if (offset + 4 > (int)len) { LogPrint (eLogError, "Garlic: message is too short"); break; } uint32_t gwTunnel = bufbe32toh (buf); buf += 4; offset += 4; auto msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len - offset), from); if (from) // received through an inbound tunnel { std::shared_ptr<i2p::tunnel::OutboundTunnel> tunnel; if (from->GetTunnelPool ()) tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel (); else LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel"); if (tunnel) // we have send it through an outbound tunnel tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg); else LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove"); } else // received directly i2p::transport::transports.SendMessage (gwHash, i2p::CreateTunnelGatewayMsg (gwTunnel, msg)); // send directly break; } case eGarlicDeliveryTypeRouter: { uint8_t * ident = buf; buf += 32; offset = buf - buf1; if (!from) // received directly { if (offset > (int)len) { LogPrint (eLogError, "Garlic: message is too short"); break; } i2p::transport::transports.SendMessage (ident, CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len - offset))); } else LogPrint (eLogWarning, "Garlic: type router for inbound tunnels not supported"); break; } default: LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType); } if (offset > (int)len) { LogPrint (eLogError, "Garlic: message is too short"); break; } buf += GetI2NPMessageLength (buf, len - offset); // I2NP buf += 4; // CloveID buf += 8; // Date buf += 3; // Certificate offset = buf - buf1; if (offset > (int)len) { LogPrint (eLogError, "Garlic: clove is too long"); break; } len -= offset; } }
void GarlicDestination::HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) { const uint8_t * buf1 = buf; int numCloves = buf[0]; LogPrint (eLogDebug, "Garlic: ", numCloves," cloves"); buf++; for (int i = 0; i < numCloves; i++) { // delivery instructions uint8_t flag = buf[0]; buf++; // flag if (flag & 0x80) // encrypted? { // TODO: implement LogPrint (eLogWarning, "Garlic: clove encrypted"); buf += 32; } GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03); switch (deliveryType) { case eGarlicDeliveryTypeLocal: LogPrint (eLogDebug, "Garlic: type local"); HandleI2NPMessage (buf, len, from); break; case eGarlicDeliveryTypeDestination: LogPrint (eLogDebug, "Garlic: type destination"); buf += 32; // destination. check it later or for multiple destinations HandleI2NPMessage (buf, len, from); break; case eGarlicDeliveryTypeTunnel: { LogPrint (eLogDebug, "Garlic: type tunnel"); // gwHash and gwTunnel sequence is reverted uint8_t * gwHash = buf; buf += 32; uint32_t gwTunnel = bufbe32toh (buf); buf += 4; std::shared_ptr<i2p::tunnel::OutboundTunnel> tunnel; if (from && from->GetTunnelPool ()) tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel (); if (tunnel) // we have send it through an outbound tunnel { auto msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from); tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg); } else LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove"); break; } case eGarlicDeliveryTypeRouter: LogPrint (eLogWarning, "Garlic: type router not supported"); buf += 32; break; default: LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType); } buf += GetI2NPMessageLength (buf); // I2NP buf += 4; // CloveID buf += 8; // Date buf += 3; // Certificate if (buf - buf1 > (int)len) { LogPrint (eLogError, "Garlic: clove is too long"); break; } } }