Compare commits

...

25 Commits

Author SHA1 Message Date
orignal
8fde36a4b0 Update version.h
version 0.4.0
2014-11-25 12:46:30 -05:00
orignal
de14f8dcd7 handle Phase3 in two steps 2014-11-25 12:33:51 -05:00
orignal
1e81652a62 send Phase3 with proper identity 2014-11-25 10:59:29 -05:00
orignal
f7ce86e0c4 pass tsA to SendPhase4 2014-11-25 10:35:35 -05:00
orignal
9eb5982ea3 use generic receive buffer for phase 4 2014-11-25 10:14:18 -05:00
orignal
4778c8bdfb fixed excess data for P521 2014-11-24 21:48:01 -05:00
orignal
9574163aeb fixed incorrect certificate length 2014-11-24 21:23:12 -05:00
orignal
199ff0c210 ECDSA P384 and ECDSA P521 support 2014-11-24 20:19:13 -05:00
orignal
e0635548e9 handle EcDSA signatures 2014-11-24 15:26:57 -05:00
orignal
95524c8db3 shared pointer for SSU 2014-11-24 12:26:11 -05:00
orignal
1a0957b571 move WaitForConnect away from constructor 2014-11-24 11:18:12 -05:00
orignal
97656e7349 shared pointer for I2PTunnelConnection 2014-11-23 22:23:17 -05:00
orignal
0262a8b057 replaced boost::bind to std::bind 2014-11-23 17:00:45 -05:00
orignal
4bd8b44ab2 shared pointers for streams 2014-11-23 11:33:58 -05:00
orignal
4dc33a6f45 fixed crash 2014-11-22 21:56:59 -05:00
Mikal Villa
335de27095 Merge branch 'master' of github.com:PrivacySolutions/i2pd
* 'master' of github.com:PrivacySolutions/i2pd:
  shared pointers for SAM sockets
2014-11-22 23:12:34 +01:00
Mikal Villa
fa461b1254 Added prefix support, which enables the homebrew package to work. 2014-11-22 23:12:05 +01:00
orignal
81c63b0c30 shared pointers for SAM sockets 2014-11-22 16:35:58 -05:00
orignal
dcefe7d221 fixed typo 2014-11-21 13:49:49 -05:00
orignal
ed3aaefe96 delete delete routers from memory 2014-11-21 13:29:19 -05:00
orignal
6042aefd17 delete dead floodfill 2014-11-21 13:02:46 -05:00
orignal
1c3f70056a use shared pointer of RI for transports 2014-11-21 12:34:17 -05:00
orignal
d8b9968aed use shared pointer for RI in requested destination 2014-11-21 11:37:17 -05:00
orignal
8a357ac46c store shared pointer to RI in tunnel config 2014-11-21 10:46:11 -05:00
Mikal
5187701af1 Updated NSI file
Forgot to update version in NSI installer script
2014-11-21 00:28:21 -08:00
38 changed files with 689 additions and 425 deletions

View File

@@ -38,7 +38,7 @@ namespace datagram
auto service = m_Owner.GetService (); auto service = m_Owner.GetService ();
if (service) if (service)
service->post (boost::bind (&DatagramDestination::SendMsg, this, service->post (std::bind (&DatagramDestination::SendMsg, this,
CreateDataMessage (buf, len + headerLen), remote)); CreateDataMessage (buf, len + headerLen), remote));
else else
LogPrint (eLogWarning, "Failed to send datagram. Destination is not running"); LogPrint (eLogWarning, "Failed to send datagram. Destination is not running");

View File

@@ -190,12 +190,12 @@ namespace client
void ClientDestination::ProcessGarlicMessage (I2NPMessage * msg) void ClientDestination::ProcessGarlicMessage (I2NPMessage * msg)
{ {
m_Service->post (boost::bind (&ClientDestination::HandleGarlicMessage, this, msg)); m_Service->post (std::bind (&ClientDestination::HandleGarlicMessage, this, msg));
} }
void ClientDestination::ProcessDeliveryStatusMessage (I2NPMessage * msg) void ClientDestination::ProcessDeliveryStatusMessage (I2NPMessage * msg)
{ {
m_Service->post (boost::bind (&ClientDestination::HandleDeliveryStatusMessage, this, msg)); m_Service->post (std::bind (&ClientDestination::HandleDeliveryStatusMessage, this, msg));
} }
void ClientDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from) void ClientDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from)
@@ -274,7 +274,7 @@ namespace client
} }
} }
i2p::stream::Stream * ClientDestination::CreateStream (const i2p::data::LeaseSet& remote, int port) std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (const i2p::data::LeaseSet& remote, int port)
{ {
if (m_StreamingDestination) if (m_StreamingDestination)
return m_StreamingDestination->CreateNewOutgoingStream (remote, port); return m_StreamingDestination->CreateNewOutgoingStream (remote, port);

View File

@@ -3,6 +3,7 @@
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <memory>
#include "Identity.h" #include "Identity.h"
#include "TunnelPool.h" #include "TunnelPool.h"
#include "CryptoConst.h" #include "CryptoConst.h"
@@ -41,7 +42,7 @@ namespace client
// streaming // streaming
i2p::stream::StreamingDestination * GetStreamingDestination () const { return m_StreamingDestination; }; i2p::stream::StreamingDestination * GetStreamingDestination () const { return m_StreamingDestination; };
i2p::stream::Stream * CreateStream (const i2p::data::LeaseSet& remote, int port = 0); std::shared_ptr<i2p::stream::Stream> CreateStream (const i2p::data::LeaseSet& remote, int port = 0);
void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor); void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor);
void StopAcceptingStreams (); void StopAcceptingStreams ();
bool IsAcceptingStreams () const; bool IsAcceptingStreams () const;

View File

@@ -518,7 +518,7 @@ namespace util
{ {
m_Stream->Close (); m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream); i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr; m_Stream.reset ();
} }
m_Socket->close (); m_Socket->close ();
//delete this; //delete this;
@@ -710,7 +710,7 @@ namespace util
if (it.second && it.second->IsEstablished ()) if (it.second && it.second->IsEstablished ())
{ {
// incoming connection doesn't have remote RI // incoming connection doesn't have remote RI
bool outgoing = it.second->GetRemoteRouter (); auto outgoing = it.second->GetRemoteRouter ();
if (outgoing) s << "-->"; if (outgoing) s << "-->";
s << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase64 ().substr (0, 4) << ": " s << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase64 ().substr (0, 4) << ": "
<< it.second->GetSocket ().remote_endpoint().address ().to_string (); << it.second->GetSocket ().remote_endpoint().address ().to_string ();
@@ -727,7 +727,7 @@ namespace util
for (auto it: ssuServer->GetSessions ()) for (auto it: ssuServer->GetSessions ())
{ {
// incoming connections don't have remote router // incoming connections don't have remote router
bool outgoing = it.second->GetRemoteRouter (); auto outgoing = it.second->GetRemoteRouter ();
auto endpoint = it.second->GetRemoteEndpoint (); auto endpoint = it.second->GetRemoteEndpoint ();
if (outgoing) s << "-->"; if (outgoing) s << "-->";
s << endpoint.address ().to_string () << ":" << endpoint.port (); s << endpoint.address ().to_string () << ":" << endpoint.port ();

View File

@@ -3,6 +3,7 @@
#include <sstream> #include <sstream>
#include <thread> #include <thread>
#include <memory>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/array.hpp> #include <boost/array.hpp>
#include "LeaseSet.h" #include "LeaseSet.h"
@@ -79,7 +80,7 @@ namespace util
boost::asio::ip::tcp::socket * m_Socket; boost::asio::ip::tcp::socket * m_Socket;
boost::asio::deadline_timer m_Timer; boost::asio::deadline_timer m_Timer;
i2p::stream::Stream * m_Stream; std::shared_ptr<i2p::stream::Stream> m_Stream;
char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1]; char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
size_t m_BufferLen; size_t m_BufferLen;
request m_Request; request m_Request;

View File

@@ -1,4 +1,3 @@
#include <boost/bind.hpp>
#include "base64.h" #include "base64.h"
#include "Log.h" #include "Log.h"
#include "NetDb.h" #include "NetDb.h"
@@ -12,21 +11,15 @@ namespace client
{ {
I2PTunnelConnection::I2PTunnelConnection (I2PTunnel * owner, I2PTunnelConnection::I2PTunnelConnection (I2PTunnel * owner,
boost::asio::ip::tcp::socket * socket, const i2p::data::LeaseSet * leaseSet): boost::asio::ip::tcp::socket * socket, const i2p::data::LeaseSet * leaseSet):
m_Socket (socket), m_Owner (owner) m_Socket (socket), m_Owner (owner), m_RemoteEndpoint (socket->remote_endpoint ())
{ {
m_Stream = m_Owner->GetLocalDestination ()->CreateStream (*leaseSet); m_Stream = m_Owner->GetLocalDestination ()->CreateStream (*leaseSet);
m_Stream->Send (m_Buffer, 0); // connect
StreamReceive ();
Receive ();
} }
I2PTunnelConnection::I2PTunnelConnection (I2PTunnel * owner, i2p::stream::Stream * stream, I2PTunnelConnection::I2PTunnelConnection (I2PTunnel * owner, std::shared_ptr<i2p::stream::Stream> stream,
boost::asio::ip::tcp::socket * socket, const boost::asio::ip::tcp::endpoint& target): boost::asio::ip::tcp::socket * socket, const boost::asio::ip::tcp::endpoint& target):
m_Socket (socket), m_Stream (stream), m_Owner (owner) m_Socket (socket), m_Stream (stream), m_Owner (owner), m_RemoteEndpoint (target)
{ {
if (m_Socket)
m_Socket->async_connect (target, boost::bind (&I2PTunnelConnection::HandleConnect,
this, boost::asio::placeholders::error));
} }
I2PTunnelConnection::~I2PTunnelConnection () I2PTunnelConnection::~I2PTunnelConnection ()
@@ -34,25 +27,38 @@ namespace client
delete m_Socket; delete m_Socket;
} }
void I2PTunnelConnection::I2PConnect ()
{
m_Stream->Send (m_Buffer, 0); // connect
StreamReceive ();
Receive ();
}
void I2PTunnelConnection::Connect ()
{
if (m_Socket)
m_Socket->async_connect (m_RemoteEndpoint, std::bind (&I2PTunnelConnection::HandleConnect,
shared_from_this (), std::placeholders::_1));
}
void I2PTunnelConnection::Terminate () void I2PTunnelConnection::Terminate ()
{ {
if (m_Stream) if (m_Stream)
{ {
m_Stream->Close (); m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream); i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr; m_Stream.reset ();
} }
m_Socket->close (); m_Socket->close ();
if (m_Owner) if (m_Owner)
m_Owner->RemoveConnection (this); m_Owner->RemoveConnection (shared_from_this ());
//delete this;
} }
void I2PTunnelConnection::Receive () void I2PTunnelConnection::Receive ()
{ {
m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
boost::bind(&I2PTunnelConnection::HandleReceived, this, std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::placeholders::_1, std::placeholders::_2));
} }
void I2PTunnelConnection::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) void I2PTunnelConnection::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@@ -87,8 +93,8 @@ namespace client
{ {
if (m_Stream) if (m_Stream)
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
boost::bind (&I2PTunnelConnection::HandleStreamReceive, this, std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred), std::placeholders::_1, std::placeholders::_2),
I2P_TUNNEL_CONNECTION_MAX_IDLE); I2P_TUNNEL_CONNECTION_MAX_IDLE);
} }
@@ -103,7 +109,7 @@ namespace client
else else
{ {
boost::asio::async_write (*m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), boost::asio::async_write (*m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred),
boost::bind (&I2PTunnelConnection::HandleWrite, this, boost::asio::placeholders::error)); std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
} }
} }
@@ -112,12 +118,7 @@ namespace client
if (ecode) if (ecode)
{ {
LogPrint ("I2PTunnel connect error: ", ecode.message ()); LogPrint ("I2PTunnel connect error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) Terminate ();
{
if (m_Stream) m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
}
} }
else else
{ {
@@ -127,20 +128,18 @@ namespace client
} }
} }
void I2PTunnel::AddConnection (I2PTunnelConnection * conn) void I2PTunnel::AddConnection (std::shared_ptr<I2PTunnelConnection> conn)
{ {
m_Connections.insert (conn); m_Connections.insert (conn);
} }
void I2PTunnel::RemoveConnection (I2PTunnelConnection * conn) void I2PTunnel::RemoveConnection (std::shared_ptr<I2PTunnelConnection> conn)
{ {
m_Connections.erase (conn); m_Connections.erase (conn);
} }
void I2PTunnel::ClearConnections () void I2PTunnel::ClearConnections ()
{ {
for (auto it: m_Connections)
delete it;
m_Connections.clear (); m_Connections.clear ();
} }
@@ -181,8 +180,8 @@ namespace client
void I2PClientTunnel::Accept () void I2PClientTunnel::Accept ()
{ {
auto newSocket = new boost::asio::ip::tcp::socket (GetService ()); auto newSocket = new boost::asio::ip::tcp::socket (GetService ());
m_Acceptor.async_accept (*newSocket, boost::bind (&I2PClientTunnel::HandleAccept, this, m_Acceptor.async_accept (*newSocket, std::bind (&I2PClientTunnel::HandleAccept, this,
boost::asio::placeholders::error, newSocket)); std::placeholders::_1, newSocket));
} }
void I2PClientTunnel::HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket) void I2PClientTunnel::HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket)
@@ -205,8 +204,8 @@ namespace client
{ {
i2p::data::netdb.RequestDestination (*m_DestinationIdentHash, true, GetLocalDestination ()->GetTunnelPool ()); i2p::data::netdb.RequestDestination (*m_DestinationIdentHash, true, GetLocalDestination ()->GetTunnelPool ());
m_Timer.expires_from_now (boost::posix_time::seconds (I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds (I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT));
m_Timer.async_wait (boost::bind (&I2PClientTunnel::HandleDestinationRequestTimer, m_Timer.async_wait (std::bind (&I2PClientTunnel::HandleDestinationRequestTimer,
this, boost::asio::placeholders::error, socket)); this, std::placeholders::_1, socket));
} }
} }
else else
@@ -240,8 +239,9 @@ namespace client
if (m_RemoteLeaseSet) // leaseSet found if (m_RemoteLeaseSet) // leaseSet found
{ {
LogPrint ("New I2PTunnel connection"); LogPrint ("New I2PTunnel connection");
auto connection = new I2PTunnelConnection (this, socket, m_RemoteLeaseSet); auto connection = std::make_shared<I2PTunnelConnection>(this, socket, m_RemoteLeaseSet);
AddConnection (connection); AddConnection (connection);
connection->I2PConnect ();
} }
else else
{ {
@@ -275,10 +275,14 @@ namespace client
LogPrint ("Local destination not set for server tunnel"); LogPrint ("Local destination not set for server tunnel");
} }
void I2PServerTunnel::HandleAccept (i2p::stream::Stream * stream) void I2PServerTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
{ {
if (stream) if (stream)
new I2PTunnelConnection (this, stream, new boost::asio::ip::tcp::socket (GetService ()), m_Endpoint); {
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, new boost::asio::ip::tcp::socket (GetService ()), m_Endpoint);
AddConnection (conn);
conn->Connect ();
}
} }
} }
} }

View File

