Browse Source

Merge branch 'master' of https://github.com/orignal/i2pd

pull/40/head
Meeh 11 years ago
parent
commit
370324d119
  1. 28
      NetDb.cpp
  2. 1
      NetDb.h
  3. 128
      SSU.cpp
  4. 3
      SSU.h
  5. 18
      Transports.cpp

28
NetDb.cpp

@ -450,8 +450,16 @@ namespace data @@ -450,8 +450,16 @@ namespace data
// do we have that floodfill router in our database?
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 @@ -506,16 +514,15 @@ namespace data
auto inbound = i2p::tunnel::tunnels.GetNextInboundTunnel ();
if (outbound && inbound)
{
auto floodfill = GetRandomRouter (outbound->GetEndpointRouter (), true);
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);
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
if (floodfill)
{
LogPrint ("Exploring new routers ...");
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
@ -531,6 +538,8 @@ namespace data @@ -531,6 +538,8 @@ namespace data
});
outbound->SendTunnelDataMsg (msgs);
}
else
DeleteRequestedDestination (dest);
}
}
@ -558,6 +567,15 @@ namespace data @@ -558,6 +567,15 @@ namespace data
}
}
void NetDb::DeleteRequestedDestination (RequestedDestination * dest)
{
if (dest)
{
m_RequestedDestinations.erase (dest->GetDestination ());
delete dest;
}
}
const RouterInfo * NetDb::GetRandomNTCPRouter (bool floodfillOnly) const
{
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();

1
NetDb.h

@ -87,6 +87,7 @@ namespace data @@ -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:

128
SSU.cpp

@ -47,6 +47,7 @@ namespace ssu @@ -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 @@ -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 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 @@ -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 @@ -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 ();
}
}
@ -148,8 +162,8 @@ namespace ssu @@ -148,8 +162,8 @@ namespace ssu
{
m_State = eSessionStateConfirmedReceived;
LogPrint ("Session confirmed received");
// TODO:
m_State = eSessionStateEstablished;
// TODO: send DeliverStatus
Established ();
}
else
@ -161,10 +175,10 @@ namespace ssu @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -463,11 +487,25 @@ namespace ssu
m_IncomleteMessages[msgID] = msg;
if (isLast)
{
SendMsgAck (msgID);
if (fragmentNum > 0)
m_IncomleteMessages.erase (msgID);
msg->FromSSU (msgID);
if (m_State == eSessionStateEstablished)
i2p::HandleI2NPMessage (msg, false);
SendMsgAck (msgID);
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 @@ -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
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 @@ -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 @@ -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 @@ -570,6 +625,7 @@ namespace ssu
void SSUServer::Stop ()
{
DeleteAllSessions ();
m_Socket.close ();
}

3
SSU.h

@ -89,10 +89,11 @@ namespace ssu @@ -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:

18
Transports.cpp

@ -168,7 +168,23 @@ namespace i2p @@ -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…
Cancel
Save