Browse Source

establish SSU session through relay

pull/46/head
orignal 11 years ago
parent
commit
64aa588a9b
  1. 7
      RouterInfo.cpp
  2. 1
      RouterInfo.h
  3. 134
      SSU.cpp
  4. 10
      SSU.h

7
RouterInfo.cpp

@ -323,6 +323,13 @@ namespace data
else else
return m_SupportedTransports & (eSSUV4 | eSSUV6); return m_SupportedTransports & (eSSUV4 | eSSUV6);
} }
bool RouterInfo::UsesIntroducer () const
{
if (!IsSSU ()) return false;
auto address = GetSSUAddress (true); // no introducers for v6
return address && !address->introducers.empty ();
}
const RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) const const RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) const
{ {

1
RouterInfo.h

@ -75,6 +75,7 @@ namespace data
bool IsNTCP (bool v4only = true) const; bool IsNTCP (bool v4only = true) const;
bool IsSSU (bool v4only = true) const; bool IsSSU (bool v4only = true) const;
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
bool UsesIntroducer () const;
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
bool IsUnreachable () const { return m_IsUnreachable; }; bool IsUnreachable () const { return m_IsUnreachable; };

134
SSU.cpp

@ -65,6 +65,15 @@ namespace ssu
// session confirmed // session confirmed
ProcessSessionConfirmed (buf, len); ProcessSessionConfirmed (buf, len);
break; break;
case eSessionRelayRequestSent:
// relay response
ProcessRelayResponse (buf,len);
break;
case eSessionRelayRequestReceived:
// HolePunch
m_State = eSessionStateUnknown;
Connect ();
break;
default: default:
LogPrint ("SSU state not implemented yet"); LogPrint ("SSU state not implemented yet");
} }
@ -91,8 +100,12 @@ namespace ssu
LogPrint ("SSU session destroy received"); LogPrint ("SSU session destroy received");
if (m_Server) if (m_Server)
m_Server->DeleteSession (this); // delete this m_Server->DeleteSession (this); // delete this
} break;
break; }
case PAYLOAD_TYPE_RELAY_INTRO:
LogPrint ("SSU relay intro received");
// TODO:
break;
default: default:
LogPrint ("Unexpected SSU payload type ", (int)payloadType); LogPrint ("Unexpected SSU payload type ", (int)payloadType);
} }
@ -197,6 +210,37 @@ namespace ssu
m_Server->Send (buf, 304, m_RemoteEndpoint); m_Server->Send (buf, 304, m_RemoteEndpoint);
} }
void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer)
{
auto address = i2p::context.GetRouterInfo ().GetSSUAddress ();
if (!address)
{
LogPrint ("SSU is not supported");
return;
}
uint8_t buf[96 + 18];
uint8_t * payload = buf + sizeof (SSUHeader);
*(uint32_t *)payload = htobe32 (introducer.iTag);
payload += 4;
*payload = 0; // no address
payload++;
*(uint16_t *)payload = 0; // port = 0
payload += 2;
*payload = 0; // challenge
payload++;
memcpy (payload, address->key, 32);
payload += 32;
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
*(uint32_t *)payload = htobe32 (rnd.GenerateWord32 ()); // nonce
uint8_t iv[16];
rnd.GenerateBlock (iv, 16); // random iv
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey);
m_State = eSessionRelayRequestSent;
m_Server->Send (buf, 96, m_RemoteEndpoint);
}
void SSUSession::SendSessionCreated (const uint8_t * x) void SSUSession::SendSessionCreated (const uint8_t * x)
{ {
auto introKey = GetIntroKey (); auto introKey = GetIntroKey ();
@ -282,6 +326,46 @@ namespace ssu
m_Server->Send (buf, 480, m_RemoteEndpoint); m_Server->Send (buf, 480, m_RemoteEndpoint);
} }
void SSUSession::ProcessRelayResponse (uint8_t * buf, size_t len)
{
LogPrint ("Process relay response");
auto address = i2p::context.GetRouterInfo ().GetSSUAddress ();
if (!address)
{
LogPrint ("SSU is not supported");
return;
}
if (Validate (buf, len, address->key))
{
Decrypt (buf, len, address->key);
SSUHeader * header = (SSUHeader *)buf;
if ((header->flag >> 4) == PAYLOAD_TYPE_RELAY_RESPONSE)
{
LogPrint ("Relay response received");
m_State = eSessionRelayRequestReceived;
uint8_t * payload = buf + sizeof (SSUHeader);
payload++;
boost::asio::ip::address_v4 remoteIP (be32toh (*(uint32_t* )(payload)));
payload += 4;
uint16_t remotePort = be16toh (*(uint16_t *)(payload));
payload += 2;
boost::asio::ip::udp::endpoint newRemoteEndpoint(remoteIP, remotePort);
m_Server->ReassignSession (m_RemoteEndpoint, newRemoteEndpoint);
m_RemoteEndpoint = newRemoteEndpoint;
payload++;
boost::asio::ip::address_v4 ourIP (be32toh (*(uint32_t* )(payload)));
payload += 4;
uint16_t ourPort = be16toh (*(uint16_t *)(payload));
payload += 2;
LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort);
i2p::context.UpdateAddress (ourIP.to_string ().c_str ());
}
else
LogPrint ("Unexpected payload type ", (int)(header->flag >> 4));
}
}
bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len) bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len)
{ {
auto introKey = GetIntroKey (); auto introKey = GetIntroKey ();
@ -301,7 +385,7 @@ namespace ssu
LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); LogPrint ("Unexpected payload type ", (int)(header->flag >> 4));
} }
else else
LogPrint ("MAC verifcation failed"); LogPrint ("MAC verification failed");
} }
else else
LogPrint ("SSU is not supported"); LogPrint ("SSU is not supported");
@ -368,6 +452,11 @@ namespace ssu
SendSessionRequest (); SendSessionRequest ();
} }
void SSUSession::ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer)
{
SendRelayRequest (introducer);
}
void SSUSession::Close () void SSUSession::Close ()
{ {
SendSesionDestroyed (); SendSesionDestroyed ();
@ -677,12 +766,27 @@ namespace ssu
session = it->second; session = it->second;
else else
{ {
// otherwise create new session // otherwise create new session
session = new SSUSession (this, remoteEndpoint, router); if (!router->UsesIntroducer ())
m_Sessions[remoteEndpoint] = session; {
LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ", // connect directly
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created"); session = new SSUSession (this, remoteEndpoint, router);
session->Connect (); m_Sessions[remoteEndpoint] = session;
LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ",
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created");
session->Connect ();
}
else
{
// connect to introducer
auto& introducer = address->introducers[0]; // TODO:
boost::asio::ip::udp::endpoint introducerEndpoint (introducer.iHost, introducer.iPort);
session = new SSUSession (this, introducerEndpoint, router);
m_Sessions[introducerEndpoint] = session;
LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (),
"] created through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ());
session->ConnectThroughIntroducer (introducer);
}
} }
} }
else else
@ -709,6 +813,18 @@ namespace ssu
delete it.second; delete it.second;
} }
m_Sessions.clear (); m_Sessions.clear ();
}
void SSUServer::ReassignSession (const boost::asio::ip::udp::endpoint& oldEndpoint, const boost::asio::ip::udp::endpoint& newEndpoint)
{
auto it = m_Sessions.find (oldEndpoint);
if (it != m_Sessions.end ())
{
m_Sessions.erase (it);
m_Sessions[newEndpoint] = it->second;
LogPrint ("SSU session ressigned from ", oldEndpoint.address ().to_string (), ":", oldEndpoint.port (),
" to ", newEndpoint.address ().to_string (), ":", newEndpoint.port ());
}
} }
} }
} }