@@ -4,6 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <string> #include <string>
#include <set> #include <set>
#include <memory>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "Identity.h" #include "Identity.h"
#include "Destination.h" #include "Destination.h"
@@ -18,16 +19,19 @@ namespace client
const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
class I2PTunnel; class I2PTunnel;
class I2PTunnelConnection class I2PTunnelConnection: public std::enable_shared_from_this<I2PTunnelConnection>
{ {
public: public:
I2PTunnelConnection (I2PTunnel * owner, boost::asio::ip::tcp::socket * socket, I2PTunnelConnection (I2PTunnel * owner, boost::asio::ip::tcp::socket * socket,
const i2p::data::LeaseSet * leaseSet); const i2p::data::LeaseSet * leaseSet);
I2PTunnelConnection (I2PTunnel * owner, i2p::stream::Stream * stream, boost::asio::ip::tcp::socket * socket, I2PTunnelConnection (I2PTunnel * owner, std::shared_ptr<i2p::stream::Stream> stream, boost::asio::ip::tcp::socket * socket,
const boost::asio::ip::tcp::endpoint& target); const boost::asio::ip::tcp::endpoint& target);
~I2PTunnelConnection (); ~I2PTunnelConnection ();
void I2PConnect ();
void Connect ();
private: private:
void Terminate (); void Terminate ();
@@ -44,8 +48,9 @@ namespace client
uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE]; uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE];
boost::asio::ip::tcp::socket * m_Socket; boost::asio::ip::tcp::socket * m_Socket;
i2p::stream::Stream * m_Stream; std::shared_ptr<i2p::stream::Stream> m_Stream;
I2PTunnel * m_Owner; I2PTunnel * m_Owner;
boost::asio::ip::tcp::endpoint m_RemoteEndpoint;
}; };
class I2PTunnel class I2PTunnel
@@ -56,8 +61,8 @@ namespace client
m_Service (service), m_LocalDestination (localDestination) {}; m_Service (service), m_LocalDestination (localDestination) {};
virtual ~I2PTunnel () { ClearConnections (); }; virtual ~I2PTunnel () { ClearConnections (); };
void AddConnection (I2PTunnelConnection * conn); void AddConnection (std::shared_ptr<I2PTunnelConnection> conn);
void RemoveConnection (I2PTunnelConnection * conn); void RemoveConnection (std::shared_ptr<I2PTunnelConnection> conn);
void ClearConnections (); void ClearConnections ();
ClientDestination * GetLocalDestination () { return m_LocalDestination; }; ClientDestination * GetLocalDestination () { return m_LocalDestination; };
void SetLocalDestination (ClientDestination * dest) { m_LocalDestination = dest; }; void SetLocalDestination (ClientDestination * dest) { m_LocalDestination = dest; };
@@ -68,7 +73,7 @@ namespace client
boost::asio::io_service& m_Service; boost::asio::io_service& m_Service;
ClientDestination * m_LocalDestination; ClientDestination * m_LocalDestination;
std::set<I2PTunnelConnection *> m_Connections; std::set<std::shared_ptr<I2PTunnelConnection> > m_Connections;
}; };
class I2PClientTunnel: public I2PTunnel class I2PClientTunnel: public I2PTunnel
@@ -111,7 +116,7 @@ namespace client
private: private:
void Accept (); void Accept ();
void HandleAccept (i2p::stream::Stream * stream); void HandleAccept (std::shared_ptr<i2p::stream::Stream> stream);
private: private:

View File

