void RouterContext::HandleI2NPMessage( const uint8_t* buf, size_t, std::shared_ptr<i2p::tunnel::InboundTunnel> from) { i2p::HandleI2NPMessage( CreateI2NPMessage( buf, GetI2NPMessageLength(buf), from)); }
I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID) { I2NPDeliveryStatusMsg msg; if (msgID) { msg.msgID = htobe32 (msgID); msg.timestamp = htobe64 (i2p::util::GetMillisecondsSinceEpoch ()); } else // for SSU establishment { msg.msgID = htobe32 (i2p::context.GetRandomNumberGenerator ().GenerateWord32 ()); msg.timestamp = htobe64 (2); // netID = 2 } return CreateI2NPMessage (eI2NPDeliveryStatus, (uint8_t *)&msg, sizeof (msg)); }
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len) { int num = buf[0]; LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records"); if (len < num*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 1) { LogPrint (eLogError, "VaribleTunnelBuild message of ", num, " records is too short ", len); return; } auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID); if (tunnel) { // endpoint of inbound tunnel LogPrint (eLogDebug, "I2NP: VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ()); if (tunnel->HandleTunnelBuildResponse (buf, len)) { LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been created"); tunnel->SetState (i2p::tunnel::eTunnelStateEstablished); i2p::tunnel::tunnels.AddInboundTunnel (tunnel); } else { LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined"); tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed); } } else { uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; if (HandleBuildRequestRecords (num, buf + 1, clearText)) { if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel { // so we send it to reply tunnel transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), eI2NPVariableTunnelBuildReply, buf, len, bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); } else transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); } } }
void HandleTunnelBuildMsg (uint8_t * buf, size_t len) { I2NPBuildRequestRecordClearText clearText; if (HandleBuildRequestRecords (NUM_TUNNEL_BUILD_RECORDS, (I2NPBuildRequestRecordElGamalEncrypted *)buf, clearText)) { if (clearText.flag & 0x40) // we are endpoint of outbound tunnel { // so we send it to reply tunnel transports.SendMessage (clearText.nextIdent, CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel), eI2NPTunnelBuildReply, buf, len, be32toh (clearText.nextMessageID))); } else transports.SendMessage (clearText.nextIdent, CreateI2NPMessage (eI2NPTunnelBuild, buf, len, be32toh (clearText.nextMessageID))); } }
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len) { int num = buf[0]; LogPrint ("VariableTunnelBuild ", num, " records"); i2p::tunnel::Tunnel * tunnel = i2p::tunnel::tunnels.GetPendingTunnel (replyMsgID); if (tunnel) { // endpoint of inbound tunnel LogPrint ("VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ()); if (tunnel->HandleTunnelBuildResponse (buf, len)) { LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been created"); tunnel->SetState (i2p::tunnel::eTunnelStateEstablished); i2p::tunnel::tunnels.AddInboundTunnel (static_cast<i2p::tunnel::InboundTunnel *>(tunnel)); } else { LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been declined"); tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed); } } else { I2NPBuildRequestRecordElGamalEncrypted * records = (I2NPBuildRequestRecordElGamalEncrypted *)(buf+1); I2NPBuildRequestRecordClearText clearText; if (HandleBuildRequestRecords (num, records, clearText)) { if (clearText.flag & 0x40) // we are endpoint of outboud tunnel { // so we send it to reply tunnel transports.SendMessage (clearText.nextIdent, CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel), eI2NPVariableTunnelBuildReply, buf, len, be32toh (clearText.nextMessageID))); } else transports.SendMessage (clearText.nextIdent, CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, be32toh (clearText.nextMessageID))); } } }
void HandleTunnelBuildMsg (uint8_t * buf, size_t len) { if (len < NUM_TUNNEL_BUILD_RECORDS*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE) { LogPrint (eLogError, "TunnelBuild message is too short ", len); return; } uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; if (HandleBuildRequestRecords (NUM_TUNNEL_BUILD_RECORDS, buf, clearText)) { if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outbound tunnel { // so we send it to reply tunnel transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), eI2NPTunnelBuildReply, buf, len, bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); } else transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, CreateI2NPMessage (eI2NPTunnelBuild, buf, len, bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); } }
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; } } }