mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 04:04:16 +00:00
Merge branch 'master' of https://github.com/orignal/i2pd
This commit is contained in:
commit
370324d119
38
NetDb.cpp
38
NetDb.cpp
@ -448,10 +448,18 @@ namespace data
|
||||
{
|
||||
auto r = FindRouter (router);
|
||||
// do we have that floodfill router in our database?
|
||||
if (r)
|
||||
if (r)
|
||||
{
|
||||
// we do
|
||||
if (!dest->IsExcluded (r->GetIdentHash ()) && dest->GetNumExcludedPeers () < 30) // TODO: fix TunnelGateway first
|
||||
{
|
||||
// tell floodfill about us
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
i2p::tunnel::eDeliveryTypeRouter,
|
||||
r->GetIdentHash (), 0,
|
||||
CreateDatabaseStoreMsg ()
|
||||
});
|
||||
// request destination
|
||||
auto msg = dest->CreateRequestMessage (r, dest->GetLastReplyTunnel ());
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
@ -506,16 +514,15 @@ namespace data
|
||||
auto inbound = i2p::tunnel::tunnels.GetNextInboundTunnel ();
|
||||
if (outbound && inbound)
|
||||
{
|
||||
auto floodfill = GetRandomRouter (outbound->GetEndpointRouter (), true);
|
||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||
uint8_t randomHash[32];
|
||||
rnd.GenerateBlock (randomHash, 32);
|
||||
RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), false, true);
|
||||
dest->SetLastOutboundTunnel (outbound);
|
||||
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
|
||||
if (floodfill)
|
||||
{
|
||||
{
|
||||
LogPrint ("Exploring new routers ...");
|
||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||
uint8_t randomHash[32];
|
||||
rnd.GenerateBlock (randomHash, 32);
|
||||
RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), false, true);
|
||||
dest->SetLastOutboundTunnel (outbound);
|
||||
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
@ -529,8 +536,10 @@ namespace data
|
||||
floodfill->GetIdentHash (), 0,
|
||||
dest->CreateRequestMessage (floodfill, inbound) // explore
|
||||
});
|
||||
outbound->SendTunnelDataMsg (msgs);
|
||||
outbound->SendTunnelDataMsg (msgs);
|
||||
}
|
||||
else
|
||||
DeleteRequestedDestination (dest);
|
||||
}
|
||||
}
|
||||
|
||||
@ -557,6 +566,15 @@ namespace data
|
||||
m_RequestedDestinations.erase (it);
|
||||
}
|
||||
}
|
||||
|
||||
void NetDb::DeleteRequestedDestination (RequestedDestination * dest)
|
||||
{
|
||||
if (dest)
|
||||
{
|
||||
m_RequestedDestinations.erase (dest->GetDestination ());
|
||||
delete dest;
|
||||
}
|
||||
}
|
||||
|
||||
const RouterInfo * NetDb::GetRandomNTCPRouter (bool floodfillOnly) const
|
||||
{
|
||||
|
1
NetDb.h
1
NetDb.h
@ -87,6 +87,7 @@ namespace data
|
||||
RequestedDestination * CreateRequestedDestination (const IdentHash& dest,
|
||||
bool isLeaseSet, bool isExploratory = false);
|
||||
void DeleteRequestedDestination (const IdentHash& dest);
|
||||
void DeleteRequestedDestination (RequestedDestination * dest);
|
||||
|
||||
private:
|
||||
|
||||
|
138
SSU.cpp
138
SSU.cpp
@ -47,6 +47,7 @@ namespace ssu
|
||||
{
|
||||
switch (m_State)
|
||||
{
|
||||
case eSessionStateConfirmedSent:
|
||||
case eSessionStateEstablished:
|
||||
// most common case
|
||||
ProcessMessage (buf, len);
|
||||
@ -86,23 +87,38 @@ namespace ssu
|
||||
LogPrint ("SSU test received");
|
||||
break;
|
||||
case PAYLOAD_TYPE_SESSION_DESTROYED:
|
||||
{
|
||||
LogPrint ("SSU session destroy received");
|
||||
if (m_Server)
|
||||
m_Server->DeleteSession (this); // delete this
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LogPrint ("Unexpected SSU payload type ", (int)payloadType);
|
||||
}
|
||||
}
|
||||
// TODO: try intro key as well
|
||||
else
|
||||
LogPrint ("MAC verifcation failed");
|
||||
{
|
||||
LogPrint ("MAC key failed. Trying intro key");
|
||||
auto introKey = GetIntroKey ();
|
||||
if (introKey && Validate (buf, len, introKey))
|
||||
{
|
||||
Decrypt (buf, len, introKey);
|
||||
SSUHeader * header = (SSUHeader *)buf;
|
||||
LogPrint ("Unexpected SSU payload type ", (int)(header->flag >> 4));
|
||||
// TODO:
|
||||
}
|
||||
else
|
||||
LogPrint ("MAC verifcation failed");
|
||||
m_State = eSessionStateUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||
{
|
||||
LogPrint ("Process session request");
|
||||
// use our intro key
|
||||
if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST,
|
||||
i2p::context.GetRouterInfo (), buf, len))
|
||||
if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, buf, len))
|
||||
{
|
||||
m_State = eSessionStateRequestReceived;
|
||||
LogPrint ("Session request received");
|
||||
@ -121,7 +137,7 @@ namespace ssu
|
||||
}
|
||||
|
||||
// use remote intro key
|
||||
if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, *m_RemoteRouter, buf, len))
|
||||
if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, buf, len))
|
||||
{
|
||||
m_State = eSessionStateCreatedReceived;
|
||||
LogPrint ("Session created received");
|
||||
@ -132,8 +148,6 @@ namespace ssu
|
||||
i2p::context.UpdateAddress (ourIP.to_string ().c_str ());
|
||||
uint32_t relayTag = be32toh (*(uint32_t *)(buf + sizeof (SSUHeader) + 263));
|
||||
SendSessionConfirmed (buf + sizeof (SSUHeader), ourAddress, relayTag);
|
||||
m_State = eSessionStateEstablished;
|
||||
Established ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,9 +161,9 @@ namespace ssu
|
||||
if ((header->flag >> 4) == PAYLOAD_TYPE_SESSION_CONFIRMED)
|
||||
{
|
||||
m_State = eSessionStateConfirmedReceived;
|
||||
LogPrint ("Session confirmed received");
|
||||
// TODO:
|
||||
LogPrint ("Session confirmed received");
|
||||
m_State = eSessionStateEstablished;
|
||||
// TODO: send DeliverStatus
|
||||
Established ();
|
||||
}
|
||||
else
|
||||
@ -161,10 +175,10 @@ namespace ssu
|
||||
|
||||
void SSUSession::SendSessionRequest ()
|
||||
{
|
||||
auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr;
|
||||
if (!address)
|
||||
auto introKey = GetIntroKey ();
|
||||
if (!introKey)
|
||||
{
|
||||
LogPrint ("Missing remote SSU address");
|
||||
LogPrint ("SSU is not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -177,7 +191,7 @@ namespace ssu
|
||||
uint8_t iv[16];
|
||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||
rnd.GenerateBlock (iv, 16); // random iv
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, 304, address->key, iv, address->key);
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, 304, introKey, iv, introKey);
|
||||
|
||||
m_State = eSessionStateRequestSent;
|
||||
m_Server->Send (buf, 304, m_RemoteEndpoint);
|
||||
@ -185,10 +199,10 @@ namespace ssu
|
||||
|
||||
void SSUSession::SendSessionCreated (const uint8_t * x)
|
||||
{
|
||||
auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr;
|
||||
if (!address)
|
||||
auto introKey = GetIntroKey ();
|
||||
if (!introKey)
|
||||
{
|
||||
LogPrint ("Missing remote SSU address");
|
||||
LogPrint ("SSU is not supported");
|
||||
return;
|
||||
}
|
||||
uint8_t signedData[532]; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time
|
||||
@ -224,20 +238,13 @@ namespace ssu
|
||||
m_Encryption.ProcessData (payload, payload, 48);
|
||||
|
||||
// encrypt message with intro key
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, 368, address->key, iv, address->key);
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, 368, introKey, iv, introKey);
|
||||
m_State = eSessionStateRequestSent;
|
||||
m_Server->Send (buf, 368, m_RemoteEndpoint);
|
||||
}
|
||||
|
||||
void SSUSession::SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag)
|
||||
{
|
||||
auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr;
|
||||
if (!address)
|
||||
{
|
||||
LogPrint ("Missing remote SSU address");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t buf[480 + 18];
|
||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
*payload = 1; // 1 fragment
|
||||
@ -275,15 +282,15 @@ namespace ssu
|
||||
m_Server->Send (buf, 480, m_RemoteEndpoint);
|
||||
}
|
||||
|
||||
bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, const i2p::data::RouterInfo& r, uint8_t * buf, size_t len)
|
||||
bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len)
|
||||
{
|
||||
auto address = r.GetSSUAddress ();
|
||||
if (address)
|
||||
auto introKey = GetIntroKey ();
|
||||
if (introKey)
|
||||
{
|
||||
// use intro key for verification and decryption
|
||||
if (Validate (buf, len, address->key))
|
||||
if (Validate (buf, len, introKey))
|
||||
{
|
||||
Decrypt (buf, len, address->key);
|
||||
Decrypt (buf, len, introKey);
|
||||
SSUHeader * header = (SSUHeader *)buf;
|
||||
if ((header->flag >> 4) == expectedPayloadType)
|
||||
{
|
||||
@ -297,7 +304,7 @@ namespace ssu
|
||||
LogPrint ("MAC verifcation failed");
|
||||
}
|
||||
else
|
||||
LogPrint ("SSU is not supported by ", r.GetIdentHashAbbreviation ());
|
||||
LogPrint ("SSU is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -374,6 +381,7 @@ namespace ssu
|
||||
|
||||
void SSUSession::Established ()
|
||||
{
|
||||
SendI2NPMessage (CreateDatabaseStoreMsg ());
|
||||
if (!m_DelayedMessages.empty ())
|
||||
{
|
||||
for (auto it :m_DelayedMessages)
|
||||
@ -382,6 +390,22 @@ namespace ssu
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t * SSUSession::GetIntroKey () const
|
||||
{
|
||||
if (m_RemoteRouter)
|
||||
{
|
||||
// we are client
|
||||
auto address = m_RemoteRouter->GetSSUAddress ();
|
||||
return address ? address->key : nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are server
|
||||
auto address = i2p::context.GetRouterInfo ().GetSSUAddress ();
|
||||
return address ? address->key : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::SendI2NPMessage (I2NPMessage * msg)
|
||||
{
|
||||
if (msg)
|
||||
@ -463,11 +487,25 @@ namespace ssu
|
||||
m_IncomleteMessages[msgID] = msg;
|
||||
if (isLast)
|
||||
{
|
||||
SendMsgAck (msgID);
|
||||
if (fragmentNum > 0)
|
||||
m_IncomleteMessages.erase (msgID);
|
||||
msg->FromSSU (msgID);
|
||||
i2p::HandleI2NPMessage (msg, false);
|
||||
SendMsgAck (msgID);
|
||||
if (m_State == eSessionStateEstablished)
|
||||
i2p::HandleI2NPMessage (msg, false);
|
||||
else
|
||||
{
|
||||
// we expect DeliveryStatus
|
||||
if (msg->GetHeader ()->typeID == eI2NPDeliveryStatus)
|
||||
{
|
||||
LogPrint ("SSU session established");
|
||||
m_State = eSessionStateEstablished;
|
||||
Established ();
|
||||
}
|
||||
else
|
||||
LogPrint ("SSU unexpected message ", (int)msg->GetHeader ()->typeID);
|
||||
DeleteI2NPMessage (msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
buf += fragmentSize;
|
||||
@ -499,8 +537,21 @@ namespace ssu
|
||||
uint8_t buf[48 + 18], iv[16];
|
||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||
rnd.GenerateBlock (iv, 16); // random iv
|
||||
// encrypt message with session key
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, m_SessionKey, iv, m_MacKey);
|
||||
if (m_State == eSessionStateEstablished)
|
||||
// encrypt message with session key
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, m_SessionKey, iv, m_MacKey);
|
||||
else
|
||||
{
|
||||
auto introKey = GetIntroKey ();
|
||||
if (introKey)
|
||||
// encrypt message with intro key
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, introKey, iv, introKey);
|
||||
else
|
||||
{
|
||||
LogPrint ("SSU: can't send SessionDestroyed message");
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_Server->Send (buf, 48, m_RemoteEndpoint);
|
||||
}
|
||||
|
||||
@ -514,10 +565,13 @@ namespace ssu
|
||||
uint32_t fragmentNum = 0;
|
||||
while (len > 0)
|
||||
{
|
||||
uint8_t buf[SSU_MTU + 18], iv[16];
|
||||
buf[0] = DATA_FLAG_WANT_REPLY; // for compatibility
|
||||
buf[1] = 1; // always 1 message fragment per message
|
||||
*(uint32_t *)(buf + 2) = msgID;
|
||||
uint8_t buf[SSU_MTU + 18], iv[16], * payload = buf + sizeof (SSUHeader);
|
||||
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
|
||||
payload++;
|
||||
*payload = 1; // always 1 message fragment per message
|
||||
payload++;
|
||||
*(uint32_t *)payload = msgID;
|
||||
payload += 4;
|
||||
bool isLast = (len <= payloadSize);
|
||||
size_t size = isLast ? len : payloadSize;
|
||||
uint32_t fragmentInfo = (fragmentNum << 17);
|
||||
@ -526,10 +580,11 @@ namespace ssu
|
||||
|
||||
fragmentInfo |= size;
|
||||
fragmentInfo = htobe32 (fragmentInfo);
|
||||
memcpy (buf + 6, (uint8_t *)(&fragmentInfo) + 1, 3);
|
||||
memcpy (buf + 9, msgBuf, size);
|
||||
memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3);
|
||||
payload += 3;
|
||||
memcpy (payload, msgBuf, size);
|
||||
|
||||
size += sizeof (SSUHeader) + 9;
|
||||
size += payload - buf;
|
||||
if (size % 16) // make sure 16 bytes boundary
|
||||
size = (size/16 + 1)*16;
|
||||
|
||||
@ -570,6 +625,7 @@ namespace ssu
|
||||
|
||||
void SSUServer::Stop ()
|
||||
{
|
||||
DeleteAllSessions ();
|
||||
m_Socket.close ();
|
||||
}
|
||||
|
||||
|
3
SSU.h
3
SSU.h
@ -89,10 +89,11 @@ namespace ssu
|
||||
void SendSesionDestroyed ();
|
||||
void Send (i2p::I2NPMessage * msg);
|
||||
|
||||
bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, const i2p::data::RouterInfo& r, uint8_t * buf, size_t len);
|
||||
bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len);
|
||||
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey);
|
||||
void Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey);
|
||||
bool Validate (uint8_t * buf, size_t len, const uint8_t * macKey);
|
||||
const uint8_t * GetIntroKey () const;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -168,7 +168,23 @@ namespace i2p
|
||||
AddNTCPSession (session);
|
||||
}
|
||||
else
|
||||
LogPrint ("No NTCP addresses available");
|
||||
{
|
||||
// SSU always have lower prioprity than NTCP
|
||||
// TODO: it shouldn't
|
||||
LogPrint ("No NTCP addresses available. Trying SSU");
|
||||
address = r->GetSSUAddress ();
|
||||
if (address && m_SSUServer)
|
||||
{
|
||||
auto s = m_SSUServer->GetSession (r);
|
||||
if (s)
|
||||
{
|
||||
s->SendI2NPMessage (msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint ("No SSU addresses available");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user