@@ -42,18 +42,53 @@ namespace data
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type) IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type)
{ {
memcpy (m_StandardIdentity.publicKey, publicKey, sizeof (m_StandardIdentity.publicKey)); memcpy (m_StandardIdentity.publicKey, publicKey, sizeof (m_StandardIdentity.publicKey));
if (type == SIGNING_KEY_TYPE_ECDSA_SHA256_P256) if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{ {
memcpy (m_StandardIdentity.signingKey + 64, signingKey, 64); size_t excessLen = 0;
uint8_t * excessBuf = nullptr;
switch (type)
{
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
{
size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP256_KEY_LENGTH);
break;
}
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
{
size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP384_KEY_LENGTH);
break;
}
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
{
memcpy (m_StandardIdentity.signingKey, signingKey, 128);
excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132 - 128
excessBuf = new uint8_t[excessLen];
memcpy (excessBuf, signingKey + 128, excessLen);
break;
}
default:
LogPrint ("Signing key type ", (int)type, " is not supported");
}
m_ExtendedLen = 4 + excessLen; // 4 bytes extra + excess length
// fill certificate
m_StandardIdentity.certificate.type = CERTIFICATE_TYPE_KEY; m_StandardIdentity.certificate.type = CERTIFICATE_TYPE_KEY;
m_ExtendedLen = 4; // 4 bytes extra m_StandardIdentity.certificate.length = htobe16 (m_ExtendedLen);
m_StandardIdentity.certificate.length = htobe16 (4); // fill extended buffer
m_ExtendedBuffer = new uint8_t[m_ExtendedLen]; m_ExtendedBuffer = new uint8_t[m_ExtendedLen];
*(uint16_t *)m_ExtendedBuffer = htobe16 (SIGNING_KEY_TYPE_ECDSA_SHA256_P256); *(uint16_t *)m_ExtendedBuffer = htobe16 (type);
*(uint16_t *)(m_ExtendedBuffer + 2) = htobe16 (CRYPTO_KEY_TYPE_ELGAMAL); *(uint16_t *)(m_ExtendedBuffer + 2) = htobe16 (CRYPTO_KEY_TYPE_ELGAMAL);
uint8_t buf[DEFAULT_IDENTITY_SIZE + 4]; if (excessLen && excessBuf)
ToBuffer (buf, DEFAULT_IDENTITY_SIZE + 4); {
memcpy (m_ExtendedBuffer + 4, excessBuf, excessLen);
delete[] excessBuf;
}
// calculate ident hash
uint8_t * buf = new uint8_t[GetFullLen ()];
ToBuffer (buf, GetFullLen ());
CryptoPP::SHA256().CalculateDigest(m_IdentHash, buf, GetFullLen ()); CryptoPP::SHA256().CalculateDigest(m_IdentHash, buf, GetFullLen ());
delete[] buf;
} }
else // DSA-SHA1 else // DSA-SHA1
{ {
@@ -188,6 +223,13 @@ namespace data
return be16toh (*(const uint16_t *)m_ExtendedBuffer); // signing key return be16toh (*(const uint16_t *)m_ExtendedBuffer); // signing key
return SIGNING_KEY_TYPE_DSA_SHA1; return SIGNING_KEY_TYPE_DSA_SHA1;
} }
CryptoKeyType IdentityEx::GetCryptoKeyType () const
{
if (m_StandardIdentity.certificate.type == CERTIFICATE_TYPE_KEY && m_ExtendedBuffer)
return be16toh (*(const uint16_t *)(m_ExtendedBuffer + 2)); // crypto key
return CRYPTO_KEY_TYPE_ELGAMAL;
}
void IdentityEx::CreateVerifier () const void IdentityEx::CreateVerifier () const
{ {
@@ -198,8 +240,26 @@ namespace data
m_Verifier = new i2p::crypto::DSAVerifier (m_StandardIdentity.signingKey); m_Verifier = new i2p::crypto::DSAVerifier (m_StandardIdentity.signingKey);
break; break;
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
m_Verifier = new i2p::crypto::ECDSAP256Verifier (m_StandardIdentity.signingKey + 64); {
break; size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
m_Verifier = new i2p::crypto::ECDSAP256Verifier (m_StandardIdentity.signingKey + padding);
break;
}
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
{
size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96
m_Verifier = new i2p::crypto::ECDSAP384Verifier (m_StandardIdentity.signingKey + padding);
break;
}
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
{
uint8_t signingKey[i2p::crypto::ECDSAP521_KEY_LENGTH];
memcpy (signingKey, m_StandardIdentity.signingKey, 128);
size_t excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132- 128
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
m_Verifier = new i2p::crypto::ECDSAP521Verifier (signingKey);
break;
}
default: default:
LogPrint ("Signing key type ", (int)keyType, " is not supported"); LogPrint ("Signing key type ", (int)keyType, " is not supported");
} }
@@ -211,6 +271,7 @@ namespace data
memcpy (m_PrivateKey, keys.privateKey, 256); // 256 memcpy (m_PrivateKey, keys.privateKey, 256); // 256
memcpy (m_SigningPrivateKey, keys.signingPrivateKey, 20); // 20 - DSA memcpy (m_SigningPrivateKey, keys.signingPrivateKey, 20); // 20 - DSA
delete m_Signer; delete m_Signer;
m_Signer = nullptr;
CreateSigner (); CreateSigner ();
return *this; return *this;
} }
@@ -221,6 +282,7 @@ namespace data
memcpy (m_PrivateKey, other.m_PrivateKey, 256); // 256 memcpy (m_PrivateKey, other.m_PrivateKey, 256); // 256
memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, 128); // 128 memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, 128); // 128
delete m_Signer; delete m_Signer;
m_Signer = nullptr;
CreateSigner (); CreateSigner ();
return *this; return *this;
} }
@@ -234,6 +296,7 @@ namespace data
memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize); memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize);
ret += signingPrivateKeySize; ret += signingPrivateKeySize;
delete m_Signer; delete m_Signer;
m_Signer = nullptr;
CreateSigner (); CreateSigner ();
return ret; return ret;
} }
@@ -257,26 +320,55 @@ namespace data
void PrivateKeys::CreateSigner () void PrivateKeys::CreateSigner ()
{ {
if (m_Public.GetSigningKeyType () == SIGNING_KEY_TYPE_ECDSA_SHA256_P256) switch (m_Public.GetSigningKeyType ())
m_Signer = new i2p::crypto::ECDSAP256Signer (m_SigningPrivateKey); {
else case SIGNING_KEY_TYPE_DSA_SHA1:
m_Signer = new i2p::crypto::DSASigner (m_SigningPrivateKey); m_Signer = new i2p::crypto::DSASigner (m_SigningPrivateKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
m_Signer = new i2p::crypto::ECDSAP256Signer (m_SigningPrivateKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
m_Signer = new i2p::crypto::ECDSAP384Signer (m_SigningPrivateKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
m_Signer = new i2p::crypto::ECDSAP521Signer (m_SigningPrivateKey);
break;
default:
LogPrint ("Signing key type ", (int)m_Public.GetSigningKeyType (), " is not supported");
}
} }
PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type) PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type)
{ {
if (type == SIGNING_KEY_TYPE_ECDSA_SHA256_P256) if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{ {
PrivateKeys keys; PrivateKeys keys;
auto& rnd = i2p::context.GetRandomNumberGenerator (); auto& rnd = i2p::context.GetRandomNumberGenerator ();
// signature
uint8_t signingPublicKey[i2p::crypto::ECDSAP521_KEY_LENGTH]; // 132 bytes is max key size now
switch (type)
{
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
i2p::crypto::CreateECDSAP256RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
i2p::crypto::CreateECDSAP384RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
i2p::crypto::CreateECDSAP521RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey);
break;
default:
LogPrint ("Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1
}
// encryption // encryption
uint8_t publicKey[256]; uint8_t publicKey[256];
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(rnd, keys.m_PrivateKey, publicKey); dh.GenerateKeyPair(rnd, keys.m_PrivateKey, publicKey);
// signature // identity
uint8_t signingPublicKey[64]; keys.m_Public = IdentityEx (publicKey, signingPublicKey, type);
i2p::crypto::CreateECDSAP256RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey);
keys.m_Public = IdentityEx (publicKey, signingPublicKey, SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
keys.CreateSigner (); keys.CreateSigner ();
return keys; return keys;
} }

View File

@@ -102,11 +102,14 @@ namespace data
Keys CreateRandomKeys (); Keys CreateRandomKeys ();
const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0; const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
const uint16_t SIGNING_KEY_TYPE_DSA_SHA1 = 0; const uint16_t SIGNING_KEY_TYPE_DSA_SHA1 = 0;
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA256_P256 = 1; const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA256_P256 = 1;
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA384_P384 = 2;
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA512_P521 = 3;
typedef uint16_t SigningKeyType; typedef uint16_t SigningKeyType;
typedef uint16_t CryptoKeyType;
class IdentityEx class IdentityEx
{ {
@@ -131,6 +134,7 @@ namespace data
size_t GetSignatureLen () const; size_t GetSignatureLen () const;
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
SigningKeyType GetSigningKeyType () const; SigningKeyType GetSigningKeyType () const;
CryptoKeyType GetCryptoKeyType () const;
private: private:

View File

@@ -12,6 +12,15 @@ LIBS =
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic # Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
CXXFLAGS += -maes -DAESNI CXXFLAGS += -maes -DAESNI
${PREFIX}:
install: all
mkdir -p ${PREFIX}/
cp -r i2p ${PREFIX}/
# Apple Mac OSX # Apple Mac OSX
UNAME_S := $(shell uname -s) UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin) ifeq ($(UNAME_S),Darwin)

View File

@@ -19,7 +19,7 @@ namespace i2p
{ {
namespace transport namespace transport
{ {
NTCPSession::NTCPSession (boost::asio::io_service& service, const i2p::data::RouterInfo * in_RemoteRouter): NTCPSession::NTCPSession (boost::asio::io_service& service, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
TransportSession (in_RemoteRouter), m_Socket (service), TransportSession (in_RemoteRouter), m_Socket (service),
m_TerminationTimer (service), m_IsEstablished (false), m_ReceiveBufferOffset (0), m_TerminationTimer (service), m_IsEstablished (false), m_ReceiveBufferOffset (0),
m_NextMessage (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0) m_NextMessage (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0)
@@ -44,7 +44,7 @@ namespace transport
uint8_t sharedKey[256]; uint8_t sharedKey[256];
if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey)) if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey))
{ {
LogPrint ("Couldn't create shared key"); LogPrint (eLogError, "Couldn't create shared key");
Terminate (); Terminate ();
return; return;
}; };
@@ -66,7 +66,7 @@ namespace transport
nonZero++; nonZero++;
if (nonZero - sharedKey > 32) if (nonZero - sharedKey > 32)
{ {
LogPrint ("First 32 bytes of shared key is all zeros. Ignored"); LogPrint (eLogWarning, "First 32 bytes of shared key is all zeros. Ignored");
return; return;
} }
} }
@@ -89,7 +89,7 @@ namespace transport
} }
m_DelayedMessages.clear (); m_DelayedMessages.clear ();
if (numDelayed > 0) if (numDelayed > 0)
LogPrint ("NTCP session ", numDelayed, " not sent"); LogPrint (eLogWarning, "NTCP session ", numDelayed, " not sent");
// TODO: notify tunnels // TODO: notify tunnels
delete this; delete this;
@@ -146,13 +146,13 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Couldn't send Phase 1 message: ", ecode.message ()); LogPrint (eLogWarning, "Couldn't send Phase 1 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 1 sent: ", bytes_transferred); LogPrint (eLogDebug, "Phase 1 sent: ", bytes_transferred);
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all (), boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase2Received, this, boost::bind(&NTCPSession::HandlePhase2Received, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
@@ -163,13 +163,13 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Phase 1 read error: ", ecode.message ()); LogPrint (eLogError, "Phase 1 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 1 received: ", bytes_transferred); LogPrint (eLogDebug, "Phase 1 received: ", bytes_transferred);
// verify ident // verify ident
uint8_t digest[32]; uint8_t digest[32];
CryptoPP::SHA256().CalculateDigest(digest, m_Establisher->phase1.pubKey, 256); CryptoPP::SHA256().CalculateDigest(digest, m_Establisher->phase1.pubKey, 256);
@@ -178,7 +178,7 @@ namespace transport
{ {
if ((m_Establisher->phase1.HXxorHI[i] ^ ident[i]) != digest[i]) if ((m_Establisher->phase1.HXxorHI[i] ^ ident[i]) != digest[i])
{ {
LogPrint ("Wrong ident"); LogPrint (eLogError, "Wrong ident");
Terminate (); Terminate ();
return; return;
} }
@@ -219,14 +219,14 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Couldn't send Phase 2 message: ", ecode.message ()); LogPrint (eLogWarning, "Couldn't send Phase 2 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 2 sent: ", bytes_transferred); LogPrint (eLogDebug, "Phase 2 sent: ", bytes_transferred);
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase3, sizeof (NTCPPhase3)), boost::asio::transfer_all (), boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer, NTCP_DEFAULT_PHASE3_SIZE), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase3Received, this, boost::bind(&NTCPSession::HandlePhase3Received, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsB)); boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsB));
} }
@@ -248,7 +248,7 @@ namespace transport
} }
else else
{ {
LogPrint ("Phase 2 received: ", bytes_transferred); LogPrint (eLogDebug, "Phase 2 received: ", bytes_transferred);
i2p::crypto::AESKey aesKey; i2p::crypto::AESKey aesKey;
CreateAESKey (m_Establisher->phase2.pubKey, aesKey); CreateAESKey (m_Establisher->phase2.pubKey, aesKey);
@@ -265,7 +265,7 @@ namespace transport
CryptoPP::SHA256().CalculateDigest(hxy, xy, 512); CryptoPP::SHA256().CalculateDigest(hxy, xy, 512);
if (memcmp (hxy, m_Establisher->phase2.encrypted.hxy, 32)) if (memcmp (hxy, m_Establisher->phase2.encrypted.hxy, 32))
{ {
LogPrint ("Incorrect hash"); LogPrint (eLogError, "Incorrect hash");
transports.ReuseDHKeysPair (m_DHKeysPair); transports.ReuseDHKeysPair (m_DHKeysPair);
m_DHKeysPair = nullptr; m_DHKeysPair = nullptr;
Terminate (); Terminate ();
@@ -277,22 +277,35 @@ namespace transport
void NTCPSession::SendPhase3 () void NTCPSession::SendPhase3 ()
{ {
m_Establisher->phase3.size = htons (i2p::data::DEFAULT_IDENTITY_SIZE); auto keys = i2p::context.GetPrivateKeys ();
memcpy (&m_Establisher->phase3.ident, &i2p::context.GetIdentity ().GetStandardIdentity (), i2p::data::DEFAULT_IDENTITY_SIZE); // TODO: uint8_t * buf = m_ReceiveBuffer;
*(uint16_t *)buf = htobe16 (keys.GetPublic ().GetFullLen ());
buf += 2;
buf += i2p::context.GetIdentity ().ToBuffer (buf, NTCP_BUFFER_SIZE);
uint32_t tsA = htobe32 (i2p::util::GetSecondsSinceEpoch ()); uint32_t tsA = htobe32 (i2p::util::GetSecondsSinceEpoch ());
m_Establisher->phase3.timestamp = tsA; *(uint32_t *)buf = tsA;
buf += 4;
size_t signatureLen = keys.GetPublic ().GetSignatureLen ();
size_t len = (buf - m_ReceiveBuffer) + signatureLen;
size_t paddingSize = len & 0x0F; // %16
if (paddingSize > 0)
{
paddingSize = 16 - paddingSize;
// TODO: fill padding with random data
buf += paddingSize;
len += paddingSize;
}
SignedData s; SignedData s;
s.Insert (m_Establisher->phase1.pubKey, 256); // x s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident
s.Insert (tsA); // tsA s.Insert (tsA); // tsA
s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB
s.Sign (i2p::context.GetPrivateKeys (), m_Establisher->phase3.signature); s.Sign (keys, buf);
m_Encryption.Encrypt((uint8_t *)&m_Establisher->phase3, sizeof(NTCPPhase3), (uint8_t *)&m_Establisher->phase3); m_Encryption.Encrypt(m_ReceiveBuffer, len, m_ReceiveBuffer);
boost::asio::async_write (m_Socket, boost::asio::buffer (m_ReceiveBuffer, len), boost::asio::transfer_all (),
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase3, sizeof (NTCPPhase3)), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase3Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsA)); boost::bind(&NTCPSession::HandlePhase3Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsA));
} }
@@ -300,14 +313,18 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Couldn't send Phase 3 message: ", ecode.message ()); LogPrint (eLogWarning, "Couldn't send Phase 3 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 3 sent: ", bytes_transferred); LogPrint (eLogDebug, "Phase 3 sent: ", bytes_transferred);
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase4, sizeof (NTCPPhase4)), boost::asio::transfer_all (), // wait for phase4
auto signatureLen = m_RemoteIdentity.GetSignatureLen ();
size_t paddingSize = signatureLen & 0x0F; // %16
if (paddingSize > 0) signatureLen += (16 - paddingSize);
boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer, signatureLen), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase4Received, this, boost::bind(&NTCPSession::HandlePhase4Received, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsA)); boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsA));
} }
@@ -317,45 +334,89 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Phase 3 read error: ", ecode.message ()); LogPrint (eLogError, "Phase 3 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 3 received: ", bytes_transferred); LogPrint (eLogDebug, "Phase 3 received: ", bytes_transferred);
m_Decryption.Decrypt ((uint8_t *)&m_Establisher->phase3, sizeof(NTCPPhase3), (uint8_t *)&m_Establisher->phase3); m_Decryption.Decrypt (m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer);
m_RemoteIdentity = m_Establisher->phase3.ident; uint8_t * buf = m_ReceiveBuffer;
uint16_t size = be16toh (*(uint16_t *)buf);
m_RemoteIdentity.FromBuffer (buf + 2, size);
size_t expectedSize = size + 2/*size*/ + 4/*timestamp*/ + m_RemoteIdentity.GetSignatureLen ();
size_t paddingLen = expectedSize & 0x0F;
if (paddingLen) paddingLen = (16 - paddingLen);
if (expectedSize > NTCP_DEFAULT_PHASE3_SIZE)
{
// we need more bytes for Phase3
expectedSize += paddingLen;
LogPrint (eLogDebug, "Wait for ", expectedSize, " more bytes for Phase3");
boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer + NTCP_DEFAULT_PHASE3_SIZE, expectedSize), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase3ExtraReceived, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsB, paddingLen));
}
SignedData s; HandlePhase3 (tsB, paddingLen);
s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (i2p::context.GetRouterInfo ().GetIdentHash (), 32); // ident
s.Insert (m_Establisher->phase3.timestamp); // tsA
s.Insert (tsB); // tsB
if (!s.Verify (m_RemoteIdentity, m_Establisher->phase3.signature))
{
LogPrint ("signature verification failed");
Terminate ();
return;
}
SendPhase4 (tsB);
} }
} }
void NTCPSession::SendPhase4 (uint32_t tsB) void NTCPSession::HandlePhase3ExtraReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB, size_t paddingLen)
{
if (ecode)
{
LogPrint (eLogError, "Phase 3 extra read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
{
LogPrint (eLogDebug, "Phase 3 extra received: ", bytes_transferred);
m_Decryption.Decrypt (m_ReceiveBuffer + NTCP_DEFAULT_PHASE3_SIZE, bytes_transferred, m_ReceiveBuffer+ NTCP_DEFAULT_PHASE3_SIZE);
HandlePhase3 (tsB, paddingLen);
}
}
void NTCPSession::HandlePhase3 (uint32_t tsB, size_t paddingLen)
{
uint8_t * buf = m_ReceiveBuffer + m_RemoteIdentity.GetFullLen () + 2 /*size*/;
uint32_t tsA = *(uint32_t *)buf;
buf += 4;
buf += paddingLen;
SignedData s;
s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (i2p::context.GetRouterInfo ().GetIdentHash (), 32); // ident
s.Insert (tsA); // tsA
s.Insert (tsB); // tsB
if (!s.Verify (m_RemoteIdentity, buf))
{
LogPrint (eLogError, "signature verification failed");
Terminate ();
return;
}
SendPhase4 (tsA, tsB);
}
void NTCPSession::SendPhase4 (uint32_t tsA, uint32_t tsB)
{ {
SignedData s; SignedData s;
s.Insert (m_Establisher->phase1.pubKey, 256); // x s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident
s.Insert (m_Establisher->phase3.timestamp); // tsA s.Insert (tsA); // tsA
s.Insert (tsB); // tsB s.Insert (tsB); // tsB
s.Sign (i2p::context.GetPrivateKeys (), m_Establisher->phase4.signature); auto keys = i2p::context.GetPrivateKeys ();
m_Encryption.Encrypt ((uint8_t *)&m_Establisher->phase4, sizeof(NTCPPhase4), (uint8_t *)&m_Establisher->phase4); auto signatureLen = keys.GetPublic ().GetSignatureLen ();
s.Sign (keys, m_ReceiveBuffer);
size_t paddingSize = signatureLen & 0x0F; // %16
if (paddingSize > 0) signatureLen += (16 - paddingSize);
m_Encryption.Encrypt (m_ReceiveBuffer, signatureLen, m_ReceiveBuffer);
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase4, sizeof (NTCPPhase4)), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (m_ReceiveBuffer, signatureLen), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase4Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); boost::bind(&NTCPSession::HandlePhase4Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
} }
@@ -363,13 +424,13 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Couldn't send Phase 4 message: ", ecode.message ()); LogPrint (eLogWarning, "Couldn't send Phase 4 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 4 sent: ", bytes_transferred); LogPrint (eLogDebug, "Phase 4 sent: ", bytes_transferred);
Connected (); Connected ();
m_ReceiveBufferOffset = 0; m_ReceiveBufferOffset = 0;
m_NextMessage = nullptr; m_NextMessage = nullptr;
@@ -381,7 +442,7 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Phase 4 read error: ", ecode.message ()); LogPrint (eLogError, "Phase 4 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
// this router doesn't like us // this router doesn't like us
@@ -391,8 +452,8 @@ namespace transport
} }
else else
{ {
LogPrint ("Phase 4 received: ", bytes_transferred); LogPrint (eLogDebug, "Phase 4 received: ", bytes_transferred);
m_Decryption.Decrypt((uint8_t *)&m_Establisher->phase4, sizeof(NTCPPhase4), (uint8_t *)&m_Establisher->phase4); m_Decryption.Decrypt(m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer);
// verify signature // verify signature
SignedData s; SignedData s;
@@ -402,9 +463,9 @@ namespace transport
s.Insert (tsA); // tsA s.Insert (tsA); // tsA
s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB
if (!s.Verify (m_RemoteIdentity, m_Establisher->phase4.signature)) if (!s.Verify (m_RemoteIdentity, m_ReceiveBuffer))
{ {
LogPrint ("signature verification failed"); LogPrint (eLogError, "signature verification failed");
Terminate (); Terminate ();
return; return;
} }
@@ -427,7 +488,7 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Read error: ", ecode.message ()); LogPrint (eLogError, "Read error: ", ecode.message ());
//if (ecode != boost::asio::error::operation_aborted) //if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
@@ -472,7 +533,7 @@ namespace transport
// new message // new message
if (dataSize > NTCP_MAX_MESSAGE_SIZE) if (dataSize > NTCP_MAX_MESSAGE_SIZE)
{ {
LogPrint ("NTCP data size ", dataSize, " exceeds max size"); LogPrint (eLogError, "NTCP data size ", dataSize, " exceeds max size");
i2p::DeleteI2NPMessage (m_NextMessage); i2p::DeleteI2NPMessage (m_NextMessage);
m_NextMessage = nullptr; m_NextMessage = nullptr;
return false; return false;
@@ -515,7 +576,7 @@ namespace transport
// regular I2NP // regular I2NP
if (msg->offset < 2) if (msg->offset < 2)
{ {
LogPrint ("Malformed I2NP message"); LogPrint (eLogError, "Malformed I2NP message");
i2p::DeleteI2NPMessage (msg); i2p::DeleteI2NPMessage (msg);
} }
sendBuffer = msg->GetBuffer () - 2; sendBuffer = msg->GetBuffer () - 2;
@@ -549,7 +610,7 @@ namespace transport
i2p::DeleteI2NPMessage (msg); i2p::DeleteI2NPMessage (msg);
if (ecode) if (ecode)
{ {
LogPrint ("Couldn't send msg: ", ecode.message ()); LogPrint (eLogWarning, "Couldn't send msg: ", ecode.message ());
// we shouldn't call Terminate () here, because HandleReceive takes care // we shouldn't call Terminate () here, because HandleReceive takes care
// TODO: 'delete this' statement in Terminate () must be eliminated later // TODO: 'delete this' statement in Terminate () must be eliminated later
// Terminate (); // Terminate ();
@@ -597,8 +658,8 @@ namespace transport
NTCPClient::NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, NTCPClient::NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address,
int port, const i2p::data::RouterInfo& in_RouterInfo): int port, std::shared_ptr<const i2p::data::RouterInfo> in_RouterInfo):
NTCPSession (service, &in_RouterInfo), m_Endpoint (address, port) NTCPSession (service, in_RouterInfo), m_Endpoint (address, port)
{ {
Connect (); Connect ();
} }

View File

@@ -35,34 +35,19 @@ namespace transport
uint8_t filler[12]; uint8_t filler[12];
} encrypted; } encrypted;
}; };
struct NTCPPhase3
{
uint16_t size;
i2p::data::Identity ident;
uint32_t timestamp;
uint8_t padding[15];
uint8_t signature[40];
};
struct NTCPPhase4
{
uint8_t signature[40];
uint8_t padding[8];
};
#pragma pack() #pragma pack()
const size_t NTCP_MAX_MESSAGE_SIZE = 16384; const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
const size_t NTCP_BUFFER_SIZE = 1040; // fits one tunnel message (1028) const size_t NTCP_BUFFER_SIZE = 1040; // fits one tunnel message (1028)
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes
const size_t NTCP_DEFAULT_PHASE3_SIZE = 2/*size*/ + i2p::data::DEFAULT_IDENTITY_SIZE/*387*/ + 4/*ts*/ + 15/*padding*/ + 40/*signature*/; // 428
class NTCPSession: public TransportSession class NTCPSession: public TransportSession
{ {
public: public:
NTCPSession (boost::asio::io_service& service, const i2p::data::RouterInfo * in_RemoteRouter = nullptr); NTCPSession (boost::asio::io_service& service, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr);
~NTCPSession (); ~NTCPSession ();
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
@@ -95,10 +80,12 @@ namespace transport
//server //server
void SendPhase2 (); void SendPhase2 ();
void SendPhase4 (uint32_t tsB); void SendPhase4 (uint32_t tsA, uint32_t tsB);
void HandlePhase1Received (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandlePhase1Received (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandlePhase2Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB); void HandlePhase2Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB);
void HandlePhase3Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB); void HandlePhase3Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB);
void HandlePhase3ExtraReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB, size_t paddingLen);
void HandlePhase3 (uint32_t tsB, size_t paddingLen);
void HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
// common // common
@@ -128,11 +115,10 @@ namespace transport
{ {
NTCPPhase1 phase1; NTCPPhase1 phase1;
NTCPPhase2 phase2; NTCPPhase2 phase2;
NTCPPhase3 phase3;
NTCPPhase4 phase4;
} * m_Establisher; } * m_Establisher;
uint8_t m_ReceiveBuffer[NTCP_BUFFER_SIZE + 16], m_TimeSyncBuffer[16]; i2p::crypto::AESAlignedBuffer<NTCP_BUFFER_SIZE + 16> m_ReceiveBuffer;
i2p::crypto::AESAlignedBuffer<16> m_TimeSyncBuffer;
int m_ReceiveBufferOffset; int m_ReceiveBufferOffset;
i2p::I2NPMessage * m_NextMessage; i2p::I2NPMessage * m_NextMessage;
@@ -146,7 +132,7 @@ namespace transport
{ {
public: public:
NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, int port, const i2p::data::RouterInfo& in_RouterInfo); NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, int port, std::shared_ptr<const i2p::data::RouterInfo> in_RouterInfo);
private: private:

View File