10
SSU.h

@ -55,6 +55,8 @@ namespace ssu
eSessionStateCreatedReceived, eSessionStateCreatedReceived,
eSessionStateConfirmedSent, eSessionStateConfirmedSent,
eSessionStateConfirmedReceived, eSessionStateConfirmedReceived,
eSessionRelayRequestSent,
eSessionRelayRequestReceived,
eSessionStateEstablished eSessionStateEstablished
}; };
@ -68,6 +70,7 @@ namespace ssu
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void Connect (); void Connect ();
void ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
void Close (); void Close ();
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
void SendI2NPMessage (I2NPMessage * msg); void SendI2NPMessage (I2NPMessage * msg);
@ -79,10 +82,12 @@ namespace ssu
void ProcessMessage (uint8_t * buf, size_t len); // call for established session void ProcessMessage (uint8_t * buf, size_t len); // call for established session
void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendSessionRequest (); void SendSessionRequest ();
void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer);
void ProcessSessionCreated (uint8_t * buf, size_t len); void ProcessSessionCreated (uint8_t * buf, size_t len);
void SendSessionCreated (const uint8_t * x); void SendSessionCreated (const uint8_t * x);
void ProcessSessionConfirmed (uint8_t * buf, size_t len); void ProcessSessionConfirmed (uint8_t * buf, size_t len);
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag); void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag);
void ProcessRelayResponse (uint8_t * buf, size_t len);
void Established (); void Established ();
void ProcessData (uint8_t * buf, size_t len); void ProcessData (uint8_t * buf, size_t len);
void SendMsgAck (uint32_t msgID); void SendMsgAck (uint32_t msgID);
@ -118,10 +123,11 @@ namespace ssu
void Stop (); void Stop ();
SSUSession * GetSession (const i2p::data::RouterInfo * router); SSUSession * GetSession (const i2p::data::RouterInfo * router);
void DeleteSession (SSUSession * session); void DeleteSession (SSUSession * session);
void DeleteAllSessions (); void DeleteAllSessions ();
const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; };
void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
void ReassignSession (const boost::asio::ip::udp::endpoint& oldEndpoint, const boost::asio::ip::udp::endpoint& newEndpoint);
private: private:

Loading…
Cancel
Save