@@ -21,7 +21,7 @@ namespace i2p
{ {
namespace data namespace data
{ {
I2NPMessage * RequestedDestination::CreateRequestMessage (const RouterInfo * router, I2NPMessage * RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router,
const i2p::tunnel::InboundTunnel * replyTunnel) const i2p::tunnel::InboundTunnel * replyTunnel)
{ {
I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination, I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination,
@@ -167,24 +167,27 @@ namespace data
void NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len) void NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len)
{ {
DeleteRequestedDestination (ident); DeleteRequestedDestination (ident);
auto it = m_RouterInfos.find(ident); auto r = FindRouter (ident);
if (it != m_RouterInfos.end ()) if (r)
{ {
auto ts = it->second->GetTimestamp (); auto ts = r->GetTimestamp ();
it->second->Update (buf, len); r->Update (buf, len);
if (it->second->GetTimestamp () > ts) if (r->GetTimestamp () > ts)
LogPrint ("RouterInfo updated"); LogPrint ("RouterInfo updated");
} }
else else
{ {
LogPrint ("New RouterInfo added"); LogPrint ("New RouterInfo added");
auto r = std::make_shared<RouterInfo> (buf, len); auto newRouter = std::make_shared<RouterInfo> (buf, len);
m_RouterInfos[r->GetIdentHash ()] = r; {
if (r->IsFloodfill ()) std::unique_lock<std::mutex> l(m_RouterInfosMutex);
m_RouterInfos[newRouter->GetIdentHash ()] = newRouter;
}
if (newRouter->IsFloodfill ())
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.push_back (r); m_Floodfills.push_back (newRouter);
} }
} }
} }
@@ -209,11 +212,12 @@ namespace data
} }
} }
RouterInfo * NetDb::FindRouter (const IdentHash& ident) const std::shared_ptr<RouterInfo> NetDb::FindRouter (const IdentHash& ident) const
{ {
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
auto it = m_RouterInfos.find (ident); auto it = m_RouterInfos.find (ident);
if (it != m_RouterInfos.end ()) if (it != m_RouterInfos.end ())
return it->second.get (); return it->second;
else else
return nullptr; return nullptr;
} }
@@ -354,18 +358,36 @@ namespace data
if (it.second->IsUnreachable ()) if (it.second->IsUnreachable ())
{ {
// delete RI file
if (boost::filesystem::exists (GetFilePath (fullDirectory, it.second.get ()))) if (boost::filesystem::exists (GetFilePath (fullDirectory, it.second.get ())))
{ {
boost::filesystem::remove (GetFilePath (fullDirectory, it.second.get ())); boost::filesystem::remove (GetFilePath (fullDirectory, it.second.get ()));
deletedCount++; deletedCount++;
} }
// delete from floodfills list
if (it.second->IsFloodfill ())
{
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.remove (it.second);
}
} }
} }
} }
if (count > 0) if (count > 0)
LogPrint (count," new/updated routers saved"); LogPrint (count," new/updated routers saved");
if (deletedCount > 0) if (deletedCount > 0)
{
LogPrint (deletedCount," routers deleted"); LogPrint (deletedCount," routers deleted");
// clean up RouterInfos table
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
{
if (it->second->IsUnreachable ())
it = m_RouterInfos.erase (it);
else
it++;
}
}
} }
void NetDb::RequestDestination (const IdentHash& destination, bool isLeaseSet, i2p::tunnel::TunnelPool * pool) void NetDb::RequestDestination (const IdentHash& destination, bool isLeaseSet, i2p::tunnel::TunnelPool * pool)
@@ -611,7 +633,7 @@ namespace data
LogPrint ("Requested RouterInfo ", key, " found"); LogPrint ("Requested RouterInfo ", key, " found");
router->LoadBuffer (); router->LoadBuffer ();
if (router->GetBuffer ()) if (router->GetBuffer ())
replyMsg = CreateDatabaseStoreMsg (router); replyMsg = CreateDatabaseStoreMsg (router.get ());
} }
} }
if (!replyMsg) if (!replyMsg)
@@ -633,7 +655,7 @@ namespace data
excludedRouters.insert (excluded); excludedRouters.insert (excluded);
excluded += 32; excluded += 32;
} }
replyMsg = CreateDatabaseSearchReply (buf, GetClosestFloodfill (buf, excludedRouters)); replyMsg = CreateDatabaseSearchReply (buf, GetClosestFloodfill (buf, excludedRouters).get ());
} }
else else
excluded += numExcluded*32; // we don't care about exluded excluded += numExcluded*32; // we don't care about exluded
@@ -697,9 +719,9 @@ namespace data
rnd.GenerateBlock (randomHash, 32); rnd.GenerateBlock (randomHash, 32);
RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), false, true, exploratoryPool); RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), false, true, exploratoryPool);
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ()); auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
if (floodfill && !floodfills.count (floodfill)) // request floodfill only once if (floodfill && !floodfills.count (floodfill.get ())) // request floodfill only once
{ {
floodfills.insert (floodfill); floodfills.insert (floodfill.get ());
if (throughTunnels) if (throughTunnels)
{ {
msgs.push_back (i2p::tunnel::TunnelMessageBlock msgs.push_back (i2p::tunnel::TunnelMessageBlock
@@ -787,22 +809,22 @@ namespace data
}); });
} }
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (const RouterInfo * compatibleWith) const std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const
{ {
return GetRandomRouter ( return GetRandomRouter (
[compatibleWith](std::shared_ptr<const RouterInfo> router)->bool [compatibleWith](std::shared_ptr<const RouterInfo> router)->bool
{ {
return !router->IsHidden () && router.get () != compatibleWith && return !router->IsHidden () && router != compatibleWith &&
router->IsCompatible (*compatibleWith); router->IsCompatible (*compatibleWith);
}); });
} }
std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (const RouterInfo * compatibleWith) const std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const
{ {
return GetRandomRouter ( return GetRandomRouter (
[compatibleWith](std::shared_ptr<const RouterInfo> router)->bool [compatibleWith](std::shared_ptr<const RouterInfo> router)->bool
{ {
return !router->IsHidden () && router.get () != compatibleWith && return !router->IsHidden () && router != compatibleWith &&
router->IsCompatible (*compatibleWith) && (router->GetCaps () & RouterInfo::eHighBandwidth); router->IsCompatible (*compatibleWith) && (router->GetCaps () & RouterInfo::eHighBandwidth);
}); });
} }
@@ -815,6 +837,7 @@ namespace data
for (int j = 0; j < 2; j++) for (int j = 0; j < 2; j++)
{ {
uint32_t i = 0; uint32_t i = 0;
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
for (auto it: m_RouterInfos) for (auto it: m_RouterInfos)
{ {
if (i >= ind) if (i >= ind)
@@ -836,10 +859,10 @@ namespace data
if (msg) m_Queue.Put (msg); if (msg) m_Queue.Put (msg);
} }
const RouterInfo * NetDb::GetClosestFloodfill (const IdentHash& destination, std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination,
const std::set<IdentHash>& excluded) const const std::set<IdentHash>& excluded) const
{ {
RouterInfo * r = nullptr; std::shared_ptr<const RouterInfo> r;
XORMetric minMetric; XORMetric minMetric;
IdentHash destKey = CreateRoutingKey (destination); IdentHash destKey = CreateRoutingKey (destination);
minMetric.SetMax (); minMetric.SetMax ();
@@ -852,7 +875,7 @@ namespace data
if (m < minMetric) if (m < minMetric)
{ {
minMetric = m; minMetric = m;
r = it.get (); r = it;
} }
} }
} }

21
NetDb.h
View File

@@ -4,7 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <set> #include <set>
#include <map> #include <map>
#include <vector> #include <list>
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
@@ -27,19 +27,19 @@ namespace data
RequestedDestination (const IdentHash& destination, bool isLeaseSet, RequestedDestination (const IdentHash& destination, bool isLeaseSet,
bool isExploratory = false, i2p::tunnel::TunnelPool * pool = nullptr): bool isExploratory = false, i2p::tunnel::TunnelPool * pool = nullptr):
m_Destination (destination), m_IsLeaseSet (isLeaseSet), m_IsExploratory (isExploratory), m_Destination (destination), m_IsLeaseSet (isLeaseSet), m_IsExploratory (isExploratory),
m_Pool (pool), m_LastRouter (nullptr), m_CreationTime (0) {}; m_Pool (pool), m_CreationTime (0) {};
const IdentHash& GetDestination () const { return m_Destination; }; const IdentHash& GetDestination () const { return m_Destination; };
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); }; int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; }; const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; };
void ClearExcludedPeers (); void ClearExcludedPeers ();
const RouterInfo * GetLastRouter () const { return m_LastRouter; }; std::shared_ptr<const RouterInfo> GetLastRouter () const { return m_LastRouter; };
i2p::tunnel::TunnelPool * GetTunnelPool () { return m_Pool; }; i2p::tunnel::TunnelPool * GetTunnelPool () { return m_Pool; };
bool IsExploratory () const { return m_IsExploratory; }; bool IsExploratory () const { return m_IsExploratory; };
bool IsLeaseSet () const { return m_IsLeaseSet; }; bool IsLeaseSet () const { return m_IsLeaseSet; };
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); }; bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
uint64_t GetCreationTime () const { return m_CreationTime; }; uint64_t GetCreationTime () const { return m_CreationTime; };
I2NPMessage * CreateRequestMessage (const RouterInfo * router, const i2p::tunnel::InboundTunnel * replyTunnel); I2NPMessage * CreateRequestMessage (std::shared_ptr<const RouterInfo>, const i2p::tunnel::InboundTunnel * replyTunnel);
I2NPMessage * CreateRequestMessage (const IdentHash& floodfill); I2NPMessage * CreateRequestMessage (const IdentHash& floodfill);
private: private:
@@ -48,7 +48,7 @@ namespace data
bool m_IsLeaseSet, m_IsExploratory; bool m_IsLeaseSet, m_IsExploratory;
i2p::tunnel::TunnelPool * m_Pool; i2p::tunnel::TunnelPool * m_Pool;
std::set<IdentHash> m_ExcludedPeers; std::set<IdentHash> m_ExcludedPeers;
const RouterInfo * m_LastRouter; std::shared_ptr<const RouterInfo> m_LastRouter;
uint64_t m_CreationTime; uint64_t m_CreationTime;
}; };
@@ -64,7 +64,7 @@ namespace data
void AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len); void AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len);
void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, i2p::tunnel::InboundTunnel * from); void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, i2p::tunnel::InboundTunnel * from);
RouterInfo * FindRouter (const IdentHash& ident) const; std::shared_ptr<RouterInfo> FindRouter (const IdentHash& ident) const;
LeaseSet * FindLeaseSet (const IdentHash& destination) const; LeaseSet * FindLeaseSet (const IdentHash& destination) const;
void PublishLeaseSet (const LeaseSet * leaseSet, i2p::tunnel::TunnelPool * pool); void PublishLeaseSet (const LeaseSet * leaseSet, i2p::tunnel::TunnelPool * pool);
@@ -76,8 +76,8 @@ namespace data
void HandleDatabaseLookupMsg (I2NPMessage * msg); void HandleDatabaseLookupMsg (I2NPMessage * msg);
std::shared_ptr<const RouterInfo> GetRandomRouter () const; std::shared_ptr<const RouterInfo> GetRandomRouter () const;
std::shared_ptr<const RouterInfo> GetRandomRouter (const RouterInfo * compatibleWith) const; std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (const RouterInfo * compatibleWith) const; std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
void SetUnreachable (const IdentHash& ident, bool unreachable); void SetUnreachable (const IdentHash& ident, bool unreachable);
void PostI2NPMsg (I2NPMessage * msg); void PostI2NPMsg (I2NPMessage * msg);
@@ -95,7 +95,7 @@ namespace data
void Run (); // exploratory thread void Run (); // exploratory thread
void Explore (int numDestinations); void Explore (int numDestinations);
void Publish (); void Publish ();
const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
void ManageLeaseSets (); void ManageLeaseSets ();
RequestedDestination * CreateRequestedDestination (const IdentHash& dest, RequestedDestination * CreateRequestedDestination (const IdentHash& dest,
@@ -109,9 +109,10 @@ namespace data
private: private:
std::map<IdentHash, LeaseSet *> m_LeaseSets; std::map<IdentHash, LeaseSet *> m_LeaseSets;
mutable std::mutex m_RouterInfosMutex;
std::map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos; std::map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
mutable std::mutex m_FloodfillsMutex; mutable std::mutex m_FloodfillsMutex;
std::vector<std::shared_ptr<RouterInfo> > m_Floodfills; std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
std::mutex m_RequestedDestinationsMutex; std::mutex m_RequestedDestinationsMutex;
std::map<IdentHash, RequestedDestination *> m_RequestedDestinations; std::map<IdentHash, RequestedDestination *> m_RequestedDestinations;

108
SAM.cpp
View File

@@ -3,7 +3,6 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#include <stdlib.h> #include <stdlib.h>
#endif #endif
#include <boost/bind.hpp>
#include "base64.h" #include "base64.h"
#include "Identity.h" #include "Identity.h"
#include "Log.h" #include "Log.h"
@@ -25,22 +24,23 @@ namespace client
SAMSocket::~SAMSocket () SAMSocket::~SAMSocket ()
{ {
if (m_Stream) Terminate ();
{
m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
}
} }
void SAMSocket::Terminate () void SAMSocket::CloseStream ()
{ {
if (m_Stream) if (m_Stream)
{ {
m_Stream->Close (); m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream); i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr; m_Stream.reset ();
} }
}
void SAMSocket::Terminate ()
{
CloseStream ();
switch (m_SocketType) switch (m_SocketType)
{ {
case eSAMSocketTypeSession: case eSAMSocketTypeSession:
@@ -49,14 +49,14 @@ namespace client
case eSAMSocketTypeStream: case eSAMSocketTypeStream:
{ {
if (m_Session) if (m_Session)
m_Session->sockets.remove (this); m_Session->sockets.remove (shared_from_this ());
break; break;
} }
case eSAMSocketTypeAcceptor: case eSAMSocketTypeAcceptor:
{ {
if (m_Session) if (m_Session)
{ {
m_Session->sockets.remove (this); m_Session->sockets.remove (shared_from_this ());
m_Session->localDestination->StopAcceptingStreams (); m_Session->localDestination->StopAcceptingStreams ();
} }
break; break;
@@ -64,15 +64,15 @@ namespace client
default: default:
; ;
} }
m_SocketType = eSAMSocketTypeTerminated;
m_Socket.close (); m_Socket.close ();
// delete this;
} }
void SAMSocket::ReceiveHandshake () void SAMSocket::ReceiveHandshake ()
{ {
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
boost::bind(&SAMSocket::HandleHandshakeReceived, this, std::bind(&SAMSocket::HandleHandshakeReceived, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::placeholders::_1, std::placeholders::_2));
} }
void SAMSocket::HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) void SAMSocket::HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@@ -91,8 +91,8 @@ namespace client
{ {
// TODO: check version // TODO: check version
boost::asio::async_write (m_Socket, boost::asio::buffer (SAM_HANDSHAKE_REPLY, strlen (SAM_HANDSHAKE_REPLY)), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (SAM_HANDSHAKE_REPLY, strlen (SAM_HANDSHAKE_REPLY)), boost::asio::transfer_all (),
boost::bind(&SAMSocket::HandleHandshakeReplySent, this, std::bind(&SAMSocket::HandleHandshakeReplySent, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::placeholders::_1, std::placeholders::_2));
} }
else else
{ {
@@ -113,8 +113,8 @@ namespace client
else else
{ {
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
boost::bind(&SAMSocket::HandleMessage, this, std::bind(&SAMSocket::HandleMessage, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::placeholders::_1, std::placeholders::_2));
} }
} }
@@ -122,8 +122,8 @@ namespace client
{ {
if (!m_IsSilent || m_SocketType == eSAMSocketTypeAcceptor) if (!m_IsSilent || m_SocketType == eSAMSocketTypeAcceptor)
boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (),
boost::bind(&SAMSocket::HandleMessageReplySent, this, std::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, close)); std::placeholders::_1, std::placeholders::_2, close));
else else
{ {
if (close) if (close)
@@ -228,7 +228,7 @@ namespace client
if (style == SAM_VALUE_DATAGRAM) if (style == SAM_VALUE_DATAGRAM)
{ {
auto dest = m_Session->localDestination->CreateDatagramDestination (); auto dest = m_Session->localDestination->CreateDatagramDestination ();
dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, this, dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (),
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
} }
SendSessionCreateReplyOk (); SendSessionCreateReplyOk ();
@@ -236,8 +236,8 @@ namespace client
else else
{ {
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL)); m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
m_Timer.async_wait (boost::bind (&SAMSocket::HandleSessionReadinessCheckTimer, m_Timer.async_wait (std::bind (&SAMSocket::HandleSessionReadinessCheckTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
} }
else else
@@ -253,8 +253,8 @@ namespace client
else else
{ {
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL)); m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
m_Timer.async_wait (boost::bind (&SAMSocket::HandleSessionReadinessCheckTimer, m_Timer.async_wait (std::bind (&SAMSocket::HandleSessionReadinessCheckTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
} }
} }
@@ -298,8 +298,8 @@ namespace client
{ {
i2p::data::netdb.RequestDestination (dest.GetIdentHash (), true, m_Session->localDestination->GetTunnelPool ()); i2p::data::netdb.RequestDestination (dest.GetIdentHash (), true, m_Session->localDestination->GetTunnelPool ());
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_CONNECT_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(SAM_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SAMSocket::HandleStreamDestinationRequestTimer, m_Timer.async_wait (std::bind (&SAMSocket::HandleStreamDestinationRequestTimer,
this, boost::asio::placeholders::error, dest.GetIdentHash ())); shared_from_this (), std::placeholders::_1, dest.GetIdentHash ()));
} }
} }
else else
@@ -309,7 +309,7 @@ namespace client
void SAMSocket::Connect (const i2p::data::LeaseSet& remote) void SAMSocket::Connect (const i2p::data::LeaseSet& remote)
{ {
m_SocketType = eSAMSocketTypeStream; m_SocketType = eSAMSocketTypeStream;
m_Session->sockets.push_back (this); m_Session->sockets.push_back (shared_from_this ());
m_Stream = m_Session->localDestination->CreateStream (remote); m_Stream = m_Session->localDestination->CreateStream (remote);
m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect
I2PReceive (); I2PReceive ();
@@ -366,8 +366,8 @@ namespace client
if (!m_Session->localDestination->IsAcceptingStreams ()) if (!m_Session->localDestination->IsAcceptingStreams ())
{ {
m_SocketType = eSAMSocketTypeAcceptor; m_SocketType = eSAMSocketTypeAcceptor;
m_Session->sockets.push_back (this); m_Session->sockets.push_back (shared_from_this ());
m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, this, std::placeholders::_1)); m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1));
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
} }
else else
@@ -421,8 +421,8 @@ namespace client
{ {
i2p::data::netdb.RequestDestination (ident, true, m_Session->localDestination->GetTunnelPool ()); i2p::data::netdb.RequestDestination (ident, true, m_Session->localDestination->GetTunnelPool ());
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_NAMING_LOOKUP_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(SAM_NAMING_LOOKUP_TIMEOUT));
m_Timer.async_wait (boost::bind (&SAMSocket::HandleNamingLookupDestinationRequestTimer, m_Timer.async_wait (std::bind (&SAMSocket::HandleNamingLookupDestinationRequestTimer,
this, boost::asio::placeholders::error, ident)); shared_from_this (), std::placeholders::_1, ident));
} }
} }
else else
@@ -474,8 +474,8 @@ namespace client
void SAMSocket::Receive () void SAMSocket::Receive ()
{ {
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
boost::bind((m_SocketType == eSAMSocketTypeSession) ? &SAMSocket::HandleMessage : &SAMSocket::HandleReceived, std::bind((m_SocketType == eSAMSocketTypeSession) ? &SAMSocket::HandleMessage : &SAMSocket::HandleReceived,
this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); shared_from_this (), std::placeholders::_1, std::placeholders::_2));
} }
void SAMSocket::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) void SAMSocket::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@@ -498,8 +498,8 @@ namespace client
{ {
if (m_Stream) if (m_Stream)
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE), m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE),
boost::bind (&SAMSocket::HandleI2PReceive, this, std::bind (&SAMSocket::HandleI2PReceive, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred), std::placeholders::_1, std::placeholders::_2),
SAM_SOCKET_CONNECTION_MAX_IDLE); SAM_SOCKET_CONNECTION_MAX_IDLE);
} }
@@ -514,7 +514,7 @@ namespace client
else else
{ {
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred),
boost::bind (&SAMSocket::HandleWriteI2PData, this, boost::asio::placeholders::error)); std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1));
} }
} }
@@ -530,7 +530,7 @@ namespace client
I2PReceive (); I2PReceive ();
} }
void SAMSocket::HandleI2PAccept (i2p::stream::Stream * stream) void SAMSocket::HandleI2PAccept (std::shared_ptr<i2p::stream::Stream> stream)
{ {
if (stream) if (stream)
{ {
@@ -567,7 +567,7 @@ namespace client
{ {
memcpy (m_StreamBuffer + l2, buf, len); memcpy (m_StreamBuffer + l2, buf, len);
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, len + l2), boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, len + l2),
boost::bind (&SAMSocket::HandleWriteI2PData, this, boost::asio::placeholders::error)); std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1));
} }
else else
LogPrint (eLogWarning, "Datagram size ", len," exceeds buffer"); LogPrint (eLogWarning, "Datagram size ", len," exceeds buffer");
@@ -576,15 +576,13 @@ namespace client
SAMBridge::SAMBridge (int port): SAMBridge::SAMBridge (int port):
m_IsRunning (false), m_Thread (nullptr), m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)), m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
m_DatagramEndpoint (boost::asio::ip::udp::v4 (), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint), m_DatagramEndpoint (boost::asio::ip::udp::v4 (), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint)
m_NewSocket (nullptr)
{ {
} }
SAMBridge::~SAMBridge () SAMBridge::~SAMBridge ()
{ {
Stop (); Stop ();
delete m_NewSocket;
} }
void SAMBridge::Start () void SAMBridge::Start ()
@@ -624,24 +622,20 @@ namespace client
void SAMBridge::Accept () void SAMBridge::Accept ()
{ {
m_NewSocket = new SAMSocket (*this); auto newSocket = std::make_shared<SAMSocket> (*this);
m_Acceptor.async_accept (m_NewSocket->GetSocket (), boost::bind (&SAMBridge::HandleAccept, this, m_Acceptor.async_accept (newSocket->GetSocket (), std::bind (&SAMBridge::HandleAccept, this,
boost::asio::placeholders::error)); std::placeholders::_1, newSocket));
} }
void SAMBridge::HandleAccept(const boost::system::error_code& ecode) void SAMBridge::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<SAMSocket> socket)
{ {
if (!ecode) if (!ecode)
{ {
LogPrint ("New SAM connection from ", m_NewSocket->GetSocket ().remote_endpoint ()); LogPrint ("New SAM connection from ", socket->GetSocket ().remote_endpoint ());
m_NewSocket->ReceiveHandshake (); socket->ReceiveHandshake ();
} }
else else
{
LogPrint ("SAM accept error: ", ecode.message ()); LogPrint ("SAM accept error: ", ecode.message ());
delete m_NewSocket;
m_NewSocket = nullptr;
}
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Accept (); Accept ();
@@ -680,8 +674,8 @@ namespace client
auto it = m_Sessions.find (id); auto it = m_Sessions.find (id);
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
{ {
for (auto it1 : it->second.sockets) for (auto it1: it->second.sockets)
delete it1; it1->CloseStream ();
it->second.sockets.clear (); it->second.sockets.clear ();
it->second.localDestination->Stop (); it->second.localDestination->Stop ();
m_Sessions.erase (it); m_Sessions.erase (it);
@@ -702,7 +696,7 @@ namespace client
m_DatagramSocket.async_receive_from ( m_DatagramSocket.async_receive_from (
boost::asio::buffer (m_DatagramReceiveBuffer, i2p::datagram::MAX_DATAGRAM_SIZE), boost::asio::buffer (m_DatagramReceiveBuffer, i2p::datagram::MAX_DATAGRAM_SIZE),
m_SenderEndpoint, m_SenderEndpoint,
boost::bind (&SAMBridge::HandleReceivedDatagram, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::bind (&SAMBridge::HandleReceivedDatagram, this, std::placeholders::_1, std::placeholders::_2));
} }
void SAMBridge::HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred) void SAMBridge::HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred)

20
SAM.h
View File

@@ -7,6 +7,7 @@
#include <list> #include <list>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <memory>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "Identity.h" #include "Identity.h"
#include "LeaseSet.h" #include "LeaseSet.h"
@@ -39,7 +40,7 @@ namespace client
const char SAM_DEST_REPLY_I2P_ERROR[] = "DEST REPLY RESULT=I2P_ERROR\n"; const char SAM_DEST_REPLY_I2P_ERROR[] = "DEST REPLY RESULT=I2P_ERROR\n";
const char SAM_NAMING_LOOKUP[] = "NAMING LOOKUP"; const char SAM_NAMING_LOOKUP[] = "NAMING LOOKUP";
const char SAM_NAMING_REPLY[] = "NAMING REPLY RESULT=OK NAME=ME VALUE=%s\n"; const char SAM_NAMING_REPLY[] = "NAMING REPLY RESULT=OK NAME=ME VALUE=%s\n";
const char SAM_DATAGRAM_RECEIVED[] = "DATAGRAM_RECEIVED DESTINATION=%s SIZE=%i\n"; const char SAM_DATAGRAM_RECEIVED[] = "DATAGRAM_RECEIVED DESTINATION=%s SIZE=%lu\n";
const char SAM_NAMING_REPLY_INVALID_KEY[] = "NAMING REPLY RESULT=INVALID_KEY NAME=%s\n"; const char SAM_NAMING_REPLY_INVALID_KEY[] = "NAMING REPLY RESULT=INVALID_KEY NAME=%s\n";
const char SAM_NAMING_REPLY_KEY_NOT_FOUND[] = "NAMING REPLY RESULT=INVALID_KEY_NOT_FOUND NAME=%s\n"; const char SAM_NAMING_REPLY_KEY_NOT_FOUND[] = "NAMING REPLY RESULT=INVALID_KEY_NOT_FOUND NAME=%s\n";
const char SAM_PARAM_STYLE[] = "STYLE"; const char SAM_PARAM_STYLE[] = "STYLE";
@@ -59,18 +60,20 @@ namespace client
eSAMSocketTypeUnknown, eSAMSocketTypeUnknown,
eSAMSocketTypeSession, eSAMSocketTypeSession,
eSAMSocketTypeStream, eSAMSocketTypeStream,
eSAMSocketTypeAcceptor eSAMSocketTypeAcceptor,
eSAMSocketTypeTerminated
}; };
class SAMBridge; class SAMBridge;
class SAMSession; class SAMSession;
class SAMSocket class SAMSocket: public std::enable_shared_from_this<SAMSocket>
{ {
public: public:
SAMSocket (SAMBridge& owner); SAMSocket (SAMBridge& owner);
~SAMSocket (); ~SAMSocket ();
void CloseStream (); // TODO: implement it better
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
void ReceiveHandshake (); void ReceiveHandshake ();
@@ -87,7 +90,7 @@ namespace client
void I2PReceive (); void I2PReceive ();
void HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleI2PAccept (i2p::stream::Stream * stream); void HandleI2PAccept (std::shared_ptr<i2p::stream::Stream> stream);
void HandleWriteI2PData (const boost::system::error_code& ecode); void HandleWriteI2PData (const boost::system::error_code& ecode);
void HandleI2PDatagramReceive (const i2p::data::IdentityEx& ident, const uint8_t * buf, size_t len); void HandleI2PDatagramReceive (const i2p::data::IdentityEx& ident, const uint8_t * buf, size_t len);
@@ -115,14 +118,14 @@ namespace client
SAMSocketType m_SocketType; SAMSocketType m_SocketType;
std::string m_ID; // nickname std::string m_ID; // nickname
bool m_IsSilent; bool m_IsSilent;
i2p::stream::Stream * m_Stream; std::shared_ptr<i2p::stream::Stream> m_Stream;
SAMSession * m_Session; SAMSession * m_Session;
}; };
struct SAMSession struct SAMSession
{ {
ClientDestination * localDestination; ClientDestination * localDestination;
std::list<SAMSocket *> sockets; std::list<std::shared_ptr<SAMSocket> > sockets;
}; };
class SAMBridge class SAMBridge
@@ -145,7 +148,7 @@ namespace client
void Run (); void Run ();
void Accept (); void Accept ();
void HandleAccept(const boost::system::error_code& ecode); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<SAMSocket> socket);
void ReceiveDatagram (); void ReceiveDatagram ();
void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred);
@@ -158,7 +161,6 @@ namespace client
boost::asio::ip::tcp::acceptor m_Acceptor; boost::asio::ip::tcp::acceptor m_Acceptor;
boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint; boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint;
boost::asio::ip::udp::socket m_DatagramSocket; boost::asio::ip::udp::socket m_DatagramSocket;
SAMSocket * m_NewSocket;
std::mutex m_SessionsMutex; std::mutex m_SessionsMutex;
std::map<std::string, SAMSession> m_Sessions; std::map<std::string, SAMSession> m_Sessions;
uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1]; uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1];

View File

@@ -77,8 +77,7 @@ namespace proxy
{ {
if (m_stream) { if (m_stream) {
LogPrint("--- socks4a close stream"); LogPrint("--- socks4a close stream");
delete m_stream; m_stream.reset ();
m_stream = nullptr;
} }
} }

View File

@@ -5,7 +5,7 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <vector> #include <vector>
#include <mutex> #include <mutex>
#include <memory>
#include "Identity.h" #include "Identity.h"
#include "Streaming.h" #include "Streaming.h"
@@ -47,7 +47,7 @@ namespace proxy
boost::asio::io_service * m_ios; boost::asio::io_service * m_ios;
boost::asio::ip::tcp::socket * m_sock; boost::asio::ip::tcp::socket * m_sock;
boost::asio::deadline_timer m_ls_timer; boost::asio::deadline_timer m_ls_timer;
i2p::stream::Stream * m_stream; std::shared_ptr<i2p::stream::Stream> m_stream;
i2p::data::LeaseSet * m_ls; i2p::data::LeaseSet * m_ls;
i2p::data::IdentHash m_dest; i2p::data::IdentHash m_dest;
state m_state; state m_state;

54
SSU.cpp
View File

@@ -27,17 +27,15 @@ namespace transport
SSUServer::~SSUServer () SSUServer::~SSUServer ()
{ {
for (auto it: m_Sessions)
delete it.second;
} }
void SSUServer::Start () void SSUServer::Start ()
{ {
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&SSUServer::Run, this)); m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
m_Service.post (boost::bind (&SSUServer::Receive, this)); m_Service.post (std::bind (&SSUServer::Receive, this));
if (context.SupportsV6 ()) if (context.SupportsV6 ())
m_Service.post (boost::bind (&SSUServer::ReceiveV6, this)); m_Service.post (std::bind (&SSUServer::ReceiveV6, this));
if (i2p::context.IsUnreachable ()) if (i2p::context.IsUnreachable ())
ScheduleIntroducersUpdateTimer (); ScheduleIntroducersUpdateTimer ();
} }
@@ -76,7 +74,7 @@ namespace transport
m_Relays[tag] = relay; m_Relays[tag] = relay;
} }
SSUSession * SSUServer::FindRelaySession (uint32_t tag) std::shared_ptr<SSUSession> SSUServer::FindRelaySession (uint32_t tag)
{ {
auto it = m_Relays.find (tag); auto it = m_Relays.find (tag);
if (it != m_Relays.end ()) if (it != m_Relays.end ())
@@ -128,20 +126,21 @@ namespace transport
void SSUServer::HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred) void SSUServer::HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred)
{ {
SSUSession * session = nullptr; std::shared_ptr<SSUSession> session;
auto it = m_Sessions.find (from); auto it = m_Sessions.find (from);
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
session = it->second; session = it->second;
if (!session) if (!session)
{ {
session = new SSUSession (*this, from); session = std::make_shared<SSUSession> (*this, from);
session->WaitForConnect ();
m_Sessions[from] = session; m_Sessions[from] = session;
LogPrint ("New SSU session from ", from.address ().to_string (), ":", from.port (), " created"); LogPrint ("New SSU session from ", from.address ().to_string (), ":", from.port (), " created");
} }
session->ProcessNextMessage (buf, bytes_transferred, from); session->ProcessNextMessage (buf, bytes_transferred, from);
} }
SSUSession * SSUServer::FindSession (const i2p::data::RouterInfo * router) std::shared_ptr<SSUSession> SSUServer::FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const
{ {
if (!router) return nullptr; if (!router) return nullptr;
auto address = router->GetSSUAddress (true); // v4 only auto address = router->GetSSUAddress (true); // v4 only
@@ -155,7 +154,7 @@ namespace transport
return FindSession (boost::asio::ip::udp::endpoint (address->host, address->port)); return FindSession (boost::asio::ip::udp::endpoint (address->host, address->port));
} }
SSUSession * SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) std::shared_ptr<SSUSession> SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const
{ {
auto it = m_Sessions.find (e); auto it = m_Sessions.find (e);
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
@@ -164,9 +163,9 @@ namespace transport
return nullptr; return nullptr;
} }
SSUSession * SSUServer::GetSession (const i2p::data::RouterInfo * router, bool peerTest) std::shared_ptr<SSUSession> SSUServer::GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
{ {
SSUSession * session = nullptr; std::shared_ptr<SSUSession> session;
if (router) if (router)
{ {
auto address = router->GetSSUAddress (!context.SupportsV6 ()); auto address = router->GetSSUAddress (!context.SupportsV6 ());
@@ -179,7 +178,7 @@ namespace transport
else else
{ {
// otherwise create new session // otherwise create new session
session = new SSUSession (*this, remoteEndpoint, router, peerTest); session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
m_Sessions[remoteEndpoint] = session; m_Sessions[remoteEndpoint] = session;
if (!router->UsesIntroducer ()) if (!router->UsesIntroducer ())
@@ -195,7 +194,7 @@ namespace transport
int numIntroducers = address->introducers.size (); int numIntroducers = address->introducers.size ();
if (numIntroducers > 0) if (numIntroducers > 0)
{ {
SSUSession * introducerSession = nullptr; std::shared_ptr<SSUSession> introducerSession;
const i2p::data::RouterInfo::Introducer * introducer = nullptr; const i2p::data::RouterInfo::Introducer * introducer = nullptr;
// we might have a session to introducer already // we might have a session to introducer already
for (int i = 0; i < numIntroducers; i++) for (int i = 0; i < numIntroducers; i++)
@@ -216,7 +215,7 @@ namespace transport
LogPrint ("Creating new session to introducer"); LogPrint ("Creating new session to introducer");
introducer = &(address->introducers[0]); // TODO: introducer = &(address->introducers[0]); // TODO:
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort); boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
introducerSession = new SSUSession (*this, introducerEndpoint, router); introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
m_Sessions[introducerEndpoint] = introducerSession; m_Sessions[introducerEndpoint] = introducerSession;
} }
// introduce // introduce
@@ -231,8 +230,7 @@ namespace transport
{ {
LogPrint (eLogWarning, "Can't connect to unreachable router. No introducers presented"); LogPrint (eLogWarning, "Can't connect to unreachable router. No introducers presented");
m_Sessions.erase (remoteEndpoint); m_Sessions.erase (remoteEndpoint);
delete session; session.reset ();
session = nullptr;
} }
} }
} }
@@ -243,30 +241,26 @@ namespace transport
return session; return session;
} }
void SSUServer::DeleteSession (SSUSession * session) void SSUServer::DeleteSession (std::shared_ptr<SSUSession> session)
{ {
if (session) if (session)
{ {
session->Close (); session->Close ();
m_Sessions.erase (session->GetRemoteEndpoint ()); m_Sessions.erase (session->GetRemoteEndpoint ());
delete session;
} }
} }
void SSUServer::DeleteAllSessions () void SSUServer::DeleteAllSessions ()
{ {
for (auto it: m_Sessions) for (auto it: m_Sessions)
{
it.second->Close (); it.second->Close ();
delete it.second;
}
m_Sessions.clear (); m_Sessions.clear ();
} }
template<typename Filter> template<typename Filter>
SSUSession * SSUServer::GetRandomSession (Filter filter) std::shared_ptr<SSUSession> SSUServer::GetRandomSession (Filter filter)
{ {
std::vector<SSUSession *> filteredSessions; std::vector<std::shared_ptr<SSUSession> > filteredSessions;
for (auto s :m_Sessions) for (auto s :m_Sessions)
if (filter (s.second)) filteredSessions.push_back (s.second); if (filter (s.second)) filteredSessions.push_back (s.second);
if (filteredSessions.size () > 0) if (filteredSessions.size () > 0)
@@ -277,10 +271,10 @@ namespace transport
return nullptr; return nullptr;
} }
SSUSession * SSUServer::GetRandomEstablishedSession (const SSUSession * excluded) std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedSession (std::shared_ptr<const SSUSession> excluded)
{ {
return GetRandomSession ( return GetRandomSession (
[excluded](SSUSession * session)->bool [excluded](std::shared_ptr<SSUSession> session)->bool
{ {
return session->GetState () == eSessionStateEstablished && return session->GetState () == eSessionStateEstablished &&
session != excluded; session != excluded;
@@ -295,16 +289,16 @@ namespace transport
for (int i = 0; i < maxNumIntroducers; i++) for (int i = 0; i < maxNumIntroducers; i++)
{ {
auto session = GetRandomSession ( auto session = GetRandomSession (
[&ret, ts](SSUSession * session)->bool [&ret, ts](std::shared_ptr<SSUSession> session)->bool
{ {
return session->GetRelayTag () && !ret.count (session) && return session->GetRelayTag () && !ret.count (session.get ()) &&
session->GetState () == eSessionStateEstablished && session->GetState () == eSessionStateEstablished &&
ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION; ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION;
} }
); );
if (session) if (session)
{ {
ret.insert (session); ret.insert (session.get ());
break; break;
} }
} }
@@ -314,8 +308,8 @@ namespace transport
void SSUServer::ScheduleIntroducersUpdateTimer () void SSUServer::ScheduleIntroducersUpdateTimer ()
{ {
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL)); m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL));
m_IntroducersUpdateTimer.async_wait (boost::bind (&SSUServer::HandleIntroducersUpdateTimer, m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
this, boost::asio::placeholders::error)); this, std::placeholders::_1));
} }
void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode) void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode)

16
SSU.h
View File

@@ -31,18 +31,18 @@ namespace transport
~SSUServer (); ~SSUServer ();
void Start (); void Start ();
void Stop (); void Stop ();
SSUSession * GetSession (const i2p::data::RouterInfo * router, bool peerTest = false); std::shared_ptr<SSUSession> GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
SSUSession * FindSession (const i2p::data::RouterInfo * router); std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const;
SSUSession * FindSession (const boost::asio::ip::udp::endpoint& e); std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const;
SSUSession * GetRandomEstablishedSession (const SSUSession * excluded); std::shared_ptr<SSUSession> GetRandomEstablishedSession (std::shared_ptr<const SSUSession> excluded);
void DeleteSession (SSUSession * session); void DeleteSession (std::shared_ptr<SSUSession> session);
void DeleteAllSessions (); void DeleteAllSessions ();
boost::asio::io_service& GetService () { return m_Socket.get_io_service(); }; boost::asio::io_service& GetService () { return m_Socket.get_io_service(); };
const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; };
void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
void AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay); void AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay);
SSUSession * FindRelaySession (uint32_t tag); std::shared_ptr<SSUSession> FindRelaySession (uint32_t tag);
private: private:
@@ -54,7 +54,7 @@ namespace transport
void HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred); void HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred);
template<typename Filter> template<typename Filter>
SSUSession * GetRandomSession (Filter filter); std::shared_ptr<SSUSession> GetRandomSession (Filter filter);
std::set<SSUSession *> FindIntroducers (int maxNumIntroducers); std::set<SSUSession *> FindIntroducers (int maxNumIntroducers);
void ScheduleIntroducersUpdateTimer (); void ScheduleIntroducersUpdateTimer ();
@@ -73,7 +73,7 @@ namespace transport
std::list<boost::asio::ip::udp::endpoint> m_Introducers; // introducers we are connected to std::list<boost::asio::ip::udp::endpoint> m_Introducers; // introducers we are connected to
i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V4> m_ReceiveBuffer; i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V4> m_ReceiveBuffer;
i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V6> m_ReceiveBufferV6; i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V6> m_ReceiveBufferV6;
std::map<boost::asio::ip::udp::endpoint, SSUSession *> m_Sessions; std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions;
std::map<uint32_t, boost::asio::ip::udp::endpoint> m_Relays; // we are introducer std::map<uint32_t, boost::asio::ip::udp::endpoint> m_Relays; // we are introducer
public: public:

View File

@@ -401,8 +401,9 @@ namespace transport
{ {
m_ResendTimer.cancel (); m_ResendTimer.cancel ();
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL)); m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL));
m_ResendTimer.async_wait (boost::bind (&SSUData::HandleResendTimer, auto s = m_Session.shared_from_this();
this, boost::asio::placeholders::error)); m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode)
{ s->m_Data.HandleResendTimer (ecode); });
} }
void SSUData::HandleResendTimer (const boost::system::error_code& ecode) void SSUData::HandleResendTimer (const boost::system::error_code& ecode)

View File

@@ -14,15 +14,13 @@ namespace i2p
namespace transport namespace transport
{ {
SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
const i2p::data::RouterInfo * router, bool peerTest ): TransportSession (router), std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest ): TransportSession (router),
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_Server (server), m_RemoteEndpoint (remoteEndpoint),
m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_Timer (m_Server.GetService ()), m_PeerTest (peerTest),
m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0), m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0),
m_Data (*this), m_NumSentBytes (0), m_NumReceivedBytes (0) m_Data (*this), m_NumSentBytes (0), m_NumReceivedBytes (0)
{ {
m_CreationTime = i2p::util::GetSecondsSinceEpoch (); m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
if (!router) // incoming session
ScheduleConnectTimer ();
} }
SSUSession::~SSUSession () SSUSession::~SSUSession ()
@@ -111,7 +109,7 @@ namespace transport
else else
{ {
LogPrint (eLogError, "MAC verification failed ", len, " bytes from ", senderEndpoint); LogPrint (eLogError, "MAC verification failed ", len, " bytes from ", senderEndpoint);
m_Server.DeleteSession (this); m_Server.DeleteSession (shared_from_this ());
return; return;
} }
} }
@@ -146,13 +144,13 @@ namespace transport
case PAYLOAD_TYPE_SESSION_DESTROYED: case PAYLOAD_TYPE_SESSION_DESTROYED:
{ {
LogPrint (eLogDebug, "SSU session destroy received"); LogPrint (eLogDebug, "SSU session destroy received");
m_Server.DeleteSession (this); // delete this m_Server.DeleteSession (shared_from_this ());
break; break;
} }
case PAYLOAD_TYPE_RELAY_RESPONSE: case PAYLOAD_TYPE_RELAY_RESPONSE:
ProcessRelayResponse (buf, len); ProcessRelayResponse (buf, len);
if (m_State != eSessionStateEstablished) if (m_State != eSessionStateEstablished)
m_Server.DeleteSession (this); m_Server.DeleteSession (shared_from_this ());
break; break;
case PAYLOAD_TYPE_RELAY_REQUEST: case PAYLOAD_TYPE_RELAY_REQUEST:
LogPrint (eLogDebug, "SSU relay request received"); LogPrint (eLogDebug, "SSU relay request received");
@@ -461,7 +459,7 @@ namespace transport
buf += 32; // introkey buf += 32; // introkey
uint32_t nonce = be32toh (*(uint32_t *)buf); uint32_t nonce = be32toh (*(uint32_t *)buf);
SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint); SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint);
SendRelayIntro (session, from); SendRelayIntro (session.get (), from);
} }
} }
@@ -701,12 +699,20 @@ namespace transport
} }
} }
void SSUSession::WaitForConnect ()
{
if (!m_RemoteRouter) // incoming session
ScheduleConnectTimer ();
else
LogPrint (eLogError, "SSU wait for connect for outgoing session");
}
void SSUSession::ScheduleConnectTimer () void SSUSession::ScheduleConnectTimer ()
{ {
m_Timer.cancel (); m_Timer.cancel ();
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer, m_Timer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
void SSUSession::HandleConnectTimer (const boost::system::error_code& ecode) void SSUSession::HandleConnectTimer (const boost::system::error_code& ecode)
@@ -725,8 +731,8 @@ namespace transport
{ {
// set connect timer // set connect timer
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer, m_Timer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
SendRelayRequest (iTag, iKey); SendRelayRequest (iTag, iKey);
} }
@@ -736,8 +742,8 @@ namespace transport
m_State = eSessionStateIntroduced; m_State = eSessionStateIntroduced;
// set connect timer // set connect timer
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer, m_Timer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
void SSUSession::Close () void SSUSession::Close ()
@@ -776,7 +782,7 @@ namespace transport
if (m_State != eSessionStateFailed) if (m_State != eSessionStateFailed)
{ {
m_State = eSessionStateFailed; m_State = eSessionStateFailed;
m_Server.DeleteSession (this); // delete this m_Server.DeleteSession (shared_from_this ());
} }
} }
@@ -784,8 +790,8 @@ namespace transport
{ {
m_Timer.cancel (); m_Timer.cancel ();
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_TERMINATION_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(SSU_TERMINATION_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleTerminationTimer, m_Timer.async_wait (std::bind (&SSUSession::HandleTerminationTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
void SSUSession::HandleTerminationTimer (const boost::system::error_code& ecode) void SSUSession::HandleTerminationTimer (const boost::system::error_code& ecode)
@@ -815,7 +821,7 @@ namespace transport
void SSUSession::SendI2NPMessage (I2NPMessage * msg) void SSUSession::SendI2NPMessage (I2NPMessage * msg)
{ {
m_Server.GetService ().post (boost::bind (&SSUSession::PostI2NPMessage, this, msg)); m_Server.GetService ().post (std::bind (&SSUSession::PostI2NPMessage, shared_from_this (), msg));
} }
void SSUSession::PostI2NPMessage (I2NPMessage * msg) void SSUSession::PostI2NPMessage (I2NPMessage * msg)
@@ -891,7 +897,7 @@ namespace transport
else else
{ {
LogPrint (eLogDebug, "SSU peer test from Alice. We are Bob"); LogPrint (eLogDebug, "SSU peer test from Alice. We are Bob");
auto session = m_Server.GetRandomEstablishedSession (this); // charlie auto session = m_Server.GetRandomEstablishedSession (shared_from_this ()); // charlie
if (session) if (session)
session->SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (), session->SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (),
senderEndpoint.port (), introKey, false); senderEndpoint.port (), introKey, false);

View File

@@ -4,7 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <set> #include <set>
#include <list> #include <list>
#include <boost/asio.hpp> #include <memory>
#include "aes.h" #include "aes.h"
#include "hmac.h" #include "hmac.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
@@ -50,16 +50,17 @@ namespace transport
}; };
class SSUServer; class SSUServer;
class SSUSession: public TransportSession class SSUSession: public TransportSession, public std::enable_shared_from_this<SSUSession>
{ {
public: public:
SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
const i2p::data::RouterInfo * router = nullptr, bool peerTest = false); std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, bool peerTest = false);
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);
~SSUSession (); ~SSUSession ();
void Connect (); void Connect ();
void WaitForConnect ();
void Introduce (uint32_t iTag, const uint8_t * iKey); void Introduce (uint32_t iTag, const uint8_t * iKey);
void WaitForIntroduction (); void WaitForIntroduction ();
void Close (); void Close ();

View File

@@ -87,67 +87,150 @@ namespace crypto
publicKey.GetPublicElement ().Encode (signingPublicKey, DSA_PUBLIC_KEY_LENGTH); publicKey.GetPublicElement ().Encode (signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
} }
template<typename Hash, size_t keyLen>
const size_t ECDSAP256_PUBLIC_KEY_LENGTH = 64; class ECDSAVerifier: public Verifier
const size_t ECDSAP256_PUBLIC_KEY_HALF_LENGTH = ECDSAP256_PUBLIC_KEY_LENGTH/2; {
const size_t ECDSAP256_SIGNATURE_LENGTH = 64;
const size_t ECDSAP256_PRIVATE_KEY_LENGTH = ECDSAP256_SIGNATURE_LENGTH/2;
class ECDSAP256Verifier: public Verifier
{
public: public:
ECDSAP256Verifier (const uint8_t * signingKey) template<typename Curve>
ECDSAVerifier (Curve curve, const uint8_t * signingKey)
{ {
m_PublicKey.Initialize (CryptoPP::ASN1::secp256r1(), m_PublicKey.Initialize (curve,
CryptoPP::ECP::Point (CryptoPP::Integer (signingKey, ECDSAP256_PUBLIC_KEY_HALF_LENGTH), CryptoPP::ECP::Point (CryptoPP::Integer (signingKey, keyLen/2),
CryptoPP::Integer (signingKey + ECDSAP256_PUBLIC_KEY_HALF_LENGTH, ECDSAP256_PUBLIC_KEY_HALF_LENGTH))); CryptoPP::Integer (signingKey + keyLen/2, keyLen/2)));
} }
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{ {
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::Verifier verifier (m_PublicKey); typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::Verifier verifier (m_PublicKey);
return verifier.VerifyMessage (buf, len, signature, ECDSAP256_SIGNATURE_LENGTH); return verifier.VerifyMessage (buf, len, signature, keyLen); // signature length
} }
size_t GetPublicKeyLen () const { return ECDSAP256_PUBLIC_KEY_LENGTH; }; size_t GetPublicKeyLen () const { return keyLen; };
size_t GetSignatureLen () const { return ECDSAP256_SIGNATURE_LENGTH; }; size_t GetSignatureLen () const { return keyLen; }; // signature length = key length
private: private:
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PublicKey m_PublicKey; typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PublicKey m_PublicKey;
}; };
class ECDSAP256Signer: public Signer template<typename Hash>
class ECDSASigner: public Signer
{ {
public: public:
ECDSAP256Signer (const uint8_t * signingPrivateKey) template<typename Curve>
ECDSASigner (Curve curve, const uint8_t * signingPrivateKey, size_t keyLen)
{ {
m_PrivateKey.Initialize (CryptoPP::ASN1::secp256r1(), CryptoPP::Integer (signingPrivateKey, ECDSAP256_PRIVATE_KEY_LENGTH)); m_PrivateKey.Initialize (curve, CryptoPP::Integer (signingPrivateKey, keyLen/2)); // private key length
} }
void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const
{ {
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::Signer signer (m_PrivateKey); typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::Signer signer (m_PrivateKey);
signer.SignMessage (rnd, buf, len, signature); signer.SignMessage (rnd, buf, len, signature);
} }
private: private:
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PrivateKey m_PrivateKey; typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PrivateKey m_PrivateKey;
};
template<typename Hash, typename Curve>
inline void CreateECDSARandomKeys (CryptoPP::RandomNumberGenerator& rnd, Curve curve,
size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PrivateKey privateKey;
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PublicKey publicKey;
privateKey.Initialize (rnd, curve);
privateKey.MakePublicKey (publicKey);
privateKey.GetPrivateExponent ().Encode (signingPrivateKey, keyLen/2);
auto q = publicKey.GetPublicElement ();
q.x.Encode (signingPublicKey, keyLen/2);
q.y.Encode (signingPublicKey + keyLen/2, keyLen/2);
}
// ECDSA_SHA256_P256
const size_t ECDSAP256_KEY_LENGTH = 64;
class ECDSAP256Verifier: public ECDSAVerifier<CryptoPP::SHA256, ECDSAP256_KEY_LENGTH>
{
public:
ECDSAP256Verifier (const uint8_t * signingKey):
ECDSAVerifier (CryptoPP::ASN1::secp256r1(), signingKey)
{
}
};
class ECDSAP256Signer: public ECDSASigner<CryptoPP::SHA256>
{
public:
ECDSAP256Signer (const uint8_t * signingPrivateKey):
ECDSASigner (CryptoPP::ASN1::secp256r1(), signingPrivateKey, ECDSAP256_KEY_LENGTH)
{
}
}; };
inline void CreateECDSAP256RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void CreateECDSAP256RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{ {
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PrivateKey privateKey; CreateECDSARandomKeys<CryptoPP::SHA256> (rnd, CryptoPP::ASN1::secp256r1(), ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey);
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PublicKey publicKey;
privateKey.Initialize (rnd, CryptoPP::ASN1::secp256r1());
privateKey.MakePublicKey (publicKey);
privateKey.GetPrivateExponent ().Encode (signingPrivateKey, ECDSAP256_PRIVATE_KEY_LENGTH);
auto q = publicKey.GetPublicElement ();
q.x.Encode (signingPublicKey, ECDSAP256_PUBLIC_KEY_HALF_LENGTH);
q.y.Encode (signingPublicKey + ECDSAP256_PUBLIC_KEY_HALF_LENGTH, ECDSAP256_PUBLIC_KEY_HALF_LENGTH);
} }
// ECDSA_SHA384_P384
const size_t ECDSAP384_KEY_LENGTH = 96;
class ECDSAP384Verifier: public ECDSAVerifier<CryptoPP::SHA384, ECDSAP384_KEY_LENGTH>
{
public:
ECDSAP384Verifier (const uint8_t * signingKey):
ECDSAVerifier (CryptoPP::ASN1::secp384r1(), signingKey)
{
}
};
class ECDSAP384Signer: public ECDSASigner<CryptoPP::SHA384>
{
public:
ECDSAP384Signer (const uint8_t * signingPrivateKey):
ECDSASigner (CryptoPP::ASN1::secp384r1(), signingPrivateKey, ECDSAP384_KEY_LENGTH)
{
}
};
inline void CreateECDSAP384RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
CreateECDSARandomKeys<CryptoPP::SHA384> (rnd, CryptoPP::ASN1::secp384r1(), ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey);
}
// ECDSA_SHA512_P521
const size_t ECDSAP521_KEY_LENGTH = 132;
class ECDSAP521Verifier: public ECDSAVerifier<CryptoPP::SHA512, ECDSAP521_KEY_LENGTH>
{
public:
ECDSAP521Verifier (const uint8_t * signingKey):
ECDSAVerifier (CryptoPP::ASN1::secp521r1(), signingKey)
{
}
};
class ECDSAP521Signer: public ECDSASigner<CryptoPP::SHA512>
{
public:
ECDSAP521Signer (const uint8_t * signingPrivateKey):
ECDSASigner (CryptoPP::ASN1::secp521r1(), signingPrivateKey, ECDSAP521_KEY_LENGTH)
{
}
};
inline void CreateECDSAP521RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
CreateECDSARandomKeys<CryptoPP::SHA512> (rnd, CryptoPP::ASN1::secp521r1(), ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey);
}
} }
} }

View File

@@ -102,8 +102,8 @@ namespace stream
{ {
m_IsAckSendScheduled = true; m_IsAckSendScheduled = true;
m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(ACK_SEND_TIMEOUT)); m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(ACK_SEND_TIMEOUT));
m_AckSendTimer.async_wait (boost::bind (&Stream::HandleAckSendTimer, m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
} }
else if (isSyn) else if (isSyn)
@@ -309,7 +309,7 @@ namespace stream
size += sentLen; // payload size += sentLen; // payload
} }
p->len = size; p->len = size;
m_Service.post (boost::bind (&Stream::SendPacket, this, p)); m_Service.post (std::bind (&Stream::SendPacket, this, p));
} }
return len; return len;
@@ -460,8 +460,8 @@ namespace stream
{ {
m_ResendTimer.cancel (); m_ResendTimer.cancel ();
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_TIMEOUT)); m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_TIMEOUT));
m_ResendTimer.async_wait (boost::bind (&Stream::HandleResendTimer, m_ResendTimer.async_wait (std::bind (&Stream::HandleResendTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
void Stream::HandleResendTimer (const boost::system::error_code& ecode) void Stream::HandleResendTimer (const boost::system::error_code& ecode)
@@ -563,8 +563,6 @@ namespace stream
ResetAcceptor (); ResetAcceptor ();
{ {
std::unique_lock<std::mutex> l(m_StreamsMutex); std::unique_lock<std::mutex> l(m_StreamsMutex);
for (auto it: m_Streams)
delete it.second;
m_Streams.clear (); m_Streams.clear ();
} }
} }
@@ -597,36 +595,30 @@ namespace stream
} }
} }
Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port) std::shared_ptr<Stream> StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port)
{ {
Stream * s = new Stream (*m_Owner.GetService (), *this, remote, port); auto s = std::make_shared<Stream> (*m_Owner.GetService (), *this, remote, port);
std::unique_lock<std::mutex> l(m_StreamsMutex); std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s; m_Streams[s->GetRecvStreamID ()] = s;
return s; return s;
} }
Stream * StreamingDestination::CreateNewIncomingStream () std::shared_ptr<Stream> StreamingDestination::CreateNewIncomingStream ()
{ {
Stream * s = new Stream (*m_Owner.GetService (), *this); auto s = std::make_shared<Stream> (*m_Owner.GetService (), *this);
std::unique_lock<std::mutex> l(m_StreamsMutex); std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s; m_Streams[s->GetRecvStreamID ()] = s;
return s; return s;
} }
void StreamingDestination::DeleteStream (Stream * stream) void StreamingDestination::DeleteStream (std::shared_ptr<Stream> stream)
{ {
if (stream) if (stream)
{ {
std::unique_lock<std::mutex> l(m_StreamsMutex); std::unique_lock<std::mutex> l(m_StreamsMutex);
auto it = m_Streams.find (stream->GetRecvStreamID ()); auto it = m_Streams.find (stream->GetRecvStreamID ());
if (it != m_Streams.end ()) if (it != m_Streams.end ())
{
m_Streams.erase (it); m_Streams.erase (it);
if (m_Owner.GetService ())
m_Owner.GetService ()->post ([stream](void) { delete stream; });
else
delete stream;
}
} }
} }
@@ -651,7 +643,7 @@ namespace stream
} }
} }
void DeleteStream (Stream * stream) void DeleteStream (std::shared_ptr<Stream> stream)
{ {
if (stream) if (stream)
stream->GetLocalDestination ().DeleteStream (stream); stream->GetLocalDestination ().DeleteStream (stream);

View File

@@ -7,8 +7,8 @@
#include <set> #include <set>
#include <queue> #include <queue>
#include <functional> #include <functional>
#include <memory>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/bind.hpp>
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Identity.h" #include "Identity.h"
#include "LeaseSet.h" #include "LeaseSet.h"
@@ -78,7 +78,7 @@ namespace stream
}; };
class StreamingDestination; class StreamingDestination;
class Stream class Stream: public std::enable_shared_from_this<Stream>
{ {
public: public:
@@ -153,7 +153,7 @@ namespace stream
{ {
public: public:
typedef std::function<void (Stream *)> Acceptor; typedef std::function<void (std::shared_ptr<Stream>)> Acceptor;
StreamingDestination (i2p::client::ClientDestination& owner): m_Owner (owner) {}; StreamingDestination (i2p::client::ClientDestination& owner): m_Owner (owner) {};
~StreamingDestination () {}; ~StreamingDestination () {};
@@ -161,8 +161,8 @@ namespace stream
void Start (); void Start ();
void Stop (); void Stop ();
Stream * CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port = 0); std::shared_ptr<Stream> CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port = 0);
void DeleteStream (Stream * stream); void DeleteStream (std::shared_ptr<Stream> stream);
void SetAcceptor (const Acceptor& acceptor) { m_Acceptor = acceptor; }; void SetAcceptor (const Acceptor& acceptor) { m_Acceptor = acceptor; };
void ResetAcceptor () { m_Acceptor = nullptr; }; void ResetAcceptor () { m_Acceptor = nullptr; };
bool IsAcceptorSet () const { return m_Acceptor != nullptr; }; bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
@@ -173,13 +173,13 @@ namespace stream
private: private:
void HandleNextPacket (Packet * packet); void HandleNextPacket (Packet * packet);
Stream * CreateNewIncomingStream (); std::shared_ptr<Stream> CreateNewIncomingStream ();
private: private:
i2p::client::ClientDestination& m_Owner; i2p::client::ClientDestination& m_Owner;
std::mutex m_StreamsMutex; std::mutex m_StreamsMutex;
std::map<uint32_t, Stream *> m_Streams; std::map<uint32_t, std::shared_ptr<Stream> > m_Streams;
Acceptor m_Acceptor; Acceptor m_Acceptor;
public: public:
@@ -188,7 +188,7 @@ namespace stream
const decltype(m_Streams)& GetStreams () const { return m_Streams; }; const decltype(m_Streams)& GetStreams () const { return m_Streams; };
}; };
void DeleteStream (Stream * stream); void DeleteStream (std::shared_ptr<Stream> stream);
//------------------------------------------------- //-------------------------------------------------
@@ -197,15 +197,17 @@ namespace stream
{ {
if (!m_ReceiveQueue.empty ()) if (!m_ReceiveQueue.empty ())
{ {
m_Service.post ([=](void) { this->HandleReceiveTimer ( auto s = shared_from_this();
m_Service.post ([=](void) { s->HandleReceiveTimer (
boost::asio::error::make_error_code (boost::asio::error::operation_aborted), boost::asio::error::make_error_code (boost::asio::error::operation_aborted),
buffer, handler); }); buffer, handler); });
} }
else else
{ {
m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout)); m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout));
auto s = shared_from_this();
m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode) m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode)
{ this->HandleReceiveTimer (ecode, buffer, handler); }); { s->HandleReceiveTimer (ecode, buffer, handler); });
} }
} }

View File

@@ -3,6 +3,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <iostream> #include <iostream>
#include <memory>
#include "Identity.h" #include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
@@ -51,7 +52,7 @@ namespace transport
{ {
public: public:
TransportSession (const i2p::data::RouterInfo * in_RemoteRouter): TransportSession (std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
m_RemoteRouter (in_RemoteRouter), m_DHKeysPair (nullptr) m_RemoteRouter (in_RemoteRouter), m_DHKeysPair (nullptr)
{ {
if (m_RemoteRouter) if (m_RemoteRouter)
@@ -60,12 +61,12 @@ namespace transport
virtual ~TransportSession () { delete m_DHKeysPair; }; virtual ~TransportSession () { delete m_DHKeysPair; };
const i2p::data::RouterInfo * GetRemoteRouter () { return m_RemoteRouter; }; std::shared_ptr<const i2p::data::RouterInfo> GetRemoteRouter () { return m_RemoteRouter; };
const i2p::data::IdentityEx& GetRemoteIdentity () { return m_RemoteIdentity; }; const i2p::data::IdentityEx& GetRemoteIdentity () { return m_RemoteIdentity; };
protected: protected:
const i2p::data::RouterInfo * m_RemoteRouter; std::shared_ptr<const i2p::data::RouterInfo> m_RemoteRouter;
i2p::data::IdentityEx m_RemoteIdentity; i2p::data::IdentityEx m_RemoteIdentity;
DHKeysPair * m_DHKeysPair; // X - for client and Y - for server DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
}; };

View File

@@ -277,7 +277,7 @@ namespace transport
session->SendI2NPMessage (msg); session->SendI2NPMessage (msg);
else else
{ {
RouterInfo * r = netdb.FindRouter (ident); auto r = netdb.FindRouter (ident);
if (r) if (r)
{ {
auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (r) : nullptr; auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (r) : nullptr;
@@ -290,7 +290,7 @@ namespace transport
auto address = r->GetNTCPAddress (!context.SupportsV6 ()); auto address = r->GetNTCPAddress (!context.SupportsV6 ());
if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < NTCP_MAX_MESSAGE_SIZE) if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < NTCP_MAX_MESSAGE_SIZE)
{ {
auto s = new NTCPClient (m_Service, address->host, address->port, *r); auto s = new NTCPClient (m_Service, address->host, address->port, r);
AddNTCPSession (s); AddNTCPSession (s);
s->SendI2NPMessage (msg); s->SendI2NPMessage (msg);
} }
@@ -323,7 +323,7 @@ namespace transport
void Transports::HandleResendTimer (const boost::system::error_code& ecode, void Transports::HandleResendTimer (const boost::system::error_code& ecode,
boost::asio::deadline_timer * timer, const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg) boost::asio::deadline_timer * timer, const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg)
{ {
RouterInfo * r = netdb.FindRouter (ident); auto r = netdb.FindRouter (ident);
if (r) if (r)
{ {
LogPrint ("Router found. Sending message"); LogPrint ("Router found. Sending message");
@@ -337,13 +337,13 @@ namespace transport
delete timer; delete timer;
} }
void Transports::CloseSession (const i2p::data::RouterInfo * router) void Transports::CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router)
{ {
if (!router) return; if (!router) return;
m_Service.post (boost::bind (&Transports::PostCloseSession, this, router)); m_Service.post (boost::bind (&Transports::PostCloseSession, this, router));
} }
void Transports::PostCloseSession (const i2p::data::RouterInfo * router) void Transports::PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router)
{ {
auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (router) : nullptr; auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (router) : nullptr;
if (ssuSession) // try SSU first if (ssuSession) // try SSU first
@@ -360,7 +360,7 @@ namespace transport
{ {
auto router = i2p::data::netdb.GetRandomRouter (); auto router = i2p::data::netdb.GetRandomRouter ();
if (router && router->IsSSU () && m_SSUServer) if (router && router->IsSSU () && m_SSUServer)
m_SSUServer->GetSession (router.get (), true); // peer test m_SSUServer->GetSession (router, true); // peer test
} }
} }

View File

@@ -70,7 +70,7 @@ namespace transport
NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident); NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident);
void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void CloseSession (const i2p::data::RouterInfo * router); void CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
private: private:
@@ -80,7 +80,7 @@ namespace transport
void HandleResendTimer (const boost::system::error_code& ecode, boost::asio::deadline_timer * timer, void HandleResendTimer (const boost::system::error_code& ecode, boost::asio::deadline_timer * timer,
const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void PostCloseSession (const i2p::data::RouterInfo * router); void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
void DetectExternalIP (); void DetectExternalIP ();

View File

@@ -466,9 +466,9 @@ namespace tunnel
if (!inboundTunnel) return; if (!inboundTunnel) return;
LogPrint ("Creating one hop outbound tunnel..."); LogPrint ("Creating one hop outbound tunnel...");
CreateTunnel<OutboundTunnel> ( CreateTunnel<OutboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *> new TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >
{ {
i2p::data::netdb.GetRandomRouter ().get () i2p::data::netdb.GetRandomRouter ()
}, },
inboundTunnel->GetTunnelConfig ())); inboundTunnel->GetTunnelConfig ()));
} }
@@ -519,9 +519,9 @@ namespace tunnel
// trying to create one more inbound tunnel // trying to create one more inbound tunnel
LogPrint ("Creating one hop inbound tunnel..."); LogPrint ("Creating one hop inbound tunnel...");
CreateTunnel<InboundTunnel> ( CreateTunnel<InboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *> new TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >
{ {
i2p::data::netdb.GetRandomRouter ().get () i2p::data::netdb.GetRandomRouter ()
})); }));
} }
} }
@@ -609,9 +609,9 @@ namespace tunnel
void Tunnels::CreateZeroHopsInboundTunnel () void Tunnels::CreateZeroHopsInboundTunnel ()
{ {
CreateTunnel<InboundTunnel> ( CreateTunnel<InboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *> new TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >
{ {
&i2p::context.GetRouterInfo () i2p::context.GetSharedRouterInfo ()
})); }));
} }
} }

View File

@@ -79,7 +79,7 @@ namespace tunnel
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg);
void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
const i2p::data::RouterInfo * GetEndpointRouter () const std::shared_ptr<const i2p::data::RouterInfo> GetEndpointRouter () const
{ return GetTunnelConfig ()->GetLastHop ()->router; }; { return GetTunnelConfig ()->GetLastHop ()->router; };
size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); }; size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); };

View File

@@ -4,6 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
#include <memory>
#include "aes.h" #include "aes.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "RouterContext.h" #include "RouterContext.h"
@@ -14,7 +15,7 @@ namespace tunnel
{ {
struct TunnelHopConfig struct TunnelHopConfig
{ {
const i2p::data::RouterInfo * router, * nextRouter; std::shared_ptr<const i2p::data::RouterInfo> router, nextRouter;
uint32_t tunnelID, nextTunnelID; uint32_t tunnelID, nextTunnelID;
uint8_t layerKey[32]; uint8_t layerKey[32];
uint8_t ivKey[32]; uint8_t ivKey[32];
@@ -26,7 +27,7 @@ namespace tunnel
i2p::crypto::TunnelDecryption decryption; i2p::crypto::TunnelDecryption decryption;
int recordIndex; // record # in tunnel build message int recordIndex; // record # in tunnel build message
TunnelHopConfig (const i2p::data::RouterInfo * r) TunnelHopConfig (std::shared_ptr<const i2p::data::RouterInfo> r)
{ {
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
rnd.GenerateBlock (layerKey, 32); rnd.GenerateBlock (layerKey, 32);
@@ -36,14 +37,14 @@ namespace tunnel
isGateway = true; isGateway = true;
isEndpoint = true; isEndpoint = true;
router = r; router = r;
nextRouter = 0; //nextRouter = nullptr;
nextTunnelID = 0; nextTunnelID = 0;
next = 0; next = nullptr;
prev = 0; prev = nullptr;
} }
void SetNextRouter (const i2p::data::RouterInfo * r) void SetNextRouter (std::shared_ptr<const i2p::data::RouterInfo> r)
{ {
nextRouter = r; nextRouter = r;
isEndpoint = false; isEndpoint = false;
@@ -88,7 +89,7 @@ namespace tunnel
public: public:
TunnelConfig (std::vector<const i2p::data::RouterInfo *> peers, TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> > peers,
const TunnelConfig * replyTunnelConfig = nullptr) // replyTunnelConfig=nullptr means inbound const TunnelConfig * replyTunnelConfig = nullptr) // replyTunnelConfig=nullptr means inbound
{ {
TunnelHopConfig * prev = nullptr; TunnelHopConfig * prev = nullptr;
@@ -109,7 +110,7 @@ namespace tunnel
m_LastHop->SetReplyHop (replyTunnelConfig->GetFirstHop ()); m_LastHop->SetReplyHop (replyTunnelConfig->GetFirstHop ());
} }
else // inbound else // inbound
m_LastHop->SetNextRouter (&i2p::context.GetRouterInfo ()); m_LastHop->SetNextRouter (i2p::context.GetSharedRouterInfo ());
} }
~TunnelConfig () ~TunnelConfig ()
@@ -184,7 +185,7 @@ namespace tunnel
if (hop->isGateway) // inbound tunnel if (hop->isGateway) // inbound tunnel
newHop->SetReplyHop (m_FirstHop); // use it as reply tunnel newHop->SetReplyHop (m_FirstHop); // use it as reply tunnel
else else
newHop->SetNextRouter (&i2p::context.GetRouterInfo ()); newHop->SetNextRouter (i2p::context.GetSharedRouterInfo ());
} }
if (!hop->next) newConfig->m_FirstHop = newHop; // last hop if (!hop->next) newConfig->m_FirstHop = newHop; // last hop
@@ -195,7 +196,7 @@ namespace tunnel
TunnelConfig * Clone (const TunnelConfig * replyTunnelConfig = nullptr) const TunnelConfig * Clone (const TunnelConfig * replyTunnelConfig = nullptr) const
{ {
std::vector<const i2p::data::RouterInfo *> peers; std::vector<std::shared_ptr<const i2p::data::RouterInfo> > peers;
TunnelHopConfig * hop = m_FirstHop; TunnelHopConfig * hop = m_FirstHop;
while (hop) while (hop)
{ {

View File

@@ -235,12 +235,12 @@ namespace tunnel
m_LocalDestination.ProcessDeliveryStatusMessage (msg); m_LocalDestination.ProcessDeliveryStatusMessage (msg);
} }
const i2p::data::RouterInfo * TunnelPool::SelectNextHop (const i2p::data::RouterInfo * prevHop) const std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const
{ {
auto hop = m_NumHops >= 3 ? i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop).get () : auto hop = m_NumHops >= 3 ? i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop) :
i2p::data::netdb.GetRandomRouter (prevHop).get (); i2p::data::netdb.GetRandomRouter (prevHop);
if (!hop) if (!hop)
hop = i2p::data::netdb.GetRandomRouter ().get (); hop = i2p::data::netdb.GetRandomRouter ();
return hop; return hop;
} }
@@ -250,8 +250,8 @@ namespace tunnel
if (!outboundTunnel) if (!outboundTunnel)
outboundTunnel = tunnels.GetNextOutboundTunnel (); outboundTunnel = tunnels.GetNextOutboundTunnel ();
LogPrint ("Creating destination inbound tunnel..."); LogPrint ("Creating destination inbound tunnel...");
const i2p::data::RouterInfo * prevHop = &i2p::context.GetRouterInfo (); auto prevHop = i2p::context.GetSharedRouterInfo ();
std::vector<const i2p::data::RouterInfo *> hops; std::vector<std::shared_ptr<const i2p::data::RouterInfo> > hops;
int numHops = m_NumHops; int numHops = m_NumHops;
if (outboundTunnel) if (outboundTunnel)
{ {
@@ -294,8 +294,8 @@ namespace tunnel
{ {
LogPrint ("Creating destination outbound tunnel..."); LogPrint ("Creating destination outbound tunnel...");
const i2p::data::RouterInfo * prevHop = &i2p::context.GetRouterInfo (); auto prevHop = i2p::context.GetSharedRouterInfo ();
std::vector<const i2p::data::RouterInfo *> hops; std::vector<std::shared_ptr<const i2p::data::RouterInfo> > hops;
for (int i = 0; i < m_NumHops; i++) for (int i = 0; i < m_NumHops; i++)
{ {
auto hop = SelectNextHop (prevHop); auto hop = SelectNextHop (prevHop);

View File

@@ -61,7 +61,7 @@ namespace tunnel
template<class TTunnels> template<class TTunnels>
typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels,
typename TTunnels::value_type suggested = nullptr) const; typename TTunnels::value_type suggested = nullptr) const;
const i2p::data::RouterInfo * SelectNextHop (const i2p::data::RouterInfo * prevHop) const; std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
private: private:

View File

@@ -1,6 +1,6 @@
# NSIS Installer script. (Tested with NSIS 2.64 on Windows 7) # NSIS Installer script. (Tested with NSIS 2.64 on Windows 7)
# Author: Mikal Villa (Meeh) # Author: Mikal Villa (Meeh)
# Version: 1.0 # Version: 1.1
Name PurpleI2P Name PurpleI2P
RequestExecutionLevel highest RequestExecutionLevel highest
@@ -9,7 +9,7 @@ ShowInstDetails show
# General Symbol Definitions # General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)" !define REGKEY "SOFTWARE\$(^Name)"
!define VERSION 0.2.0.0 !define VERSION 0.3.0.0
!define COMPANY "The Privacy Solutions Project" !define COMPANY "The Privacy Solutions Project"
!define URL "https://i2p.io" !define URL "https://i2p.io"
@@ -64,13 +64,13 @@ Var StartMenuGroup
!insertmacro MUI_LANGUAGE English !insertmacro MUI_LANGUAGE English
# Installer attributes # Installer attributes
OutFile PurpleI2P-0.2.0.0-win32-setup.exe OutFile PurpleI2P-0.3.0.0-win32-setup.exe
InstallDir $PROGRAMFILES\PurpleI2P InstallDir $PROGRAMFILES\PurpleI2P
CRCCheck on CRCCheck on
XPStyle on XPStyle on
BrandingText " " BrandingText " "
ShowInstDetails show ShowInstDetails show
VIProductVersion 0.2.0.0 VIProductVersion 0.3.0.0
VIAddVersionKey ProductName PurpleI2P VIAddVersionKey ProductName PurpleI2P
VIAddVersionKey ProductVersion "${VERSION}" VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}" VIAddVersionKey CompanyName "${COMPANY}"

View File

@@ -73,7 +73,7 @@ namespace api
i2p::data::netdb.RequestDestination (remote, true, dest->GetTunnelPool ()); i2p::data::netdb.RequestDestination (remote, true, dest->GetTunnelPool ());
} }
i2p::stream::Stream * CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote) std::shared_ptr<i2p::stream::Stream> CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote)
{ {
auto leaseSet = i2p::data::netdb.FindLeaseSet (remote); auto leaseSet = i2p::data::netdb.FindLeaseSet (remote);
if (leaseSet) if (leaseSet)
@@ -95,7 +95,7 @@ namespace api
dest->AcceptStreams (acceptor); dest->AcceptStreams (acceptor);
} }
void DestroyStream (i2p::stream::Stream * stream) void DestroyStream (std::shared_ptr<i2p::stream::Stream> stream)
{ {
if (stream) if (stream)
{ {

View File

@@ -1,6 +1,7 @@
#ifndef API_H__ #ifndef API_H__
#define API_H__ #define API_H__
#include <memory>
#include "Identity.h" #include "Identity.h"
#include "Destination.h" #include "Destination.h"
#include "Streaming.h" #include "Streaming.h"
@@ -16,14 +17,14 @@ namespace api
// destinations // destinations
i2p::client::ClientDestination * CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true); i2p::client::ClientDestination * CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true);
i2p::client::ClientDestination * CreateLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // transient destinations usually not published i2p::client::ClientDestination * CreateLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); // transient destinations usually not published
void DestoroyLocalDestination (i2p::client::ClientDestination * dest); void DestoroyLocalDestination (i2p::client::ClientDestination * dest);
// streams // streams
void RequestLeaseSet (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote); void RequestLeaseSet (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote);
i2p::stream::Stream * CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote); std::shared_ptr<i2p::stream::Stream> CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote);
void AcceptStream (i2p::client::ClientDestination * dest, const i2p::stream::StreamingDestination::Acceptor& acceptor); void AcceptStream (i2p::client::ClientDestination * dest, const i2p::stream::StreamingDestination::Acceptor& acceptor);
void DestroyStream (i2p::stream::Stream * stream); void DestroyStream (std::shared_ptr<i2p::stream::Stream> stream);
} }
} }

View File

@@ -2,7 +2,7 @@
#define _VERSION_H_ #define _VERSION_H_
#define CODENAME "Purple" #define CODENAME "Purple"
#define VERSION "0.3.0" #define VERSION "0.4.0"
#define I2P_VERSION "0.9.16" #define I2P_VERSION "0.9.16"
#endif #endif