mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-13 04:46:38 +01:00
commit
85b1505e51
105 changed files with 22391 additions and 22194 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -5,6 +5,8 @@ router.keys
|
||||||
i2p
|
i2p
|
||||||
libi2pd.so
|
libi2pd.so
|
||||||
netDb
|
netDb
|
||||||
|
tunnels.cfg
|
||||||
|
tests/tests
|
||||||
|
|
||||||
# Autotools
|
# Autotools
|
||||||
autom4te.cache
|
autom4te.cache
|
||||||
|
|
1018
AddressBook.cpp
1018
AddressBook.cpp
File diff suppressed because it is too large
Load diff
132
AddressBook.h
132
AddressBook.h
|
@ -17,86 +17,86 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
const char DEFAULT_SUBSCRIPTION_ADDRESS[] = "http://udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p/hosts.txt";
|
const char DEFAULT_SUBSCRIPTION_ADDRESS[] = "http://udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p/hosts.txt";
|
||||||
const int INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT = 3; // in minutes
|
const int INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT = 3; // in minutes
|
||||||
const int INITIAL_SUBSCRIPTION_RETRY_TIMEOUT = 1; // in minutes
|
const int INITIAL_SUBSCRIPTION_RETRY_TIMEOUT = 1; // in minutes
|
||||||
const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours)
|
const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours)
|
||||||
const int CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT = 5; // in minutes
|
const int CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT = 5; // in minutes
|
||||||
const int SUBSCRIPTION_REQUEST_TIMEOUT = 60; //in second
|
const int SUBSCRIPTION_REQUEST_TIMEOUT = 60; //in second
|
||||||
|
|
||||||
inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); }
|
inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); }
|
||||||
|
|
||||||
class AddressBookStorage // interface for storage
|
class AddressBookStorage // interface for storage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~AddressBookStorage () {};
|
virtual ~AddressBookStorage () {};
|
||||||
virtual bool GetAddress (const i2p::data::IdentHash& ident, i2p::data::IdentityEx& address) const = 0;
|
virtual bool GetAddress (const i2p::data::IdentHash& ident, i2p::data::IdentityEx& address) const = 0;
|
||||||
virtual void AddAddress (const i2p::data::IdentityEx& address) = 0;
|
virtual void AddAddress (const i2p::data::IdentityEx& address) = 0;
|
||||||
virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0;
|
virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0;
|
||||||
|
|
||||||
virtual int Load (std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
|
virtual int Load (std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
|
||||||
virtual int Save (const std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
|
virtual int Save (const std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddressBookSubscription;
|
class AddressBookSubscription;
|
||||||
class AddressBook
|
class AddressBook
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AddressBook ();
|
AddressBook ();
|
||||||
~AddressBook ();
|
~AddressBook ();
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
bool GetIdentHash (const std::string& address, i2p::data::IdentHash& ident);
|
bool GetIdentHash (const std::string& address, i2p::data::IdentHash& ident);
|
||||||
bool GetAddress (const std::string& address, i2p::data::IdentityEx& identity);
|
bool GetAddress (const std::string& address, i2p::data::IdentityEx& identity);
|
||||||
const i2p::data::IdentHash * FindAddress (const std::string& address);
|
const i2p::data::IdentHash * FindAddress (const std::string& address);
|
||||||
void InsertAddress (const std::string& address, const std::string& base64); // for jump service
|
void InsertAddress (const std::string& address, const std::string& base64); // for jump service
|
||||||
void InsertAddress (const i2p::data::IdentityEx& address);
|
void InsertAddress (const i2p::data::IdentityEx& address);
|
||||||
|
|
||||||
void LoadHostsFromStream (std::istream& f);
|
void LoadHostsFromStream (std::istream& f);
|
||||||
void DownloadComplete (bool success);
|
void DownloadComplete (bool success);
|
||||||
//This method returns the ".b32.i2p" address
|
//This method returns the ".b32.i2p" address
|
||||||
std::string ToAddress(const i2p::data::IdentHash& ident) { return GetB32Address(ident); }
|
std::string ToAddress(const i2p::data::IdentHash& ident) { return GetB32Address(ident); }
|
||||||
std::string ToAddress(const i2p::data::IdentityEx& ident) { return ToAddress(ident.GetIdentHash ()); }
|
std::string ToAddress(const i2p::data::IdentityEx& ident) { return ToAddress(ident.GetIdentHash ()); }
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void StartSubscriptions ();
|
void StartSubscriptions ();
|
||||||
void StopSubscriptions ();
|
void StopSubscriptions ();
|
||||||
|
|
||||||
AddressBookStorage * CreateStorage ();
|
AddressBookStorage * CreateStorage ();
|
||||||
void LoadHosts ();
|
void LoadHosts ();
|
||||||
void LoadSubscriptions ();
|
void LoadSubscriptions ();
|
||||||
|
|
||||||
void HandleSubscriptionsUpdateTimer (const boost::system::error_code& ecode);
|
void HandleSubscriptionsUpdateTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::mutex m_AddressBookMutex;
|
std::mutex m_AddressBookMutex;
|
||||||
std::map<std::string, i2p::data::IdentHash> m_Addresses;
|
std::map<std::string, i2p::data::IdentHash> m_Addresses;
|
||||||
AddressBookStorage * m_Storage;
|
AddressBookStorage * m_Storage;
|
||||||
volatile bool m_IsLoaded, m_IsDownloading;
|
volatile bool m_IsLoaded, m_IsDownloading;
|
||||||
std::vector<AddressBookSubscription *> m_Subscriptions;
|
std::vector<AddressBookSubscription *> m_Subscriptions;
|
||||||
AddressBookSubscription * m_DefaultSubscription; // in case if we don't know any addresses yet
|
AddressBookSubscription * m_DefaultSubscription; // in case if we don't know any addresses yet
|
||||||
boost::asio::deadline_timer * m_SubscriptionsUpdateTimer;
|
boost::asio::deadline_timer * m_SubscriptionsUpdateTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddressBookSubscription
|
class AddressBookSubscription
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AddressBookSubscription (AddressBook& book, const std::string& link);
|
AddressBookSubscription (AddressBook& book, const std::string& link);
|
||||||
void CheckSubscription ();
|
void CheckSubscription ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Request ();
|
void Request ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
AddressBook& m_Book;
|
AddressBook& m_Book;
|
||||||
std::string m_Link, m_Etag, m_LastModified;
|
std::string m_Link, m_Etag, m_LastModified;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
344
BOB.h
344
BOB.h
|
@ -16,220 +16,220 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
const size_t BOB_COMMAND_BUFFER_SIZE = 1024;
|
const size_t BOB_COMMAND_BUFFER_SIZE = 1024;
|
||||||
const char BOB_COMMAND_ZAP[] = "zap";
|
const char BOB_COMMAND_ZAP[] = "zap";
|
||||||
const char BOB_COMMAND_QUIT[] = "quit";
|
const char BOB_COMMAND_QUIT[] = "quit";
|
||||||
const char BOB_COMMAND_START[] = "start";
|
const char BOB_COMMAND_START[] = "start";
|
||||||
const char BOB_COMMAND_STOP[] = "stop";
|
const char BOB_COMMAND_STOP[] = "stop";
|
||||||
const char BOB_COMMAND_SETNICK[] = "setnick";
|
const char BOB_COMMAND_SETNICK[] = "setnick";
|
||||||
const char BOB_COMMAND_GETNICK[] = "getnick";
|
const char BOB_COMMAND_GETNICK[] = "getnick";
|
||||||
const char BOB_COMMAND_NEWKEYS[] = "newkeys";
|
const char BOB_COMMAND_NEWKEYS[] = "newkeys";
|
||||||
const char BOB_COMMAND_GETKEYS[] = "getkeys";
|
const char BOB_COMMAND_GETKEYS[] = "getkeys";
|
||||||
const char BOB_COMMAND_SETKEYS[] = "setkeys";
|
const char BOB_COMMAND_SETKEYS[] = "setkeys";
|
||||||
const char BOB_COMMAND_GETDEST[] = "getdest";
|
const char BOB_COMMAND_GETDEST[] = "getdest";
|
||||||
const char BOB_COMMAND_OUTHOST[] = "outhost";
|
const char BOB_COMMAND_OUTHOST[] = "outhost";
|
||||||
const char BOB_COMMAND_OUTPORT[] = "outport";
|
const char BOB_COMMAND_OUTPORT[] = "outport";
|
||||||
const char BOB_COMMAND_INHOST[] = "inhost";
|
const char BOB_COMMAND_INHOST[] = "inhost";
|
||||||
const char BOB_COMMAND_INPORT[] = "inport";
|
const char BOB_COMMAND_INPORT[] = "inport";
|
||||||
const char BOB_COMMAND_QUIET[] = "quiet";
|
const char BOB_COMMAND_QUIET[] = "quiet";
|
||||||
const char BOB_COMMAND_LOOKUP[] = "lookup";
|
const char BOB_COMMAND_LOOKUP[] = "lookup";
|
||||||
const char BOB_COMMAND_CLEAR[] = "clear";
|
const char BOB_COMMAND_CLEAR[] = "clear";
|
||||||
const char BOB_COMMAND_LIST[] = "list";
|
const char BOB_COMMAND_LIST[] = "list";
|
||||||
const char BOB_COMMAND_OPTION[] = "option";
|
const char BOB_COMMAND_OPTION[] = "option";
|
||||||
|
|
||||||
const char BOB_VERSION[] = "BOB 00.00.10\nOK\n";
|
const char BOB_VERSION[] = "BOB 00.00.10\nOK\n";
|
||||||
const char BOB_REPLY_OK[] = "OK %s\n";
|
const char BOB_REPLY_OK[] = "OK %s\n";
|
||||||
const char BOB_REPLY_ERROR[] = "ERROR %s\n";
|
const char BOB_REPLY_ERROR[] = "ERROR %s\n";
|
||||||
const char BOB_DATA[] = "NICKNAME %s\n";
|
const char BOB_DATA[] = "NICKNAME %s\n";
|
||||||
|
|
||||||
class BOBI2PTunnel: public I2PService
|
class BOBI2PTunnel: public I2PService
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BOBI2PTunnel (std::shared_ptr<ClientDestination> localDestination):
|
BOBI2PTunnel (std::shared_ptr<ClientDestination> localDestination):
|
||||||
I2PService (localDestination) {};
|
I2PService (localDestination) {};
|
||||||
|
|
||||||
virtual void Start () {};
|
virtual void Start () {};
|
||||||
virtual void Stop () {};
|
virtual void Stop () {};
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOBI2PInboundTunnel: public BOBI2PTunnel
|
class BOBI2PInboundTunnel: public BOBI2PTunnel
|
||||||
{
|
{
|
||||||
struct AddressReceiver
|
struct AddressReceiver
|
||||||
{
|
{
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket;
|
std::shared_ptr<boost::asio::ip::tcp::socket> socket;
|
||||||
char buffer[BOB_COMMAND_BUFFER_SIZE + 1]; // for destination base64 address
|
char buffer[BOB_COMMAND_BUFFER_SIZE + 1]; // for destination base64 address
|
||||||
uint8_t * data; // pointer to buffer
|
uint8_t * data; // pointer to buffer
|
||||||
size_t dataLen, bufferOffset;
|
size_t dataLen, bufferOffset;
|
||||||
|
|
||||||
AddressReceiver (): data (nullptr), dataLen (0), bufferOffset (0) {};
|
AddressReceiver (): data (nullptr), dataLen (0), bufferOffset (0) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BOBI2PInboundTunnel (int port, std::shared_ptr<ClientDestination> localDestination);
|
BOBI2PInboundTunnel (int port, std::shared_ptr<ClientDestination> localDestination);
|
||||||
~BOBI2PInboundTunnel ();
|
~BOBI2PInboundTunnel ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Accept ();
|
void Accept ();
|
||||||
void HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<AddressReceiver> receiver);
|
void HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<AddressReceiver> receiver);
|
||||||
|
|
||||||
void ReceiveAddress (std::shared_ptr<AddressReceiver> receiver);
|
void ReceiveAddress (std::shared_ptr<AddressReceiver> receiver);
|
||||||
void HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred,
|
void HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred,
|
||||||
std::shared_ptr<AddressReceiver> receiver);
|
std::shared_ptr<AddressReceiver> receiver);
|
||||||
|
|
||||||
void HandleDestinationRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::shared_ptr<AddressReceiver> receiver);
|
void HandleDestinationRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::shared_ptr<AddressReceiver> receiver);
|
||||||
|
|
||||||
void CreateConnection (std::shared_ptr<AddressReceiver> receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet);
|
void CreateConnection (std::shared_ptr<AddressReceiver> receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOBI2POutboundTunnel: public BOBI2PTunnel
|
class BOBI2POutboundTunnel: public BOBI2PTunnel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BOBI2POutboundTunnel (const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, bool quiet);
|
BOBI2POutboundTunnel (const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, bool quiet);
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
void SetQuiet () { m_IsQuiet = true; };
|
void SetQuiet () { m_IsQuiet = true; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Accept ();
|
void Accept ();
|
||||||
void HandleAccept (std::shared_ptr<i2p::stream::Stream> stream);
|
void HandleAccept (std::shared_ptr<i2p::stream::Stream> stream);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
boost::asio::ip::tcp::endpoint m_Endpoint;
|
boost::asio::ip::tcp::endpoint m_Endpoint;
|
||||||
bool m_IsQuiet;
|
bool m_IsQuiet;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class BOBDestination
|
class BOBDestination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BOBDestination (std::shared_ptr<ClientDestination> localDestination);
|
BOBDestination (std::shared_ptr<ClientDestination> localDestination);
|
||||||
~BOBDestination ();
|
~BOBDestination ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
void StopTunnels ();
|
void StopTunnels ();
|
||||||
void CreateInboundTunnel (int port);
|
void CreateInboundTunnel (int port);
|
||||||
void CreateOutboundTunnel (const std::string& address, int port, bool quiet);
|
void CreateOutboundTunnel (const std::string& address, int port, bool quiet);
|
||||||
const i2p::data::PrivateKeys& GetKeys () const { return m_LocalDestination->GetPrivateKeys (); };
|
const i2p::data::PrivateKeys& GetKeys () const { return m_LocalDestination->GetPrivateKeys (); };
|
||||||
std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDestination; };
|
std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDestination; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> m_LocalDestination;
|
std::shared_ptr<ClientDestination> m_LocalDestination;
|
||||||
BOBI2POutboundTunnel * m_OutboundTunnel;
|
BOBI2POutboundTunnel * m_OutboundTunnel;
|
||||||
BOBI2PInboundTunnel * m_InboundTunnel;
|
BOBI2PInboundTunnel * m_InboundTunnel;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOBCommandChannel;
|
class BOBCommandChannel;
|
||||||
class BOBCommandSession: public std::enable_shared_from_this<BOBCommandSession>
|
class BOBCommandSession: public std::enable_shared_from_this<BOBCommandSession>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BOBCommandSession (BOBCommandChannel& owner);
|
BOBCommandSession (BOBCommandChannel& owner);
|
||||||
~BOBCommandSession ();
|
~BOBCommandSession ();
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
|
|
||||||
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
||||||
void SendVersion ();
|
void SendVersion ();
|
||||||
|
|
||||||
// command handlers
|
// command handlers
|
||||||
void ZapCommandHandler (const char * operand, size_t len);
|
void ZapCommandHandler (const char * operand, size_t len);
|
||||||
void QuitCommandHandler (const char * operand, size_t len);
|
void QuitCommandHandler (const char * operand, size_t len);
|
||||||
void StartCommandHandler (const char * operand, size_t len);
|
void StartCommandHandler (const char * operand, size_t len);
|
||||||
void StopCommandHandler (const char * operand, size_t len);
|
void StopCommandHandler (const char * operand, size_t len);
|
||||||
void SetNickCommandHandler (const char * operand, size_t len);
|
void SetNickCommandHandler (const char * operand, size_t len);
|
||||||
void GetNickCommandHandler (const char * operand, size_t len);
|
void GetNickCommandHandler (const char * operand, size_t len);
|
||||||
void NewkeysCommandHandler (const char * operand, size_t len);
|
void NewkeysCommandHandler (const char * operand, size_t len);
|
||||||
void SetkeysCommandHandler (const char * operand, size_t len);
|
void SetkeysCommandHandler (const char * operand, size_t len);
|
||||||
void GetkeysCommandHandler (const char * operand, size_t len);
|
void GetkeysCommandHandler (const char * operand, size_t len);
|
||||||
void GetdestCommandHandler (const char * operand, size_t len);
|
void GetdestCommandHandler (const char * operand, size_t len);
|
||||||
void OuthostCommandHandler (const char * operand, size_t len);
|
void OuthostCommandHandler (const char * operand, size_t len);
|
||||||
void OutportCommandHandler (const char * operand, size_t len);
|
void OutportCommandHandler (const char * operand, size_t len);
|
||||||
void InhostCommandHandler (const char * operand, size_t len);
|
void InhostCommandHandler (const char * operand, size_t len);
|
||||||
void InportCommandHandler (const char * operand, size_t len);
|
void InportCommandHandler (const char * operand, size_t len);
|
||||||
void QuietCommandHandler (const char * operand, size_t len);
|
void QuietCommandHandler (const char * operand, size_t len);
|
||||||
void LookupCommandHandler (const char * operand, size_t len);
|
void LookupCommandHandler (const char * operand, size_t len);
|
||||||
void ClearCommandHandler (const char * operand, size_t len);
|
void ClearCommandHandler (const char * operand, size_t len);
|
||||||
void ListCommandHandler (const char * operand, size_t len);
|
void ListCommandHandler (const char * operand, size_t len);
|
||||||
void OptionCommandHandler (const char * operand, size_t len);
|
void OptionCommandHandler (const char * operand, size_t len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Receive ();
|
void Receive ();
|
||||||
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
|
|
||||||
void Send (size_t len);
|
void Send (size_t len);
|
||||||
void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void SendReplyOK (const char * msg);
|
void SendReplyOK (const char * msg);
|
||||||
void SendReplyError (const char * msg);
|
void SendReplyError (const char * msg);
|
||||||
void SendData (const char * nickname);
|
void SendData (const char * nickname);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
BOBCommandChannel& m_Owner;
|
BOBCommandChannel& m_Owner;
|
||||||
boost::asio::ip::tcp::socket m_Socket;
|
boost::asio::ip::tcp::socket m_Socket;
|
||||||
char m_ReceiveBuffer[BOB_COMMAND_BUFFER_SIZE + 1], m_SendBuffer[BOB_COMMAND_BUFFER_SIZE + 1];
|
char m_ReceiveBuffer[BOB_COMMAND_BUFFER_SIZE + 1], m_SendBuffer[BOB_COMMAND_BUFFER_SIZE + 1];
|
||||||
size_t m_ReceiveBufferOffset;
|
size_t m_ReceiveBufferOffset;
|
||||||
bool m_IsOpen, m_IsQuiet;
|
bool m_IsOpen, m_IsQuiet;
|
||||||
std::string m_Nickname, m_Address;
|
std::string m_Nickname, m_Address;
|
||||||
int m_InPort, m_OutPort;
|
int m_InPort, m_OutPort;
|
||||||
i2p::data::PrivateKeys m_Keys;
|
i2p::data::PrivateKeys m_Keys;
|
||||||
std::map<std::string, std::string> m_Options;
|
std::map<std::string, std::string> m_Options;
|
||||||
BOBDestination * m_CurrentDestination;
|
BOBDestination * m_CurrentDestination;
|
||||||
};
|
};
|
||||||
typedef void (BOBCommandSession::*BOBCommandHandler)(const char * operand, size_t len);
|
typedef void (BOBCommandSession::*BOBCommandHandler)(const char * operand, size_t len);
|
||||||
|
|
||||||
class BOBCommandChannel
|
class BOBCommandChannel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BOBCommandChannel (int port);
|
BOBCommandChannel (int port);
|
||||||
~BOBCommandChannel ();
|
~BOBCommandChannel ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
boost::asio::io_service& GetService () { return m_Service; };
|
boost::asio::io_service& GetService () { return m_Service; };
|
||||||
void AddDestination (const std::string& name, BOBDestination * dest);
|
void AddDestination (const std::string& name, BOBDestination * dest);
|
||||||
void DeleteDestination (const std::string& name);
|
void DeleteDestination (const std::string& name);
|
||||||
BOBDestination * FindDestination (const std::string& name);
|
BOBDestination * FindDestination (const std::string& name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void Accept ();
|
void Accept ();
|
||||||
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<BOBCommandSession> session);
|
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<BOBCommandSession> session);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
boost::asio::io_service m_Service;
|
boost::asio::io_service m_Service;
|
||||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||||
std::map<std::string, BOBDestination *> m_Destinations;
|
std::map<std::string, BOBDestination *> m_Destinations;
|
||||||
std::map<std::string, BOBCommandHandler> m_CommandHandlers;
|
std::map<std::string, BOBCommandHandler> m_CommandHandlers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
const decltype(m_CommandHandlers)& GetCommandHandlers () const { return m_CommandHandlers; };
|
const decltype(m_CommandHandlers)& GetCommandHandlers () const { return m_CommandHandlers; };
|
||||||
const decltype(m_Destinations)& GetDestinations () const { return m_Destinations; };
|
const decltype(m_Destinations)& GetDestinations () const { return m_Destinations; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,334 +11,334 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
ClientContext context;
|
ClientContext context;
|
||||||
|
|
||||||
ClientContext::ClientContext (): m_SharedLocalDestination (nullptr),
|
ClientContext::ClientContext (): m_SharedLocalDestination (nullptr),
|
||||||
m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_SamBridge (nullptr),
|
m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_SamBridge (nullptr),
|
||||||
m_BOBCommandChannel (nullptr), m_I2PControlService (nullptr)
|
m_BOBCommandChannel (nullptr), m_I2PControlService (nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientContext::~ClientContext ()
|
ClientContext::~ClientContext ()
|
||||||
{
|
{
|
||||||
delete m_HttpProxy;
|
delete m_HttpProxy;
|
||||||
delete m_SocksProxy;
|
delete m_SocksProxy;
|
||||||
delete m_SamBridge;
|
delete m_SamBridge;
|
||||||
delete m_BOBCommandChannel;
|
delete m_BOBCommandChannel;
|
||||||
delete m_I2PControlService;
|
delete m_I2PControlService;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientContext::Start ()
|
void ClientContext::Start ()
|
||||||
{
|
{
|
||||||
if (!m_SharedLocalDestination)
|
if (!m_SharedLocalDestination)
|
||||||
{
|
{
|
||||||
m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA
|
m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA
|
||||||
m_Destinations[m_SharedLocalDestination->GetIdentity ().GetIdentHash ()] = m_SharedLocalDestination;
|
m_Destinations[m_SharedLocalDestination->GetIdentity ().GetIdentHash ()] = m_SharedLocalDestination;
|
||||||
m_SharedLocalDestination->Start ();
|
m_SharedLocalDestination->Start ();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> localDestination;
|
std::shared_ptr<ClientDestination> localDestination;
|
||||||
// proxies
|
// proxies
|
||||||
std::string proxyKeys = i2p::util::config::GetArg("-proxykeys", "");
|
std::string proxyKeys = i2p::util::config::GetArg("-proxykeys", "");
|
||||||
if (proxyKeys.length () > 0)
|
if (proxyKeys.length () > 0)
|
||||||
localDestination = LoadLocalDestination (proxyKeys, false);
|
localDestination = LoadLocalDestination (proxyKeys, false);
|
||||||
m_HttpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyport", 4446), localDestination);
|
m_HttpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyport", 4446), localDestination);
|
||||||
m_HttpProxy->Start();
|
m_HttpProxy->Start();
|
||||||
LogPrint("HTTP Proxy started");
|
LogPrint("HTTP Proxy started");
|
||||||
m_SocksProxy = new i2p::proxy::SOCKSProxy(i2p::util::config::GetArg("-socksproxyport", 4447), localDestination);
|
m_SocksProxy = new i2p::proxy::SOCKSProxy(i2p::util::config::GetArg("-socksproxyport", 4447), localDestination);
|
||||||
m_SocksProxy->Start();
|
m_SocksProxy->Start();
|
||||||
LogPrint("SOCKS Proxy Started");
|
LogPrint("SOCKS Proxy Started");
|
||||||
|
|
||||||
// I2P tunnels
|
// I2P tunnels
|
||||||
std::string ircDestination = i2p::util::config::GetArg("-ircdest", "");
|
std::string ircDestination = i2p::util::config::GetArg("-ircdest", "");
|
||||||
if (ircDestination.length () > 0) // ircdest is presented
|
if (ircDestination.length () > 0) // ircdest is presented
|
||||||
{
|
{
|
||||||
localDestination = nullptr;
|
localDestination = nullptr;
|
||||||
std::string ircKeys = i2p::util::config::GetArg("-irckeys", "");
|
std::string ircKeys = i2p::util::config::GetArg("-irckeys", "");
|
||||||
if (ircKeys.length () > 0)
|
if (ircKeys.length () > 0)
|
||||||
localDestination = LoadLocalDestination (ircKeys, false);
|
localDestination = LoadLocalDestination (ircKeys, false);
|
||||||
auto ircPort = i2p::util::config::GetArg("-ircport", 6668);
|
auto ircPort = i2p::util::config::GetArg("-ircport", 6668);
|
||||||
auto ircTunnel = new I2PClientTunnel (ircDestination, ircPort, localDestination);
|
auto ircTunnel = new I2PClientTunnel (ircDestination, ircPort, localDestination);
|
||||||
ircTunnel->Start ();
|
ircTunnel->Start ();
|
||||||
m_ClientTunnels.insert (std::make_pair(ircPort, std::unique_ptr<I2PClientTunnel>(ircTunnel)));
|
m_ClientTunnels.insert (std::make_pair(ircPort, std::unique_ptr<I2PClientTunnel>(ircTunnel)));
|
||||||
LogPrint("IRC tunnel started");
|
LogPrint("IRC tunnel started");
|
||||||
}
|
}
|
||||||
std::string eepKeys = i2p::util::config::GetArg("-eepkeys", "");
|
std::string eepKeys = i2p::util::config::GetArg("-eepkeys", "");
|
||||||
if (eepKeys.length () > 0) // eepkeys file is presented
|
if (eepKeys.length () > 0) // eepkeys file is presented
|
||||||
{
|
{
|
||||||
localDestination = LoadLocalDestination (eepKeys, true);
|
localDestination = LoadLocalDestination (eepKeys, true);
|
||||||
auto serverTunnel = new I2PServerTunnel (i2p::util::config::GetArg("-eephost", "127.0.0.1"),
|
auto serverTunnel = new I2PServerTunnel (i2p::util::config::GetArg("-eephost", "127.0.0.1"),
|
||||||
i2p::util::config::GetArg("-eepport", 80), localDestination);
|
i2p::util::config::GetArg("-eepport", 80), localDestination);
|
||||||
serverTunnel->Start ();
|
serverTunnel->Start ();
|
||||||
m_ServerTunnels.insert (std::make_pair(localDestination->GetIdentHash (), std::unique_ptr<I2PServerTunnel>(serverTunnel)));
|
m_ServerTunnels.insert (std::make_pair(localDestination->GetIdentHash (), std::unique_ptr<I2PServerTunnel>(serverTunnel)));
|
||||||
LogPrint("Server tunnel started");
|
LogPrint("Server tunnel started");
|
||||||
}
|
}
|
||||||
ReadTunnels ();
|
ReadTunnels ();
|
||||||
|
|
||||||
// SAM
|
// SAM
|
||||||
int samPort = i2p::util::config::GetArg("-samport", 0);
|
int samPort = i2p::util::config::GetArg("-samport", 0);
|
||||||
if (samPort)
|
if (samPort)
|
||||||
{
|
{
|
||||||
m_SamBridge = new SAMBridge (samPort);
|
m_SamBridge = new SAMBridge (samPort);
|
||||||
m_SamBridge->Start ();
|
m_SamBridge->Start ();
|
||||||
LogPrint("SAM bridge started");
|
LogPrint("SAM bridge started");
|
||||||
}
|
}
|
||||||
|
|
||||||
// BOB
|
// BOB
|
||||||
int bobPort = i2p::util::config::GetArg("-bobport", 0);
|
int bobPort = i2p::util::config::GetArg("-bobport", 0);
|
||||||
if (bobPort)
|
if (bobPort)
|
||||||
{
|
{
|
||||||
m_BOBCommandChannel = new BOBCommandChannel (bobPort);
|
m_BOBCommandChannel = new BOBCommandChannel (bobPort);
|
||||||
m_BOBCommandChannel->Start ();
|
m_BOBCommandChannel->Start ();
|
||||||
LogPrint("BOB command channel started");
|
LogPrint("BOB command channel started");
|
||||||
}
|
}
|
||||||
|
|
||||||
// I2P Control
|
// I2P Control
|
||||||
int i2pcontrolPort = i2p::util::config::GetArg("-i2pcontrolport", 0);
|
int i2pcontrolPort = i2p::util::config::GetArg("-i2pcontrolport", 0);
|
||||||
if (i2pcontrolPort)
|
if (i2pcontrolPort)
|
||||||
{
|
{
|
||||||
m_I2PControlService = new I2PControlService (i2pcontrolPort);
|
m_I2PControlService = new I2PControlService (i2pcontrolPort);
|
||||||
m_I2PControlService->Start ();
|
m_I2PControlService->Start ();
|
||||||
LogPrint("I2PControl started");
|
LogPrint("I2PControl started");
|
||||||
}
|
}
|
||||||
m_AddressBook.Start ();
|
m_AddressBook.Start ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientContext::Stop ()
|
void ClientContext::Stop ()
|
||||||
{
|
{
|
||||||
m_HttpProxy->Stop();
|
m_HttpProxy->Stop();
|
||||||
delete m_HttpProxy;
|
delete m_HttpProxy;
|
||||||
m_HttpProxy = nullptr;
|
m_HttpProxy = nullptr;
|
||||||
LogPrint("HTTP Proxy stopped");
|
LogPrint("HTTP Proxy stopped");
|
||||||
m_SocksProxy->Stop();
|
m_SocksProxy->Stop();
|
||||||
delete m_SocksProxy;
|
delete m_SocksProxy;
|
||||||
m_SocksProxy = nullptr;
|
m_SocksProxy = nullptr;
|
||||||
LogPrint("SOCKS Proxy stopped");
|
LogPrint("SOCKS Proxy stopped");
|
||||||
for (auto& it: m_ClientTunnels)
|
for (auto& it: m_ClientTunnels)
|
||||||
{
|
{
|
||||||
it.second->Stop ();
|
it.second->Stop ();
|
||||||
LogPrint("I2P client tunnel on port ", it.first, " stopped");
|
LogPrint("I2P client tunnel on port ", it.first, " stopped");
|
||||||
}
|
}
|
||||||
m_ClientTunnels.clear ();
|
m_ClientTunnels.clear ();
|
||||||
for (auto& it: m_ServerTunnels)
|
for (auto& it: m_ServerTunnels)
|
||||||
{
|
{
|
||||||
it.second->Stop ();
|
it.second->Stop ();
|
||||||
LogPrint("I2P server tunnel stopped");
|
LogPrint("I2P server tunnel stopped");
|
||||||
}
|
}
|
||||||
m_ServerTunnels.clear ();
|
m_ServerTunnels.clear ();
|
||||||
if (m_SamBridge)
|
if (m_SamBridge)
|
||||||
{
|
{
|
||||||
m_SamBridge->Stop ();
|
m_SamBridge->Stop ();
|
||||||
delete m_SamBridge;
|
delete m_SamBridge;
|
||||||
m_SamBridge = nullptr;
|
m_SamBridge = nullptr;
|
||||||
LogPrint("SAM brdige stopped");
|
LogPrint("SAM brdige stopped");
|
||||||
}
|
}
|
||||||
if (m_BOBCommandChannel)
|
if (m_BOBCommandChannel)
|
||||||
{
|
{
|
||||||
m_BOBCommandChannel->Stop ();
|
m_BOBCommandChannel->Stop ();
|
||||||
delete m_BOBCommandChannel;
|
delete m_BOBCommandChannel;
|
||||||
m_BOBCommandChannel = nullptr;
|
m_BOBCommandChannel = nullptr;
|
||||||
LogPrint("BOB command channel stopped");
|
LogPrint("BOB command channel stopped");
|
||||||
}
|
}
|
||||||
if (m_I2PControlService)
|
if (m_I2PControlService)
|
||||||
{
|
{
|
||||||
m_I2PControlService->Stop ();
|
m_I2PControlService->Stop ();
|
||||||
delete m_I2PControlService;
|
delete m_I2PControlService;
|
||||||
m_I2PControlService = nullptr;
|
m_I2PControlService = nullptr;
|
||||||
LogPrint("I2PControl stopped");
|
LogPrint("I2PControl stopped");
|
||||||
}
|
}
|
||||||
m_AddressBook.Stop ();
|
m_AddressBook.Stop ();
|
||||||
for (auto it: m_Destinations)
|
for (auto it: m_Destinations)
|
||||||
it.second->Stop ();
|
it.second->Stop ();
|
||||||
m_Destinations.clear ();
|
m_Destinations.clear ();
|
||||||
m_SharedLocalDestination = nullptr;
|
m_SharedLocalDestination = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> ClientContext::LoadLocalDestination (const std::string& filename, bool isPublic)
|
std::shared_ptr<ClientDestination> ClientContext::LoadLocalDestination (const std::string& filename, bool isPublic)
|
||||||
{
|
{
|
||||||
i2p::data::PrivateKeys keys;
|
i2p::data::PrivateKeys keys;
|
||||||
std::string fullPath = i2p::util::filesystem::GetFullPath (filename);
|
std::string fullPath = i2p::util::filesystem::GetFullPath (filename);
|
||||||
std::ifstream s(fullPath.c_str (), std::ifstream::binary);
|
std::ifstream s(fullPath.c_str (), std::ifstream::binary);
|
||||||
if (s.is_open ())
|
if (s.is_open ())
|
||||||
{
|
{
|
||||||
s.seekg (0, std::ios::end);
|
s.seekg (0, std::ios::end);
|
||||||
size_t len = s.tellg();
|
size_t len = s.tellg();
|
||||||
s.seekg (0, std::ios::beg);
|
s.seekg (0, std::ios::beg);
|
||||||
uint8_t * buf = new uint8_t[len];
|
uint8_t * buf = new uint8_t[len];
|
||||||
s.read ((char *)buf, len);
|
s.read ((char *)buf, len);
|
||||||
keys.FromBuffer (buf, len);
|
keys.FromBuffer (buf, len);
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
LogPrint ("Local address ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " loaded");
|
LogPrint ("Local address ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " loaded");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint ("Can't open file ", fullPath, " Creating new one");
|
LogPrint ("Can't open file ", fullPath, " Creating new one");
|
||||||
keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
||||||
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
||||||
size_t len = keys.GetFullLen ();
|
size_t len = keys.GetFullLen ();
|
||||||
uint8_t * buf = new uint8_t[len];
|
uint8_t * buf = new uint8_t[len];
|
||||||
len = keys.ToBuffer (buf, len);
|
len = keys.ToBuffer (buf, len);
|
||||||
f.write ((char *)buf, len);
|
f.write ((char *)buf, len);
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
|
|
||||||
LogPrint ("New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " created");
|
LogPrint ("New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " created");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||||
auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ());
|
auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ());
|
||||||
if (it != m_Destinations.end ())
|
if (it != m_Destinations.end ())
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Local destination ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " alreday exists");
|
LogPrint (eLogWarning, "Local destination ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " alreday exists");
|
||||||
localDestination = it->second;
|
localDestination = it->second;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
localDestination = std::make_shared<ClientDestination> (keys, isPublic);
|
localDestination = std::make_shared<ClientDestination> (keys, isPublic);
|
||||||
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
||||||
localDestination->Start ();
|
localDestination->Start ();
|
||||||
}
|
}
|
||||||
return localDestination;
|
return localDestination;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
|
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
|
||||||
const std::map<std::string, std::string> * params)
|
const std::map<std::string, std::string> * params)
|
||||||
{
|
{
|
||||||
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
||||||
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
|
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
|
||||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||||
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
||||||
localDestination->Start ();
|
localDestination->Start ();
|
||||||
return localDestination;
|
return localDestination;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientContext::DeleteLocalDestination (std::shared_ptr<ClientDestination> destination)
|
void ClientContext::DeleteLocalDestination (std::shared_ptr<ClientDestination> destination)
|
||||||
{
|
{
|
||||||
if (!destination) return;
|
if (!destination) return;
|
||||||
auto it = m_Destinations.find (destination->GetIdentHash ());
|
auto it = m_Destinations.find (destination->GetIdentHash ());
|
||||||
if (it != m_Destinations.end ())
|
if (it != m_Destinations.end ())
|
||||||
{
|
{
|
||||||
auto d = it->second;
|
auto d = it->second;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||||
m_Destinations.erase (it);
|
m_Destinations.erase (it);
|
||||||
}
|
}
|
||||||
d->Stop ();
|
d->Stop ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
|
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
|
||||||
const std::map<std::string, std::string> * params)
|
const std::map<std::string, std::string> * params)
|
||||||
{
|
{
|
||||||
auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ());
|
auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ());
|
||||||
if (it != m_Destinations.end ())
|
if (it != m_Destinations.end ())
|
||||||
{
|
{
|
||||||
LogPrint ("Local destination ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " exists");
|
LogPrint ("Local destination ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " exists");
|
||||||
if (!it->second->IsRunning ())
|
if (!it->second->IsRunning ())
|
||||||
{
|
{
|
||||||
it->second->Start ();
|
it->second->Start ();
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
|
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
|
||||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||||
m_Destinations[keys.GetPublic ().GetIdentHash ()] = localDestination;
|
m_Destinations[keys.GetPublic ().GetIdentHash ()] = localDestination;
|
||||||
localDestination->Start ();
|
localDestination->Start ();
|
||||||
return localDestination;
|
return localDestination;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const
|
std::shared_ptr<ClientDestination> ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const
|
||||||
{
|
{
|
||||||
auto it = m_Destinations.find (destination);
|
auto it = m_Destinations.find (destination);
|
||||||
if (it != m_Destinations.end ())
|
if (it != m_Destinations.end ())
|
||||||
return it->second;
|
return it->second;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientContext::ReadTunnels ()
|
void ClientContext::ReadTunnels ()
|
||||||
{
|
{
|
||||||
boost::property_tree::ptree pt;
|
boost::property_tree::ptree pt;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
boost::property_tree::read_ini (i2p::util::filesystem::GetFullPath (TUNNELS_CONFIG_FILENAME), pt);
|
boost::property_tree::read_ini (i2p::util::filesystem::GetFullPath (TUNNELS_CONFIG_FILENAME), pt);
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Can't read ", TUNNELS_CONFIG_FILENAME, ": ", ex.what ());
|
LogPrint (eLogWarning, "Can't read ", TUNNELS_CONFIG_FILENAME, ": ", ex.what ());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int numClientTunnels = 0, numServerTunnels = 0;
|
int numClientTunnels = 0, numServerTunnels = 0;
|
||||||
for (auto& section: pt)
|
for (auto& section: pt)
|
||||||
{
|
{
|
||||||
std::string name = section.first;
|
std::string name = section.first;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::string type = section.second.get<std::string> (I2P_TUNNELS_SECTION_TYPE);
|
std::string type = section.second.get<std::string> (I2P_TUNNELS_SECTION_TYPE);
|
||||||
if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT)
|
if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT)
|
||||||
{
|
{
|
||||||
// mandatory params
|
// mandatory params
|
||||||
std::string dest = section.second.get<std::string> (I2P_CLIENT_TUNNEL_DESTINATION);
|
std::string dest = section.second.get<std::string> (I2P_CLIENT_TUNNEL_DESTINATION);
|
||||||
int port = section.second.get<int> (I2P_CLIENT_TUNNEL_PORT);
|
int port = section.second.get<int> (I2P_CLIENT_TUNNEL_PORT);
|
||||||
// optional params
|
// optional params
|
||||||
std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, "");
|
std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, "");
|
||||||
int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0);
|
int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0);
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||||
if (keys.length () > 0)
|
if (keys.length () > 0)
|
||||||
localDestination = LoadLocalDestination (keys, false);
|
localDestination = LoadLocalDestination (keys, false);
|
||||||
auto clientTunnel = new I2PClientTunnel (dest, port, localDestination, destinationPort);
|
auto clientTunnel = new I2PClientTunnel (dest, port, localDestination, destinationPort);
|
||||||
if (m_ClientTunnels.insert (std::make_pair (port, std::unique_ptr<I2PClientTunnel>(clientTunnel))).second)
|
if (m_ClientTunnels.insert (std::make_pair (port, std::unique_ptr<I2PClientTunnel>(clientTunnel))).second)
|
||||||
clientTunnel->Start ();
|
clientTunnel->Start ();
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "I2P client tunnel with port ", port, " already exists");
|
LogPrint (eLogError, "I2P client tunnel with port ", port, " already exists");
|
||||||
numClientTunnels++;
|
numClientTunnels++;
|
||||||
}
|
}
|
||||||
else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER || type == I2P_TUNNELS_SECTION_TYPE_HTTP)
|
else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER || type == I2P_TUNNELS_SECTION_TYPE_HTTP)
|
||||||
{
|
{
|
||||||
// mandatory params
|
// mandatory params
|
||||||
std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST);
|
std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST);
|
||||||
int port = section.second.get<int> (I2P_SERVER_TUNNEL_PORT);
|
int port = section.second.get<int> (I2P_SERVER_TUNNEL_PORT);
|
||||||
std::string keys = section.second.get<std::string> (I2P_SERVER_TUNNEL_KEYS);
|
std::string keys = section.second.get<std::string> (I2P_SERVER_TUNNEL_KEYS);
|
||||||
// optional params
|
// optional params
|
||||||
int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0);
|
int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0);
|
||||||
std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
|
std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
|
||||||
|
|
||||||
auto localDestination = LoadLocalDestination (keys, true);
|
auto localDestination = LoadLocalDestination (keys, true);
|
||||||
I2PServerTunnel * serverTunnel = (type == I2P_TUNNELS_SECTION_TYPE_HTTP) ? new I2PServerTunnelHTTP (host, port, localDestination, inPort) : new I2PServerTunnel (host, port, localDestination, inPort);
|
I2PServerTunnel * serverTunnel = (type == I2P_TUNNELS_SECTION_TYPE_HTTP) ? new I2PServerTunnelHTTP (host, port, localDestination, inPort) : new I2PServerTunnel (host, port, localDestination, inPort);
|
||||||
if (accessList.length () > 0)
|
if (accessList.length () > 0)
|
||||||
{
|
{
|
||||||
std::set<i2p::data::IdentHash> idents;
|
std::set<i2p::data::IdentHash> idents;
|
||||||
size_t pos = 0, comma;
|
size_t pos = 0, comma;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
comma = accessList.find (',', pos);
|
comma = accessList.find (',', pos);
|
||||||
i2p::data::IdentHash ident;
|
i2p::data::IdentHash ident;
|
||||||
ident.FromBase32 (accessList.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos));
|
ident.FromBase32 (accessList.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos));
|
||||||
idents.insert (ident);
|
idents.insert (ident);
|
||||||
pos = comma + 1;
|
pos = comma + 1;
|
||||||
}
|
}
|
||||||
while (comma != std::string::npos);
|
while (comma != std::string::npos);
|
||||||
serverTunnel->SetAccessList (idents);
|
serverTunnel->SetAccessList (idents);
|
||||||
}
|
}
|
||||||
if (m_ServerTunnels.insert (std::make_pair (localDestination->GetIdentHash (), std::unique_ptr<I2PServerTunnel>(serverTunnel))).second)
|
if (m_ServerTunnels.insert (std::make_pair (localDestination->GetIdentHash (), std::unique_ptr<I2PServerTunnel>(serverTunnel))).second)
|
||||||
serverTunnel->Start ();
|
serverTunnel->Start ();
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "I2P server tunnel for destination ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), " already exists");
|
LogPrint (eLogError, "I2P server tunnel for destination ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), " already exists");
|
||||||
numServerTunnels++;
|
numServerTunnels++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Unknown section type=", type, " of ", name, " in ", TUNNELS_CONFIG_FILENAME);
|
LogPrint (eLogWarning, "Unknown section type=", type, " of ", name, " in ", TUNNELS_CONFIG_FILENAME);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Can't read tunnel ", name, " params: ", ex.what ());
|
LogPrint (eLogError, "Can't read tunnel ", name, " params: ", ex.what ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogPrint (eLogInfo, numClientTunnels, " I2P client tunnels created");
|
LogPrint (eLogInfo, numClientTunnels, " I2P client tunnels created");
|
||||||
LogPrint (eLogInfo, numServerTunnels, " I2P server tunnels created");
|
LogPrint (eLogInfo, numServerTunnels, " I2P server tunnels created");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
110
ClientContext.h
110
ClientContext.h
|
@ -17,70 +17,70 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
const char I2P_TUNNELS_SECTION_TYPE[] = "type";
|
const char I2P_TUNNELS_SECTION_TYPE[] = "type";
|
||||||
const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client";
|
const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client";
|
||||||
const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server";
|
const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server";
|
||||||
const char I2P_TUNNELS_SECTION_TYPE_HTTP[] = "http";
|
const char I2P_TUNNELS_SECTION_TYPE_HTTP[] = "http";
|
||||||
const char I2P_CLIENT_TUNNEL_PORT[] = "port";
|
const char I2P_CLIENT_TUNNEL_PORT[] = "port";
|
||||||
const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination";
|
const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination";
|
||||||
const char I2P_CLIENT_TUNNEL_KEYS[] = "keys";
|
const char I2P_CLIENT_TUNNEL_KEYS[] = "keys";
|
||||||
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
|
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
|
||||||
const char I2P_SERVER_TUNNEL_HOST[] = "host";
|
const char I2P_SERVER_TUNNEL_HOST[] = "host";
|
||||||
const char I2P_SERVER_TUNNEL_PORT[] = "port";
|
const char I2P_SERVER_TUNNEL_PORT[] = "port";
|
||||||
const char I2P_SERVER_TUNNEL_KEYS[] = "keys";
|
const char I2P_SERVER_TUNNEL_KEYS[] = "keys";
|
||||||
const char I2P_SERVER_TUNNEL_INPORT[] = "inport";
|
const char I2P_SERVER_TUNNEL_INPORT[] = "inport";
|
||||||
const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist";
|
const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist";
|
||||||
const char TUNNELS_CONFIG_FILENAME[] = "tunnels.cfg";
|
const char TUNNELS_CONFIG_FILENAME[] = "tunnels.cfg";
|
||||||
|
|
||||||
class ClientContext
|
class ClientContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ClientContext ();
|
ClientContext ();
|
||||||
~ClientContext ();
|
~ClientContext ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> GetSharedLocalDestination () const { return m_SharedLocalDestination; };
|
std::shared_ptr<ClientDestination> GetSharedLocalDestination () const { return m_SharedLocalDestination; };
|
||||||
std::shared_ptr<ClientDestination> CreateNewLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1,
|
std::shared_ptr<ClientDestination> CreateNewLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1,
|
||||||
const std::map<std::string, std::string> * params = nullptr); // transient
|
const std::map<std::string, std::string> * params = nullptr); // transient
|
||||||
std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
||||||
const std::map<std::string, std::string> * params = nullptr);
|
const std::map<std::string, std::string> * params = nullptr);
|
||||||
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
|
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
|
||||||
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
|
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
|
||||||
std::shared_ptr<ClientDestination> LoadLocalDestination (const std::string& filename, bool isPublic);
|
std::shared_ptr<ClientDestination> LoadLocalDestination (const std::string& filename, bool isPublic);
|
||||||
|
|
||||||
AddressBook& GetAddressBook () { return m_AddressBook; };
|
AddressBook& GetAddressBook () { return m_AddressBook; };
|
||||||
const SAMBridge * GetSAMBridge () const { return m_SamBridge; };
|
const SAMBridge * GetSAMBridge () const { return m_SamBridge; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void ReadTunnels ();
|
void ReadTunnels ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::mutex m_DestinationsMutex;
|
std::mutex m_DestinationsMutex;
|
||||||
std::map<i2p::data::IdentHash, std::shared_ptr<ClientDestination> > m_Destinations;
|
std::map<i2p::data::IdentHash, std::shared_ptr<ClientDestination> > m_Destinations;
|
||||||
std::shared_ptr<ClientDestination> m_SharedLocalDestination;
|
std::shared_ptr<ClientDestination> m_SharedLocalDestination;
|
||||||
|
|
||||||
AddressBook m_AddressBook;
|
AddressBook m_AddressBook;
|
||||||
|
|
||||||
i2p::proxy::HTTPProxy * m_HttpProxy;
|
i2p::proxy::HTTPProxy * m_HttpProxy;
|
||||||
i2p::proxy::SOCKSProxy * m_SocksProxy;
|
i2p::proxy::SOCKSProxy * m_SocksProxy;
|
||||||
std::map<int, std::unique_ptr<I2PClientTunnel> > m_ClientTunnels; // port->tunnel
|
std::map<int, std::unique_ptr<I2PClientTunnel> > m_ClientTunnels; // port->tunnel
|
||||||
std::map<i2p::data::IdentHash, std::unique_ptr<I2PServerTunnel> > m_ServerTunnels; // destination->tunnel
|
std::map<i2p::data::IdentHash, std::unique_ptr<I2PServerTunnel> > m_ServerTunnels; // destination->tunnel
|
||||||
SAMBridge * m_SamBridge;
|
SAMBridge * m_SamBridge;
|
||||||
BOBCommandChannel * m_BOBCommandChannel;
|
BOBCommandChannel * m_BOBCommandChannel;
|
||||||
I2PControlService * m_I2PControlService;
|
I2PControlService * m_I2PControlService;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// for HTTP
|
// for HTTP
|
||||||
const decltype(m_Destinations)& GetDestinations () const { return m_Destinations; };
|
const decltype(m_Destinations)& GetDestinations () const { return m_Destinations; };
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ClientContext context;
|
extern ClientContext context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
120
CryptoConst.cpp
120
CryptoConst.cpp
|
@ -5,69 +5,69 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace crypto
|
namespace crypto
|
||||||
{
|
{
|
||||||
const uint8_t elgp_[256]=
|
const uint8_t elgp_[256]=
|
||||||
{
|
{
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
||||||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
||||||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
|
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
|
||||||
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
|
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
|
||||||
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
||||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
|
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
|
||||||
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
|
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
|
||||||
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
|
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
|
||||||
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
|
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
|
||||||
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
|
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
|
||||||
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
|
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
|
||||||
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
|
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
|
||||||
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
|
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
|
||||||
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
|
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
|
||||||
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8_t dsap_[128]=
|
const uint8_t dsap_[128]=
|
||||||
{
|
{
|
||||||
0x9c, 0x05, 0xb2, 0xaa, 0x96, 0x0d, 0x9b, 0x97, 0xb8, 0x93, 0x19, 0x63, 0xc9, 0xcc, 0x9e, 0x8c,
|
0x9c, 0x05, 0xb2, 0xaa, 0x96, 0x0d, 0x9b, 0x97, 0xb8, 0x93, 0x19, 0x63, 0xc9, 0xcc, 0x9e, 0x8c,
|
||||||
0x30, 0x26, 0xe9, 0xb8, 0xed, 0x92, 0xfa, 0xd0, 0xa6, 0x9c, 0xc8, 0x86, 0xd5, 0xbf, 0x80, 0x15,
|
0x30, 0x26, 0xe9, 0xb8, 0xed, 0x92, 0xfa, 0xd0, 0xa6, 0x9c, 0xc8, 0x86, 0xd5, 0xbf, 0x80, 0x15,
|
||||||
0xfc, 0xad, 0xae, 0x31, 0xa0, 0xad, 0x18, 0xfa, 0xb3, 0xf0, 0x1b, 0x00, 0xa3, 0x58, 0xde, 0x23,
|
0xfc, 0xad, 0xae, 0x31, 0xa0, 0xad, 0x18, 0xfa, 0xb3, 0xf0, 0x1b, 0x00, 0xa3, 0x58, 0xde, 0x23,
|
||||||
0x76, 0x55, 0xc4, 0x96, 0x4a, 0xfa, 0xa2, 0xb3, 0x37, 0xe9, 0x6a, 0xd3, 0x16, 0xb9, 0xfb, 0x1c,
|
0x76, 0x55, 0xc4, 0x96, 0x4a, 0xfa, 0xa2, 0xb3, 0x37, 0xe9, 0x6a, 0xd3, 0x16, 0xb9, 0xfb, 0x1c,
|
||||||
0xc5, 0x64, 0xb5, 0xae, 0xc5, 0xb6, 0x9a, 0x9f, 0xf6, 0xc3, 0xe4, 0x54, 0x87, 0x07, 0xfe, 0xf8,
|
0xc5, 0x64, 0xb5, 0xae, 0xc5, 0xb6, 0x9a, 0x9f, 0xf6, 0xc3, 0xe4, 0x54, 0x87, 0x07, 0xfe, 0xf8,
|
||||||
0x50, 0x3d, 0x91, 0xdd, 0x86, 0x02, 0xe8, 0x67, 0xe6, 0xd3, 0x5d, 0x22, 0x35, 0xc1, 0x86, 0x9c,
|
0x50, 0x3d, 0x91, 0xdd, 0x86, 0x02, 0xe8, 0x67, 0xe6, 0xd3, 0x5d, 0x22, 0x35, 0xc1, 0x86, 0x9c,
|
||||||
0xe2, 0x47, 0x9c, 0x3b, 0x9d, 0x54, 0x01, 0xde, 0x04, 0xe0, 0x72, 0x7f, 0xb3, 0x3d, 0x65, 0x11,
|
0xe2, 0x47, 0x9c, 0x3b, 0x9d, 0x54, 0x01, 0xde, 0x04, 0xe0, 0x72, 0x7f, 0xb3, 0x3d, 0x65, 0x11,
|
||||||
0x28, 0x5d, 0x4c, 0xf2, 0x95, 0x38, 0xd9, 0xe3, 0xb6, 0x05, 0x1f, 0x5b, 0x22, 0xcc, 0x1c, 0x93
|
0x28, 0x5d, 0x4c, 0xf2, 0x95, 0x38, 0xd9, 0xe3, 0xb6, 0x05, 0x1f, 0x5b, 0x22, 0xcc, 0x1c, 0x93
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8_t dsaq_[20]=
|
const uint8_t dsaq_[20]=
|
||||||
{
|
{
|
||||||
0xa5, 0xdf, 0xc2, 0x8f, 0xef, 0x4c, 0xa1, 0xe2, 0x86, 0x74, 0x4c, 0xd8, 0xee, 0xd9, 0xd2, 0x9d,
|
0xa5, 0xdf, 0xc2, 0x8f, 0xef, 0x4c, 0xa1, 0xe2, 0x86, 0x74, 0x4c, 0xd8, 0xee, 0xd9, 0xd2, 0x9d,
|
||||||
0x68, 0x40, 0x46, 0xb7
|
0x68, 0x40, 0x46, 0xb7
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8_t dsag_[128]=
|
const uint8_t dsag_[128]=
|
||||||
{
|
{
|
||||||
0x0c, 0x1f, 0x4d, 0x27, 0xd4, 0x00, 0x93, 0xb4, 0x29, 0xe9, 0x62, 0xd7, 0x22, 0x38, 0x24, 0xe0,
|
0x0c, 0x1f, 0x4d, 0x27, 0xd4, 0x00, 0x93, 0xb4, 0x29, 0xe9, 0x62, 0xd7, 0x22, 0x38, 0x24, 0xe0,
|
||||||
0xbb, 0xc4, 0x7e, 0x7c, 0x83, 0x2a, 0x39, 0x23, 0x6f, 0xc6, 0x83, 0xaf, 0x84, 0x88, 0x95, 0x81,
|
0xbb, 0xc4, 0x7e, 0x7c, 0x83, 0x2a, 0x39, 0x23, 0x6f, 0xc6, 0x83, 0xaf, 0x84, 0x88, 0x95, 0x81,
|
||||||
0x07, 0x5f, 0xf9, 0x08, 0x2e, 0xd3, 0x23, 0x53, 0xd4, 0x37, 0x4d, 0x73, 0x01, 0xcd, 0xa1, 0xd2,
|
0x07, 0x5f, 0xf9, 0x08, 0x2e, 0xd3, 0x23, 0x53, 0xd4, 0x37, 0x4d, 0x73, 0x01, 0xcd, 0xa1, 0xd2,
|
||||||
0x3c, 0x43, 0x1f, 0x46, 0x98, 0x59, 0x9d, 0xda, 0x02, 0x45, 0x18, 0x24, 0xff, 0x36, 0x97, 0x52,
|
0x3c, 0x43, 0x1f, 0x46, 0x98, 0x59, 0x9d, 0xda, 0x02, 0x45, 0x18, 0x24, 0xff, 0x36, 0x97, 0x52,
|
||||||
0x59, 0x36, 0x47, 0xcc, 0x3d, 0xdc, 0x19, 0x7d, 0xe9, 0x85, 0xe4, 0x3d, 0x13, 0x6c, 0xdc, 0xfc,
|
0x59, 0x36, 0x47, 0xcc, 0x3d, 0xdc, 0x19, 0x7d, 0xe9, 0x85, 0xe4, 0x3d, 0x13, 0x6c, 0xdc, 0xfc,
|
||||||
0x6b, 0xd5, 0x40, 0x9c, 0xd2, 0xf4, 0x50, 0x82, 0x11, 0x42, 0xa5, 0xe6, 0xf8, 0xeb, 0x1c, 0x3a,
|
0x6b, 0xd5, 0x40, 0x9c, 0xd2, 0xf4, 0x50, 0x82, 0x11, 0x42, 0xa5, 0xe6, 0xf8, 0xeb, 0x1c, 0x3a,
|
||||||
0xb5, 0xd0, 0x48, 0x4b, 0x81, 0x29, 0xfc, 0xf1, 0x7b, 0xce, 0x4f, 0x7f, 0x33, 0x32, 0x1c, 0x3c,
|
0xb5, 0xd0, 0x48, 0x4b, 0x81, 0x29, 0xfc, 0xf1, 0x7b, 0xce, 0x4f, 0x7f, 0x33, 0x32, 0x1c, 0x3c,
|
||||||
0xb3, 0xdb, 0xb1, 0x4a, 0x90, 0x5e, 0x7b, 0x2b, 0x3e, 0x93, 0xbe, 0x47, 0x08, 0xcb, 0xcc, 0x82
|
0xb3, 0xdb, 0xb1, 0x4a, 0x90, 0x5e, 0x7b, 0x2b, 0x3e, 0x93, 0xbe, 0x47, 0x08, 0xcb, 0xcc, 0x82
|
||||||
};
|
};
|
||||||
|
|
||||||
const CryptoConstants& GetCryptoConstants ()
|
const CryptoConstants& GetCryptoConstants ()
|
||||||
{
|
{
|
||||||
static CryptoConstants cryptoConstants =
|
static CryptoConstants cryptoConstants =
|
||||||
{
|
{
|
||||||
{elgp_, 256}, // elgp
|
{elgp_, 256}, // elgp
|
||||||
{2}, // elgg
|
{2}, // elgg
|
||||||
{dsap_, 128}, // dsap
|
{dsap_, 128}, // dsap
|
||||||
{dsaq_, 20}, // dsaq
|
{dsaq_, 20}, // dsaq
|
||||||
{dsag_, 128} // dsag
|
{dsag_, 128} // dsag
|
||||||
};
|
};
|
||||||
return cryptoConstants;
|
return cryptoConstants;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,32 +7,32 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace crypto
|
namespace crypto
|
||||||
{
|
{
|
||||||
struct CryptoConstants
|
struct CryptoConstants
|
||||||
{
|
{
|
||||||
// DH/ElGamal
|
// DH/ElGamal
|
||||||
const CryptoPP::Integer elgp;
|
const CryptoPP::Integer elgp;
|
||||||
const CryptoPP::Integer elgg;
|
const CryptoPP::Integer elgg;
|
||||||
|
|
||||||
// DSA
|
// DSA
|
||||||
const CryptoPP::Integer dsap;
|
const CryptoPP::Integer dsap;
|
||||||
const CryptoPP::Integer dsaq;
|
const CryptoPP::Integer dsaq;
|
||||||
const CryptoPP::Integer dsag;
|
const CryptoPP::Integer dsag;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CryptoConstants& GetCryptoConstants ();
|
const CryptoConstants& GetCryptoConstants ();
|
||||||
|
|
||||||
// DH/ElGamal
|
// DH/ElGamal
|
||||||
#define elgp GetCryptoConstants ().elgp
|
#define elgp GetCryptoConstants ().elgp
|
||||||
#define elgg GetCryptoConstants ().elgg
|
#define elgg GetCryptoConstants ().elgg
|
||||||
|
|
||||||
// DSA
|
// DSA
|
||||||
#define dsap GetCryptoConstants ().dsap
|
#define dsap GetCryptoConstants ().dsap
|
||||||
#define dsaq GetCryptoConstants ().dsaq
|
#define dsaq GetCryptoConstants ().dsaq
|
||||||
#define dsag GetCryptoConstants ().dsag
|
#define dsag GetCryptoConstants ().dsag
|
||||||
|
|
||||||
// RSA
|
// RSA
|
||||||
const int rsae = 65537;
|
const int rsae = 65537;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
200
Daemon.cpp
200
Daemon.cpp
|
@ -20,125 +20,125 @@
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
class Daemon_Singleton::Daemon_Singleton_Private
|
class Daemon_Singleton::Daemon_Singleton_Private
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Daemon_Singleton_Private() : httpServer(nullptr)
|
Daemon_Singleton_Private() : httpServer(nullptr)
|
||||||
{};
|
{};
|
||||||
~Daemon_Singleton_Private()
|
~Daemon_Singleton_Private()
|
||||||
{
|
{
|
||||||
delete httpServer;
|
delete httpServer;
|
||||||
};
|
};
|
||||||
|
|
||||||
i2p::util::HTTPServer *httpServer;
|
i2p::util::HTTPServer *httpServer;
|
||||||
};
|
};
|
||||||
|
|
||||||
Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {};
|
Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {};
|
||||||
Daemon_Singleton::~Daemon_Singleton() {
|
Daemon_Singleton::~Daemon_Singleton() {
|
||||||
delete &d;
|
delete &d;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Daemon_Singleton::IsService () const
|
bool Daemon_Singleton::IsService () const
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
return i2p::util::config::GetArg("-service", 0);
|
return i2p::util::config::GetArg("-service", 0);
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Daemon_Singleton::init(int argc, char* argv[])
|
bool Daemon_Singleton::init(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
i2p::util::config::OptionParser(argc, argv);
|
i2p::util::config::OptionParser(argc, argv);
|
||||||
i2p::context.Init ();
|
i2p::context.Init ();
|
||||||
|
|
||||||
LogPrint("\n\n\n\ni2pd starting\n");
|
LogPrint("\n\n\n\ni2pd starting\n");
|
||||||
LogPrint("Version ", VERSION);
|
LogPrint("Version ", VERSION);
|
||||||
LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string());
|
LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string());
|
||||||
i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);
|
i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);
|
||||||
|
|
||||||
isDaemon = i2p::util::config::GetArg("-daemon", 0);
|
isDaemon = i2p::util::config::GetArg("-daemon", 0);
|
||||||
isLogging = i2p::util::config::GetArg("-log", 1);
|
isLogging = i2p::util::config::GetArg("-log", 1);
|
||||||
|
|
||||||
int port = i2p::util::config::GetArg("-port", 0);
|
int port = i2p::util::config::GetArg("-port", 0);
|
||||||
if (port)
|
if (port)
|
||||||
i2p::context.UpdatePort (port);
|
i2p::context.UpdatePort (port);
|
||||||
const char * host = i2p::util::config::GetCharArg("-host", "");
|
const char * host = i2p::util::config::GetCharArg("-host", "");
|
||||||
if (host && host[0])
|
if (host && host[0])
|
||||||
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host));
|
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host));
|
||||||
|
|
||||||
i2p::context.SetSupportsV6 (i2p::util::config::GetArg("-v6", 0));
|
i2p::context.SetSupportsV6 (i2p::util::config::GetArg("-v6", 0));
|
||||||
i2p::context.SetFloodfill (i2p::util::config::GetArg("-floodfill", 0));
|
i2p::context.SetFloodfill (i2p::util::config::GetArg("-floodfill", 0));
|
||||||
auto bandwidth = i2p::util::config::GetArg("-bandwidth", "");
|
auto bandwidth = i2p::util::config::GetArg("-bandwidth", "");
|
||||||
if (bandwidth.length () > 0)
|
if (bandwidth.length () > 0)
|
||||||
{
|
{
|
||||||
if (bandwidth[0] > 'L')
|
if (bandwidth[0] > 'L')
|
||||||
i2p::context.SetHighBandwidth ();
|
i2p::context.SetHighBandwidth ();
|
||||||
else
|
else
|
||||||
i2p::context.SetLowBandwidth ();
|
i2p::context.SetLowBandwidth ();
|
||||||
}
|
}
|
||||||
|
|
||||||
LogPrint("CMD parameters:");
|
LogPrint("CMD parameters:");
|
||||||
for (int i = 0; i < argc; ++i)
|
for (int i = 0; i < argc; ++i)
|
||||||
LogPrint(i, " ", argv[i]);
|
LogPrint(i, " ", argv[i]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Daemon_Singleton::start()
|
bool Daemon_Singleton::start()
|
||||||
{
|
{
|
||||||
// initialize log
|
// initialize log
|
||||||
if (isLogging)
|
if (isLogging)
|
||||||
{
|
{
|
||||||
if (isDaemon)
|
if (isDaemon)
|
||||||
{
|
{
|
||||||
std::string logfile_path = IsService () ? "/var/log" : i2p::util::filesystem::GetDataDir().string();
|
std::string logfile_path = IsService () ? "/var/log" : i2p::util::filesystem::GetDataDir().string();
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
logfile_path.append("/i2pd.log");
|
logfile_path.append("/i2pd.log");
|
||||||
#else
|
#else
|
||||||
logfile_path.append("\\i2pd.log");
|
logfile_path.append("\\i2pd.log");
|
||||||
#endif
|
#endif
|
||||||
StartLog (logfile_path);
|
StartLog (logfile_path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
StartLog (""); // write to stdout
|
StartLog (""); // write to stdout
|
||||||
}
|
}
|
||||||
|
|
||||||
d.httpServer = new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070));
|
d.httpServer = new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070));
|
||||||
d.httpServer->Start();
|
d.httpServer->Start();
|
||||||
LogPrint("HTTP Server started");
|
LogPrint("HTTP Server started");
|
||||||
i2p::data::netdb.Start();
|
i2p::data::netdb.Start();
|
||||||
LogPrint("NetDB started");
|
LogPrint("NetDB started");
|
||||||
i2p::transport::transports.Start();
|
i2p::transport::transports.Start();
|
||||||
LogPrint("Transports started");
|
LogPrint("Transports started");
|
||||||
i2p::tunnel::tunnels.Start();
|
i2p::tunnel::tunnels.Start();
|
||||||
LogPrint("Tunnels started");
|
LogPrint("Tunnels started");
|
||||||
i2p::client::context.Start ();
|
i2p::client::context.Start ();
|
||||||
LogPrint("Client started");
|
LogPrint("Client started");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Daemon_Singleton::stop()
|
bool Daemon_Singleton::stop()
|
||||||
{
|
{
|
||||||
LogPrint("Shutdown started.");
|
LogPrint("Shutdown started.");
|
||||||
i2p::client::context.Stop();
|
i2p::client::context.Stop();
|
||||||
LogPrint("Client stopped");
|
LogPrint("Client stopped");
|
||||||
i2p::tunnel::tunnels.Stop();
|
i2p::tunnel::tunnels.Stop();
|
||||||
LogPrint("Tunnels stopped");
|
LogPrint("Tunnels stopped");
|
||||||
i2p::transport::transports.Stop();
|
i2p::transport::transports.Stop();
|
||||||
LogPrint("Transports stopped");
|
LogPrint("Transports stopped");
|
||||||
i2p::data::netdb.Stop();
|
i2p::data::netdb.Stop();
|
||||||
LogPrint("NetDB stopped");
|
LogPrint("NetDB stopped");
|
||||||
d.httpServer->Stop();
|
d.httpServer->Stop();
|
||||||
LogPrint("HTTP Server stopped");
|
LogPrint("HTTP Server stopped");
|
||||||
|
|
||||||
StopLog ();
|
StopLog ();
|
||||||
|
|
||||||
delete d.httpServer; d.httpServer = nullptr;
|
delete d.httpServer; d.httpServer = nullptr;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
98
Daemon.h
98
Daemon.h
|
@ -9,63 +9,65 @@
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
class Daemon_Singleton_Private;
|
class Daemon_Singleton_Private;
|
||||||
class Daemon_Singleton
|
class Daemon_Singleton
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual bool init(int argc, char* argv[]);
|
virtual bool init(int argc, char* argv[]);
|
||||||
virtual bool start();
|
virtual bool start();
|
||||||
virtual bool stop();
|
virtual bool stop();
|
||||||
|
|
||||||
int isLogging;
|
int isLogging;
|
||||||
int isDaemon;
|
int isDaemon;
|
||||||
|
|
||||||
int running;
|
int running;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Daemon_Singleton();
|
Daemon_Singleton();
|
||||||
virtual ~Daemon_Singleton();
|
virtual ~Daemon_Singleton();
|
||||||
|
|
||||||
bool IsService () const;
|
bool IsService () const;
|
||||||
|
|
||||||
// d-pointer for httpServer, httpProxy, etc.
|
// d-pointer for httpServer, httpProxy, etc.
|
||||||
class Daemon_Singleton_Private;
|
class Daemon_Singleton_Private;
|
||||||
Daemon_Singleton_Private &d;
|
Daemon_Singleton_Private &d;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
class DaemonWin32 : public Daemon_Singleton
|
class DaemonWin32 : public Daemon_Singleton
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static DaemonWin32& Instance()
|
static DaemonWin32& Instance()
|
||||||
{
|
{
|
||||||
static DaemonWin32 instance;
|
static DaemonWin32 instance;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool init(int argc, char* argv[]);
|
virtual bool init(int argc, char* argv[]);
|
||||||
virtual bool start();
|
virtual bool start();
|
||||||
virtual bool stop();
|
virtual bool stop();
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
class DaemonLinux : public Daemon_Singleton
|
class DaemonLinux : public Daemon_Singleton
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static DaemonLinux& Instance()
|
DaemonLinux() = default;
|
||||||
{
|
|
||||||
static DaemonLinux instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool start();
|
static DaemonLinux& Instance()
|
||||||
virtual bool stop();
|
{
|
||||||
private:
|
static DaemonLinux instance;
|
||||||
std::string pidfile;
|
return instance;
|
||||||
int pidFilehandle;
|
}
|
||||||
|
|
||||||
};
|
virtual bool start();
|
||||||
|
virtual bool stop();
|
||||||
|
private:
|
||||||
|
std::string pidfile;
|
||||||
|
int pidFilehandle;
|
||||||
|
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
172
DaemonLinux.cpp
172
DaemonLinux.cpp
|
@ -14,106 +14,106 @@
|
||||||
|
|
||||||
void handle_signal(int sig)
|
void handle_signal(int sig)
|
||||||
{
|
{
|
||||||
switch (sig)
|
switch (sig)
|
||||||
{
|
{
|
||||||
case SIGHUP:
|
case SIGHUP:
|
||||||
if (i2p::util::config::GetArg("daemon", 0) == 1)
|
if (i2p::util::config::GetArg("daemon", 0) == 1)
|
||||||
{
|
{
|
||||||
static bool first=true;
|
static bool first=true;
|
||||||
if (first)
|
if (first)
|
||||||
{
|
{
|
||||||
first=false;
|
first=false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogPrint("Reloading config.");
|
LogPrint("Reloading config.");
|
||||||
i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);
|
i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);
|
||||||
break;
|
break;
|
||||||
case SIGABRT:
|
case SIGABRT:
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
case SIGINT:
|
case SIGINT:
|
||||||
Daemon.running = 0; // Exit loop
|
Daemon.running = 0; // Exit loop
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
bool DaemonLinux::start()
|
bool DaemonLinux::start()
|
||||||
{
|
{
|
||||||
if (isDaemon == 1)
|
if (isDaemon == 1)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid > 0) // parent
|
if (pid > 0) // parent
|
||||||
::exit (EXIT_SUCCESS);
|
::exit (EXIT_SUCCESS);
|
||||||
|
|
||||||
if (pid < 0) // error
|
if (pid < 0) // error
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// child
|
// child
|
||||||
umask(0);
|
umask(0);
|
||||||
int sid = setsid();
|
int sid = setsid();
|
||||||
if (sid < 0)
|
if (sid < 0)
|
||||||
{
|
{
|
||||||
LogPrint("Error, could not create process group.");
|
LogPrint("Error, could not create process group.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::string d(i2p::util::filesystem::GetDataDir().string ()); // make a copy
|
std::string d(i2p::util::filesystem::GetDataDir().string ()); // make a copy
|
||||||
chdir(d.c_str());
|
chdir(d.c_str());
|
||||||
|
|
||||||
// close stdin/stdout/stderr descriptors
|
// close stdin/stdout/stderr descriptors
|
||||||
::close (0);
|
::close (0);
|
||||||
::open ("/dev/null", O_RDWR);
|
::open ("/dev/null", O_RDWR);
|
||||||
::close (1);
|
::close (1);
|
||||||
::open ("/dev/null", O_RDWR);
|
::open ("/dev/null", O_RDWR);
|
||||||
::close (2);
|
::close (2);
|
||||||
::open ("/dev/null", O_RDWR);
|
::open ("/dev/null", O_RDWR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pidfile
|
// Pidfile
|
||||||
pidfile = IsService () ? "/var/run" : i2p::util::filesystem::GetDataDir().string();
|
pidfile = IsService () ? "/var/run" : i2p::util::filesystem::GetDataDir().string();
|
||||||
pidfile.append("/i2pd.pid");
|
pidfile.append("/i2pd.pid");
|
||||||
pidFilehandle = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600);
|
pidFilehandle = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600);
|
||||||
if (pidFilehandle == -1)
|
if (pidFilehandle == -1)
|
||||||
{
|
{
|
||||||
LogPrint("Error, could not create pid file (", pidfile, ")\nIs an instance already running?");
|
LogPrint("Error, could not create pid file (", pidfile, ")\nIs an instance already running?");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (lockf(pidFilehandle, F_TLOCK, 0) == -1)
|
if (lockf(pidFilehandle, F_TLOCK, 0) == -1)
|
||||||
{
|
{
|
||||||
LogPrint("Error, could not lock pid file (", pidfile, ")\nIs an instance already running?");
|
LogPrint("Error, could not lock pid file (", pidfile, ")\nIs an instance already running?");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
char pid[10];
|
char pid[10];
|
||||||
sprintf(pid, "%d\n", getpid());
|
sprintf(pid, "%d\n", getpid());
|
||||||
write(pidFilehandle, pid, strlen(pid));
|
write(pidFilehandle, pid, strlen(pid));
|
||||||
|
|
||||||
// Signal handler
|
// Signal handler
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
sa.sa_handler = handle_signal;
|
sa.sa_handler = handle_signal;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_flags = SA_RESTART;
|
sa.sa_flags = SA_RESTART;
|
||||||
sigaction(SIGHUP, &sa, 0);
|
sigaction(SIGHUP, &sa, 0);
|
||||||
sigaction(SIGABRT, &sa, 0);
|
sigaction(SIGABRT, &sa, 0);
|
||||||
sigaction(SIGTERM, &sa, 0);
|
sigaction(SIGTERM, &sa, 0);
|
||||||
sigaction(SIGINT, &sa, 0);
|
sigaction(SIGINT, &sa, 0);
|
||||||
|
|
||||||
return Daemon_Singleton::start();
|
return Daemon_Singleton::start();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DaemonLinux::stop()
|
bool DaemonLinux::stop()
|
||||||
{
|
{
|
||||||
close(pidFilehandle);
|
close(pidFilehandle);
|
||||||
unlink(pidfile.c_str());
|
unlink(pidfile.c_str());
|
||||||
|
|
||||||
return Daemon_Singleton::stop();
|
return Daemon_Singleton::stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
130
DaemonWin32.cpp
130
DaemonWin32.cpp
|
@ -8,76 +8,76 @@
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
bool DaemonWin32::init(int argc, char* argv[])
|
bool DaemonWin32::init(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
setlocale(LC_CTYPE, "");
|
setlocale(LC_CTYPE, "");
|
||||||
SetConsoleCP(1251);
|
SetConsoleCP(1251);
|
||||||
SetConsoleOutputCP(1251);
|
SetConsoleOutputCP(1251);
|
||||||
setlocale(LC_ALL, "Russian");
|
setlocale(LC_ALL, "Russian");
|
||||||
|
|
||||||
if (!Daemon_Singleton::init(argc, argv)) return false;
|
if (!Daemon_Singleton::init(argc, argv)) return false;
|
||||||
if (I2PService::isService())
|
if (I2PService::isService())
|
||||||
isDaemon = 1;
|
isDaemon = 1;
|
||||||
else
|
else
|
||||||
isDaemon = 0;
|
isDaemon = 0;
|
||||||
|
|
||||||
std::string serviceControl = i2p::util::config::GetArg("-service", "none");
|
std::string serviceControl = i2p::util::config::GetArg("-service", "none");
|
||||||
if (serviceControl == "install")
|
if (serviceControl == "install")
|
||||||
{
|
{
|
||||||
InstallService(
|
InstallService(
|
||||||
SERVICE_NAME, // Name of service
|
SERVICE_NAME, // Name of service
|
||||||
SERVICE_DISPLAY_NAME, // Name to display
|
SERVICE_DISPLAY_NAME, // Name to display
|
||||||
SERVICE_START_TYPE, // Service start type
|
SERVICE_START_TYPE, // Service start type
|
||||||
SERVICE_DEPENDENCIES, // Dependencies
|
SERVICE_DEPENDENCIES, // Dependencies
|
||||||
SERVICE_ACCOUNT, // Service running account
|
SERVICE_ACCOUNT, // Service running account
|
||||||
SERVICE_PASSWORD // Password of the account
|
SERVICE_PASSWORD // Password of the account
|
||||||
);
|
);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
else if (serviceControl == "remove")
|
else if (serviceControl == "remove")
|
||||||
{
|
{
|
||||||
UninstallService(SERVICE_NAME);
|
UninstallService(SERVICE_NAME);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
else if (serviceControl != "none")
|
else if (serviceControl != "none")
|
||||||
{
|
{
|
||||||
printf(" --service=install to install the service.\n");
|
printf(" --service=install to install the service.\n");
|
||||||
printf(" --service=remove to remove the service.\n");
|
printf(" --service=remove to remove the service.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDaemon == 1)
|
if (isDaemon == 1)
|
||||||
{
|
{
|
||||||
LogPrint("Service session");
|
LogPrint("Service session");
|
||||||
I2PService service(SERVICE_NAME);
|
I2PService service(SERVICE_NAME);
|
||||||
if (!I2PService::Run(service))
|
if (!I2PService::Run(service))
|
||||||
{
|
{
|
||||||
LogPrint("Service failed to run w/err 0x%08lx\n", GetLastError());
|
LogPrint("Service failed to run w/err 0x%08lx\n", GetLastError());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint("User session");
|
LogPrint("User session");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool DaemonWin32::start()
|
bool DaemonWin32::start()
|
||||||
{
|
{
|
||||||
setlocale(LC_CTYPE, "");
|
setlocale(LC_CTYPE, "");
|
||||||
SetConsoleCP(1251);
|
SetConsoleCP(1251);
|
||||||
SetConsoleOutputCP(1251);
|
SetConsoleOutputCP(1251);
|
||||||
setlocale(LC_ALL, "Russian");
|
setlocale(LC_ALL, "Russian");
|
||||||
|
|
||||||
return Daemon_Singleton::start();
|
return Daemon_Singleton::start();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DaemonWin32::stop()
|
bool DaemonWin32::stop()
|
||||||
{
|
{
|
||||||
return Daemon_Singleton::stop();
|
return Daemon_Singleton::stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
254
Datagram.cpp
254
Datagram.cpp
|
@ -12,140 +12,140 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace datagram
|
namespace datagram
|
||||||
{
|
{
|
||||||
DatagramDestination::DatagramDestination (i2p::client::ClientDestination& owner):
|
DatagramDestination::DatagramDestination (i2p::client::ClientDestination& owner):
|
||||||
m_Owner (owner), m_Receiver (nullptr)
|
m_Owner (owner), m_Receiver (nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort, uint16_t toPort)
|
void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort, uint16_t toPort)
|
||||||
{
|
{
|
||||||
uint8_t buf[MAX_DATAGRAM_SIZE];
|
uint8_t buf[MAX_DATAGRAM_SIZE];
|
||||||
auto identityLen = m_Owner.GetIdentity ().ToBuffer (buf, MAX_DATAGRAM_SIZE);
|
auto identityLen = m_Owner.GetIdentity ().ToBuffer (buf, MAX_DATAGRAM_SIZE);
|
||||||
uint8_t * signature = buf + identityLen;
|
uint8_t * signature = buf + identityLen;
|
||||||
auto signatureLen = m_Owner.GetIdentity ().GetSignatureLen ();
|
auto signatureLen = m_Owner.GetIdentity ().GetSignatureLen ();
|
||||||
uint8_t * buf1 = signature + signatureLen;
|
uint8_t * buf1 = signature + signatureLen;
|
||||||
size_t headerLen = identityLen + signatureLen;
|
size_t headerLen = identityLen + signatureLen;
|
||||||
|
|
||||||
memcpy (buf1, payload, len);
|
memcpy (buf1, payload, len);
|
||||||
if (m_Owner.GetIdentity ().GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
if (m_Owner.GetIdentity ().GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
||||||
{
|
{
|
||||||
uint8_t hash[32];
|
uint8_t hash[32];
|
||||||
CryptoPP::SHA256().CalculateDigest (hash, buf1, len);
|
CryptoPP::SHA256().CalculateDigest (hash, buf1, len);
|
||||||
m_Owner.Sign (hash, 32, signature);
|
m_Owner.Sign (hash, 32, signature);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_Owner.Sign (buf1, len, signature);
|
m_Owner.Sign (buf1, len, signature);
|
||||||
|
|
||||||
auto msg = CreateDataMessage (buf, len + headerLen, fromPort, toPort);
|
auto msg = CreateDataMessage (buf, len + headerLen, fromPort, toPort);
|
||||||
auto remote = m_Owner.FindLeaseSet (ident);
|
auto remote = m_Owner.FindLeaseSet (ident);
|
||||||
if (remote)
|
if (remote)
|
||||||
m_Owner.GetService ().post (std::bind (&DatagramDestination::SendMsg, this, msg, remote));
|
m_Owner.GetService ().post (std::bind (&DatagramDestination::SendMsg, this, msg, remote));
|
||||||
else
|
else
|
||||||
m_Owner.RequestDestination (ident, std::bind (&DatagramDestination::HandleLeaseSetRequestComplete, this, std::placeholders::_1, msg));
|
m_Owner.RequestDestination (ident, std::bind (&DatagramDestination::HandleLeaseSetRequestComplete, this, std::placeholders::_1, msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramDestination::HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> remote, I2NPMessage * msg)
|
void DatagramDestination::HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> remote, I2NPMessage * msg)
|
||||||
{
|
{
|
||||||
if (remote)
|
if (remote)
|
||||||
SendMsg (msg, remote);
|
SendMsg (msg, remote);
|
||||||
else
|
else
|
||||||
DeleteI2NPMessage (msg);
|
DeleteI2NPMessage (msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramDestination::SendMsg (I2NPMessage * msg, std::shared_ptr<const i2p::data::LeaseSet> remote)
|
void DatagramDestination::SendMsg (I2NPMessage * msg, std::shared_ptr<const i2p::data::LeaseSet> remote)
|
||||||
{
|
{
|
||||||
auto outboundTunnel = m_Owner.GetTunnelPool ()->GetNextOutboundTunnel ();
|
auto outboundTunnel = m_Owner.GetTunnelPool ()->GetNextOutboundTunnel ();
|
||||||
auto leases = remote->GetNonExpiredLeases ();
|
auto leases = remote->GetNonExpiredLeases ();
|
||||||
if (!leases.empty () && outboundTunnel)
|
if (!leases.empty () && outboundTunnel)
|
||||||
{
|
{
|
||||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||||
uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1);
|
uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1);
|
||||||
auto garlic = m_Owner.WrapMessage (remote, ToSharedI2NPMessage (msg), true);
|
auto garlic = m_Owner.WrapMessage (remote, ToSharedI2NPMessage (msg), true);
|
||||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||||
{
|
{
|
||||||
i2p::tunnel::eDeliveryTypeTunnel,
|
i2p::tunnel::eDeliveryTypeTunnel,
|
||||||
leases[i].tunnelGateway, leases[i].tunnelID,
|
leases[i].tunnelGateway, leases[i].tunnelID,
|
||||||
garlic
|
garlic
|
||||||
});
|
});
|
||||||
outboundTunnel->SendTunnelDataMsg (msgs);
|
outboundTunnel->SendTunnelDataMsg (msgs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (outboundTunnel)
|
if (outboundTunnel)
|
||||||
LogPrint (eLogWarning, "Failed to send datagram. All leases expired");
|
LogPrint (eLogWarning, "Failed to send datagram. All leases expired");
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Failed to send datagram. No outbound tunnels");
|
LogPrint (eLogWarning, "Failed to send datagram. No outbound tunnels");
|
||||||
DeleteI2NPMessage (msg);
|
DeleteI2NPMessage (msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
i2p::data::IdentityEx identity;
|
i2p::data::IdentityEx identity;
|
||||||
size_t identityLen = identity.FromBuffer (buf, len);
|
size_t identityLen = identity.FromBuffer (buf, len);
|
||||||
const uint8_t * signature = buf + identityLen;
|
const uint8_t * signature = buf + identityLen;
|
||||||
size_t headerLen = identityLen + identity.GetSignatureLen ();
|
size_t headerLen = identityLen + identity.GetSignatureLen ();
|
||||||
|
|
||||||
bool verified = false;
|
bool verified = false;
|
||||||
if (identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
if (identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
||||||
{
|
{
|
||||||
uint8_t hash[32];
|
uint8_t hash[32];
|
||||||
CryptoPP::SHA256().CalculateDigest (hash, buf + headerLen, len - headerLen);
|
CryptoPP::SHA256().CalculateDigest (hash, buf + headerLen, len - headerLen);
|
||||||
verified = identity.Verify (hash, 32, signature);
|
verified = identity.Verify (hash, 32, signature);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
verified = identity.Verify (buf + headerLen, len - headerLen, signature);
|
verified = identity.Verify (buf + headerLen, len - headerLen, signature);
|
||||||
|
|
||||||
if (verified)
|
if (verified)
|
||||||
{
|
{
|
||||||
auto it = m_ReceiversByPorts.find (toPort);
|
auto it = m_ReceiversByPorts.find (toPort);
|
||||||
if (it != m_ReceiversByPorts.end ())
|
if (it != m_ReceiversByPorts.end ())
|
||||||
it->second (identity, fromPort, toPort, buf + headerLen, len -headerLen);
|
it->second (identity, fromPort, toPort, buf + headerLen, len -headerLen);
|
||||||
else if (m_Receiver != nullptr)
|
else if (m_Receiver != nullptr)
|
||||||
m_Receiver (identity, fromPort, toPort, buf + headerLen, len -headerLen);
|
m_Receiver (identity, fromPort, toPort, buf + headerLen, len -headerLen);
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Receiver for datagram is not set");
|
LogPrint (eLogWarning, "Receiver for datagram is not set");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Datagram signature verification failed");
|
LogPrint (eLogWarning, "Datagram signature verification failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
// unzip it
|
// unzip it
|
||||||
CryptoPP::Gunzip decompressor;
|
CryptoPP::Gunzip decompressor;
|
||||||
decompressor.Put (buf, len);
|
decompressor.Put (buf, len);
|
||||||
decompressor.MessageEnd();
|
decompressor.MessageEnd();
|
||||||
uint8_t uncompressed[MAX_DATAGRAM_SIZE];
|
uint8_t uncompressed[MAX_DATAGRAM_SIZE];
|
||||||
auto uncompressedLen = decompressor.MaxRetrievable ();
|
auto uncompressedLen = decompressor.MaxRetrievable ();
|
||||||
if (uncompressedLen <= MAX_DATAGRAM_SIZE)
|
if (uncompressedLen <= MAX_DATAGRAM_SIZE)
|
||||||
{
|
{
|
||||||
decompressor.Get (uncompressed, uncompressedLen);
|
decompressor.Get (uncompressed, uncompressedLen);
|
||||||
HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen);
|
HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint ("Received datagram size ", uncompressedLen, " exceeds max size");
|
LogPrint ("Received datagram size ", uncompressedLen, " exceeds max size");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
I2NPMessage * DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort)
|
I2NPMessage * DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort)
|
||||||
{
|
{
|
||||||
I2NPMessage * msg = NewI2NPMessage ();
|
I2NPMessage * msg = NewI2NPMessage ();
|
||||||
CryptoPP::Gzip compressor; // default level
|
CryptoPP::Gzip compressor; // default level
|
||||||
compressor.Put (payload, len);
|
compressor.Put (payload, len);
|
||||||
compressor.MessageEnd();
|
compressor.MessageEnd();
|
||||||
int size = compressor.MaxRetrievable ();
|
int size = compressor.MaxRetrievable ();
|
||||||
uint8_t * buf = msg->GetPayload ();
|
uint8_t * buf = msg->GetPayload ();
|
||||||
htobe32buf (buf, size); // length
|
htobe32buf (buf, size); // length
|
||||||
buf += 4;
|
buf += 4;
|
||||||
compressor.Get (buf, size);
|
compressor.Get (buf, size);
|
||||||
htobe16buf (buf + 4, fromPort); // source port
|
htobe16buf (buf + 4, fromPort); // source port
|
||||||
htobe16buf (buf + 6, toPort); // destination port
|
htobe16buf (buf + 6, toPort); // destination port
|
||||||
buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol
|
buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol
|
||||||
msg->len += size + 4;
|
msg->len += size + 4;
|
||||||
msg->FillI2NPMessageHeader (eI2NPData);
|
msg->FillI2NPMessageHeader (eI2NPData);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
50
Datagram.h
50
Datagram.h
|
@ -13,43 +13,43 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
class ClientDestination;
|
class ClientDestination;
|
||||||
}
|
}
|
||||||
namespace datagram
|
namespace datagram
|
||||||
{
|
{
|
||||||
const size_t MAX_DATAGRAM_SIZE = 32768;
|
const size_t MAX_DATAGRAM_SIZE = 32768;
|
||||||
class DatagramDestination
|
class DatagramDestination
|
||||||
{
|
{
|
||||||
typedef std::function<void (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> Receiver;
|
typedef std::function<void (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> Receiver;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DatagramDestination (i2p::client::ClientDestination& owner);
|
DatagramDestination (i2p::client::ClientDestination& owner);
|
||||||
~DatagramDestination () {};
|
~DatagramDestination () {};
|
||||||
|
|
||||||
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||||
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
||||||
void ResetReceiver () { m_Receiver = nullptr; };
|
void ResetReceiver () { m_Receiver = nullptr; };
|
||||||
|
|
||||||
void SetReceiver (const Receiver& receiver, uint16_t port) { m_ReceiversByPorts[port] = receiver; };
|
void SetReceiver (const Receiver& receiver, uint16_t port) { m_ReceiversByPorts[port] = receiver; };
|
||||||
void ResetReceiver (uint16_t port) { m_ReceiversByPorts.erase (port); };
|
void ResetReceiver (uint16_t port) { m_ReceiversByPorts.erase (port); };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, I2NPMessage * msg);
|
void HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, I2NPMessage * msg);
|
||||||
|
|
||||||
I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
|
I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
|
||||||
void SendMsg (I2NPMessage * msg, std::shared_ptr<const i2p::data::LeaseSet> remote);
|
void SendMsg (I2NPMessage * msg, std::shared_ptr<const i2p::data::LeaseSet> remote);
|
||||||
void HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
void HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
i2p::client::ClientDestination& m_Owner;
|
i2p::client::ClientDestination& m_Owner;
|
||||||
Receiver m_Receiver; // default
|
Receiver m_Receiver; // default
|
||||||
std::map<uint16_t, Receiver> m_ReceiversByPorts;
|
std::map<uint16_t, Receiver> m_ReceiversByPorts;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1246
Destination.cpp
1246
Destination.cpp
File diff suppressed because it is too large
Load diff
236
Destination.h
236
Destination.h
|
@ -22,135 +22,135 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
const uint8_t PROTOCOL_TYPE_STREAMING = 6;
|
const uint8_t PROTOCOL_TYPE_STREAMING = 6;
|
||||||
const uint8_t PROTOCOL_TYPE_DATAGRAM = 17;
|
const uint8_t PROTOCOL_TYPE_DATAGRAM = 17;
|
||||||
const uint8_t PROTOCOL_TYPE_RAW = 18;
|
const uint8_t PROTOCOL_TYPE_RAW = 18;
|
||||||
const int PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
|
const int PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
|
||||||
const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds
|
const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds
|
||||||
const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds
|
const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds
|
||||||
const int MAX_NUM_FLOODFILLS_PER_REQUEST = 7;
|
const int MAX_NUM_FLOODFILLS_PER_REQUEST = 7;
|
||||||
const int DESTINATION_CLEANUP_TIMEOUT = 20; // in minutes
|
const int DESTINATION_CLEANUP_TIMEOUT = 20; // in minutes
|
||||||
|
|
||||||
// I2CP
|
// I2CP
|
||||||
const char I2CP_PARAM_INBOUND_TUNNEL_LENGTH[] = "inbound.length";
|
const char I2CP_PARAM_INBOUND_TUNNEL_LENGTH[] = "inbound.length";
|
||||||
const int DEFAULT_INBOUND_TUNNEL_LENGTH = 3;
|
const int DEFAULT_INBOUND_TUNNEL_LENGTH = 3;
|
||||||
const char I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH[] = "outbound.length";
|
const char I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH[] = "outbound.length";
|
||||||
const int DEFAULT_OUTBOUND_TUNNEL_LENGTH = 3;
|
const int DEFAULT_OUTBOUND_TUNNEL_LENGTH = 3;
|
||||||
const char I2CP_PARAM_INBOUND_TUNNELS_QUANTITY[] = "inbound.quantity";
|
const char I2CP_PARAM_INBOUND_TUNNELS_QUANTITY[] = "inbound.quantity";
|
||||||
const int DEFAULT_INBOUND_TUNNELS_QUANTITY = 5;
|
const int DEFAULT_INBOUND_TUNNELS_QUANTITY = 5;
|
||||||
const char I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY[] = "outbound.quantity";
|
const char I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY[] = "outbound.quantity";
|
||||||
const int DEFAULT_OUTBOUND_TUNNELS_QUANTITY = 5;
|
const int DEFAULT_OUTBOUND_TUNNELS_QUANTITY = 5;
|
||||||
const char I2CP_PARAM_EXPLICIT_PEERS[] = "explicitPeers";
|
const char I2CP_PARAM_EXPLICIT_PEERS[] = "explicitPeers";
|
||||||
const int STREAM_REQUEST_TIMEOUT = 60; //in seconds
|
const int STREAM_REQUEST_TIMEOUT = 60; //in seconds
|
||||||
|
|
||||||
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
|
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
|
||||||
|
|
||||||
class ClientDestination: public i2p::garlic::GarlicDestination
|
class ClientDestination: public i2p::garlic::GarlicDestination
|
||||||
{
|
{
|
||||||
typedef std::function<void (std::shared_ptr<i2p::data::LeaseSet> leaseSet)> RequestComplete;
|
typedef std::function<void (std::shared_ptr<i2p::data::LeaseSet> leaseSet)> RequestComplete;
|
||||||
// leaseSet = nullptr means not found
|
// leaseSet = nullptr means not found
|
||||||
struct LeaseSetRequest
|
struct LeaseSetRequest
|
||||||
{
|
{
|
||||||
LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {};
|
LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {};
|
||||||
std::set<i2p::data::IdentHash> excluded;
|
std::set<i2p::data::IdentHash> excluded;
|
||||||
uint64_t requestTime;
|
uint64_t requestTime;
|
||||||
boost::asio::deadline_timer requestTimeoutTimer;
|
boost::asio::deadline_timer requestTimeoutTimer;
|
||||||
RequestComplete requestComplete;
|
RequestComplete requestComplete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
||||||
~ClientDestination ();
|
~ClientDestination ();
|
||||||
|
|
||||||
virtual void Start ();
|
virtual void Start ();
|
||||||
virtual void Stop ();
|
virtual void Stop ();
|
||||||
bool IsRunning () const { return m_IsRunning; };
|
bool IsRunning () const { return m_IsRunning; };
|
||||||
boost::asio::io_service& GetService () { return m_Service; };
|
boost::asio::io_service& GetService () { return m_Service; };
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; };
|
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; };
|
||||||
bool IsReady () const { return m_LeaseSet && m_LeaseSet->HasNonExpiredLeases () && m_Pool->GetOutboundTunnels ().size () > 0; };
|
bool IsReady () const { return m_LeaseSet && m_LeaseSet->HasNonExpiredLeases () && m_Pool->GetOutboundTunnels ().size () > 0; };
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
|
std::shared_ptr<const i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
|
||||||
bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr);
|
bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr);
|
||||||
|
|
||||||
// streaming
|
// streaming
|
||||||
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port); // additional
|
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port); // additional
|
||||||
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
|
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
|
||||||
// following methods operate with default streaming destination
|
// following methods operate with default streaming destination
|
||||||
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0);
|
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0);
|
||||||
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<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;
|
||||||
|
|
||||||
// datagram
|
// datagram
|
||||||
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
|
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
|
||||||
i2p::datagram::DatagramDestination * CreateDatagramDestination ();
|
i2p::datagram::DatagramDestination * CreateDatagramDestination ();
|
||||||
|
|
||||||
// implements LocalDestination
|
// implements LocalDestination
|
||||||
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
||||||
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
|
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
|
||||||
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; };
|
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; };
|
||||||
|
|
||||||
// implements GarlicDestination
|
// implements GarlicDestination
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> GetLeaseSet ();
|
std::shared_ptr<const i2p::data::LeaseSet> GetLeaseSet ();
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const { return m_Pool; }
|
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const { return m_Pool; }
|
||||||
void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||||
|
|
||||||
// override GarlicDestination
|
// override GarlicDestination
|
||||||
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
|
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
|
||||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void SetLeaseSetUpdated ();
|
void SetLeaseSetUpdated ();
|
||||||
|
|
||||||
// I2CP
|
// I2CP
|
||||||
void HandleDataMessage (const uint8_t * buf, size_t len);
|
void HandleDataMessage (const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void UpdateLeaseSet ();
|
void UpdateLeaseSet ();
|
||||||
void Publish ();
|
void Publish ();
|
||||||
void HandlePublishConfirmationTimer (const boost::system::error_code& ecode);
|
void HandlePublishConfirmationTimer (const boost::system::error_code& ecode);
|
||||||
void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len);
|
void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len);
|
||||||
void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len);
|
void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len);
|
||||||
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete);
|
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete);
|
||||||
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, LeaseSetRequest * request);
|
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, LeaseSetRequest * request);
|
||||||
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
|
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
|
||||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||||
void CleanupRemoteLeaseSets ();
|
void CleanupRemoteLeaseSets ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
volatile bool m_IsRunning;
|
volatile bool m_IsRunning;
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
boost::asio::io_service m_Service;
|
boost::asio::io_service m_Service;
|
||||||
boost::asio::io_service::work m_Work;
|
boost::asio::io_service::work m_Work;
|
||||||
i2p::data::PrivateKeys m_Keys;
|
i2p::data::PrivateKeys m_Keys;
|
||||||
uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256];
|
uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256];
|
||||||
std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
||||||
std::map<i2p::data::IdentHash, LeaseSetRequest *> m_LeaseSetRequests;
|
std::map<i2p::data::IdentHash, LeaseSetRequest *> m_LeaseSetRequests;
|
||||||
|
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
|
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
|
||||||
std::shared_ptr<i2p::data::LeaseSet> m_LeaseSet;
|
std::shared_ptr<i2p::data::LeaseSet> m_LeaseSet;
|
||||||
bool m_IsPublic;
|
bool m_IsPublic;
|
||||||
uint32_t m_PublishReplyToken;
|
uint32_t m_PublishReplyToken;
|
||||||
std::set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing
|
std::set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing
|
||||||
|
|
||||||
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
|
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
|
||||||
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
|
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
|
||||||
i2p::datagram::DatagramDestination * m_DatagramDestination;
|
i2p::datagram::DatagramDestination * m_DatagramDestination;
|
||||||
|
|
||||||
boost::asio::deadline_timer m_PublishConfirmationTimer, m_CleanupTimer;
|
boost::asio::deadline_timer m_PublishConfirmationTimer, m_CleanupTimer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); };
|
int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
120
ElGamal.h
120
ElGamal.h
|
@ -14,74 +14,74 @@ namespace i2p
|
||||||
namespace crypto
|
namespace crypto
|
||||||
{
|
{
|
||||||
|
|
||||||
class ElGamalEncryption
|
class ElGamalEncryption
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ElGamalEncryption (const uint8_t * key)
|
ElGamalEncryption (const uint8_t * key)
|
||||||
{
|
{
|
||||||
CryptoPP::AutoSeededRandomPool rnd;
|
CryptoPP::AutoSeededRandomPool rnd;
|
||||||
CryptoPP::Integer y (key, 256), k (rnd, CryptoPP::Integer::One(), elgp-1);
|
CryptoPP::Integer y (key, 256), k (rnd, CryptoPP::Integer::One(), elgp-1);
|
||||||
a = a_exp_b_mod_c (elgg, k, elgp);
|
a = a_exp_b_mod_c (elgg, k, elgp);
|
||||||
b1 = a_exp_b_mod_c (y, k, elgp);
|
b1 = a_exp_b_mod_c (y, k, elgp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding = false) const
|
void Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding = false) const
|
||||||
{
|
{
|
||||||
// calculate b = b1*m mod p
|
// calculate b = b1*m mod p
|
||||||
uint8_t m[255];
|
uint8_t m[255];
|
||||||
m[0] = 0xFF;
|
m[0] = 0xFF;
|
||||||
memcpy (m+33, data, len);
|
memcpy (m+33, data, len);
|
||||||
CryptoPP::SHA256().CalculateDigest(m+1, m+33, 222);
|
CryptoPP::SHA256().CalculateDigest(m+1, m+33, 222);
|
||||||
CryptoPP::Integer b (a_times_b_mod_c (b1, CryptoPP::Integer (m, 255), elgp));
|
CryptoPP::Integer b (a_times_b_mod_c (b1, CryptoPP::Integer (m, 255), elgp));
|
||||||
|
|
||||||
// copy a and b
|
// copy a and b
|
||||||
if (zeroPadding)
|
if (zeroPadding)
|
||||||
{
|
{
|
||||||
encrypted[0] = 0;
|
encrypted[0] = 0;
|
||||||
a.Encode (encrypted + 1, 256);
|
a.Encode (encrypted + 1, 256);
|
||||||
encrypted[257] = 0;
|
encrypted[257] = 0;
|
||||||
b.Encode (encrypted + 258, 256);
|
b.Encode (encrypted + 258, 256);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
a.Encode (encrypted, 256);
|
a.Encode (encrypted, 256);
|
||||||
b.Encode (encrypted + 256, 256);
|
b.Encode (encrypted + 256, 256);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CryptoPP::Integer a, b1;
|
CryptoPP::Integer a, b1;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted,
|
inline bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted,
|
||||||
uint8_t * data, bool zeroPadding = false)
|
uint8_t * data, bool zeroPadding = false)
|
||||||
{
|
{
|
||||||
CryptoPP::Integer x(key, 256), a(zeroPadding? encrypted +1 : encrypted, 256),
|
CryptoPP::Integer x(key, 256), a(zeroPadding? encrypted +1 : encrypted, 256),
|
||||||
b(zeroPadding? encrypted + 258 :encrypted + 256, 256);
|
b(zeroPadding? encrypted + 258 :encrypted + 256, 256);
|
||||||
uint8_t m[255];
|
uint8_t m[255];
|
||||||
a_times_b_mod_c (b, a_exp_b_mod_c (a, elgp - x - 1, elgp), elgp).Encode (m, 255);
|
a_times_b_mod_c (b, a_exp_b_mod_c (a, elgp - x - 1, elgp), elgp).Encode (m, 255);
|
||||||
if (!CryptoPP::SHA256().VerifyDigest (m + 1, m + 33, 222))
|
if (!CryptoPP::SHA256().VerifyDigest (m + 1, m + 33, 222))
|
||||||
{
|
{
|
||||||
LogPrint ("ElGamal decrypt hash doesn't match");
|
LogPrint ("ElGamal decrypt hash doesn't match");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memcpy (data, m + 33, 222);
|
memcpy (data, m + 33, 222);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void GenerateElGamalKeyPair (CryptoPP::RandomNumberGenerator& rnd, uint8_t * priv, uint8_t * pub)
|
inline void GenerateElGamalKeyPair (CryptoPP::RandomNumberGenerator& rnd, uint8_t * priv, uint8_t * pub)
|
||||||
{
|
{
|
||||||
#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER)
|
#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER)
|
||||||
rnd.GenerateBlock (priv, 256);
|
rnd.GenerateBlock (priv, 256);
|
||||||
a_exp_b_mod_c (elgg, CryptoPP::Integer (priv, 256), elgp).Encode (pub, 256);
|
a_exp_b_mod_c (elgg, CryptoPP::Integer (priv, 256), elgp).Encode (pub, 256);
|
||||||
#else
|
#else
|
||||||
CryptoPP::DH dh (elgp, elgg);
|
CryptoPP::DH dh (elgp, elgg);
|
||||||
dh.GenerateKeyPair(rnd, priv, pub);
|
dh.GenerateKeyPair(rnd, priv, pub);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
1146
Garlic.cpp
1146
Garlic.cpp
File diff suppressed because it is too large
Load diff
256
Garlic.h
256
Garlic.h
|
@ -16,154 +16,154 @@
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace garlic
|
namespace garlic
|
||||||
{
|
{
|
||||||
|
|
||||||
enum GarlicDeliveryType
|
enum GarlicDeliveryType
|
||||||
{
|
{
|
||||||
eGarlicDeliveryTypeLocal = 0,
|
eGarlicDeliveryTypeLocal = 0,
|
||||||
eGarlicDeliveryTypeDestination = 1,
|
eGarlicDeliveryTypeDestination = 1,
|
||||||
eGarlicDeliveryTypeRouter = 2,
|
eGarlicDeliveryTypeRouter = 2,
|
||||||
eGarlicDeliveryTypeTunnel = 3
|
eGarlicDeliveryTypeTunnel = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
struct ElGamalBlock
|
struct ElGamalBlock
|
||||||
{
|
{
|
||||||
uint8_t sessionKey[32];
|
uint8_t sessionKey[32];
|
||||||
uint8_t preIV[32];
|
uint8_t preIV[32];
|
||||||
uint8_t padding[158];
|
uint8_t padding[158];
|
||||||
};
|
};
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 960; // 16 minutes
|
const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 960; // 16 minutes
|
||||||
const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes
|
const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes
|
||||||
const int LEASET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
|
const int LEASET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
|
||||||
|
|
||||||
struct SessionTag: public i2p::data::Tag<32>
|
struct SessionTag: public i2p::data::Tag<32>
|
||||||
{
|
{
|
||||||
SessionTag (const uint8_t * buf, uint32_t ts = 0): Tag<32>(buf), creationTime (ts) {};
|
SessionTag (const uint8_t * buf, uint32_t ts = 0): Tag<32>(buf), creationTime (ts) {};
|
||||||
SessionTag () = default;
|
SessionTag () = default;
|
||||||
SessionTag (const SessionTag& ) = default;
|
SessionTag (const SessionTag& ) = default;
|
||||||
SessionTag& operator= (const SessionTag& ) = default;
|
SessionTag& operator= (const SessionTag& ) = default;
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
SessionTag (SessionTag&& ) = default;
|
SessionTag (SessionTag&& ) = default;
|
||||||
SessionTag& operator= (SessionTag&& ) = default;
|
SessionTag& operator= (SessionTag&& ) = default;
|
||||||
#endif
|
#endif
|
||||||
uint32_t creationTime; // seconds since epoch
|
uint32_t creationTime; // seconds since epoch
|
||||||
};
|
};
|
||||||
|
|
||||||
class GarlicDestination;
|
class GarlicDestination;
|
||||||
class GarlicRoutingSession: public std::enable_shared_from_this<GarlicRoutingSession>
|
class GarlicRoutingSession: public std::enable_shared_from_this<GarlicRoutingSession>
|
||||||
{
|
{
|
||||||
enum LeaseSetUpdateStatus
|
enum LeaseSetUpdateStatus
|
||||||
{
|
{
|
||||||
eLeaseSetUpToDate = 0,
|
eLeaseSetUpToDate = 0,
|
||||||
eLeaseSetUpdated,
|
eLeaseSetUpdated,
|
||||||
eLeaseSetSubmitted,
|
eLeaseSetSubmitted,
|
||||||
eLeaseSetDoNotSend
|
eLeaseSetDoNotSend
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UnconfirmedTags
|
struct UnconfirmedTags
|
||||||
{
|
{
|
||||||
UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; };
|
UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; };
|
||||||
~UnconfirmedTags () { delete[] sessionTags; };
|
~UnconfirmedTags () { delete[] sessionTags; };
|
||||||
int numTags;
|
int numTags;
|
||||||
SessionTag * sessionTags;
|
SessionTag * sessionTags;
|
||||||
uint32_t tagsCreationTime;
|
uint32_t tagsCreationTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr<const i2p::data::RoutingDestination> destination,
|
GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr<const i2p::data::RoutingDestination> destination,
|
||||||
int numTags, bool attachLeaseSet);
|
int numTags, bool attachLeaseSet);
|
||||||
GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption
|
GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption
|
||||||
~GarlicRoutingSession ();
|
~GarlicRoutingSession ();
|
||||||
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
|
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
|
||||||
void MessageConfirmed (uint32_t msgID);
|
void MessageConfirmed (uint32_t msgID);
|
||||||
bool CleanupExpiredTags (); // returns true if something left
|
bool CleanupExpiredTags (); // returns true if something left
|
||||||
|
|
||||||
void SetLeaseSetUpdated ()
|
void SetLeaseSetUpdated ()
|
||||||
{
|
{
|
||||||
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
|
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
size_t CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg);
|
size_t CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg);
|
||||||
size_t CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags);
|
size_t CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags);
|
||||||
size_t CreateGarlicClove (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg, bool isDestination);
|
size_t CreateGarlicClove (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg, bool isDestination);
|
||||||
size_t CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID);
|
size_t CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID);
|
||||||
|
|
||||||
void TagsConfirmed (uint32_t msgID);
|
void TagsConfirmed (uint32_t msgID);
|
||||||
UnconfirmedTags * GenerateSessionTags ();
|
UnconfirmedTags * GenerateSessionTags ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
GarlicDestination * m_Owner;
|
GarlicDestination * m_Owner;
|
||||||
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
|
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
|
||||||
i2p::crypto::AESKey m_SessionKey;
|
i2p::crypto::AESKey m_SessionKey;
|
||||||
std::list<SessionTag> m_SessionTags;
|
std::list<SessionTag> m_SessionTags;
|
||||||
int m_NumTags;
|
int m_NumTags;
|
||||||
std::map<uint32_t, UnconfirmedTags *> m_UnconfirmedTagsMsgs;
|
std::map<uint32_t, UnconfirmedTags *> m_UnconfirmedTagsMsgs;
|
||||||
|
|
||||||
LeaseSetUpdateStatus m_LeaseSetUpdateStatus;
|
LeaseSetUpdateStatus m_LeaseSetUpdateStatus;
|
||||||
uint32_t m_LeaseSetUpdateMsgID;
|
uint32_t m_LeaseSetUpdateMsgID;
|
||||||
uint64_t m_LeaseSetSubmissionTime; // in milliseconds
|
uint64_t m_LeaseSetSubmissionTime; // in milliseconds
|
||||||
|
|
||||||
i2p::crypto::CBCEncryption m_Encryption;
|
i2p::crypto::CBCEncryption m_Encryption;
|
||||||
CryptoPP::AutoSeededRandomPool m_Rnd;
|
CryptoPP::AutoSeededRandomPool m_Rnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GarlicDestination: public i2p::data::LocalDestination
|
class GarlicDestination: public i2p::data::LocalDestination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GarlicDestination (): m_LastTagsCleanupTime (0) {};
|
GarlicDestination (): m_LastTagsCleanupTime (0) {};
|
||||||
~GarlicDestination ();
|
~GarlicDestination ();
|
||||||
|
|
||||||
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
|
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
|
||||||
void CleanupRoutingSessions ();
|
void CleanupRoutingSessions ();
|
||||||
void RemoveCreatedSession (uint32_t msgID);
|
void RemoveCreatedSession (uint32_t msgID);
|
||||||
std::shared_ptr<I2NPMessage> WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
|
std::shared_ptr<I2NPMessage> WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
|
||||||
std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet = false);
|
std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet = false);
|
||||||
|
|
||||||
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
|
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
|
||||||
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
|
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
|
||||||
void DeliveryStatusSent (std::shared_ptr<GarlicRoutingSession> session, uint32_t msgID);
|
void DeliveryStatusSent (std::shared_ptr<GarlicRoutingSession> session, uint32_t msgID);
|
||||||
|
|
||||||
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
virtual void SetLeaseSetUpdated ();
|
virtual void SetLeaseSetUpdated ();
|
||||||
|
|
||||||
virtual std::shared_ptr<const i2p::data::LeaseSet> GetLeaseSet () = 0; // TODO
|
virtual std::shared_ptr<const i2p::data::LeaseSet> GetLeaseSet () = 0; // TODO
|
||||||
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0;
|
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0;
|
||||||
virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) = 0;
|
virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<i2p::crypto::CBCDecryption> decryption,
|
void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<i2p::crypto::CBCDecryption> decryption,
|
||||||
std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||||
void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// outgoing sessions
|
// outgoing sessions
|
||||||
std::mutex m_SessionsMutex;
|
std::mutex m_SessionsMutex;
|
||||||
std::map<i2p::data::IdentHash, std::shared_ptr<GarlicRoutingSession> > m_Sessions;
|
std::map<i2p::data::IdentHash, std::shared_ptr<GarlicRoutingSession> > m_Sessions;
|
||||||
// incoming
|
// incoming
|
||||||
std::map<SessionTag, std::shared_ptr<i2p::crypto::CBCDecryption>> m_Tags;
|
std::map<SessionTag, std::shared_ptr<i2p::crypto::CBCDecryption>> m_Tags;
|
||||||
uint32_t m_LastTagsCleanupTime;
|
uint32_t m_LastTagsCleanupTime;
|
||||||
// DeliveryStatus
|
// DeliveryStatus
|
||||||
std::map<uint32_t, std::shared_ptr<GarlicRoutingSession> > m_CreatedSessions; // msgID -> session
|
std::map<uint32_t, std::shared_ptr<GarlicRoutingSession> > m_CreatedSessions; // msgID -> session
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
514
HTTPProxy.cpp
514
HTTPProxy.cpp
|
@ -17,283 +17,283 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace proxy
|
namespace proxy
|
||||||
{
|
{
|
||||||
static const size_t http_buffer_size = 8192;
|
static const size_t http_buffer_size = 8192;
|
||||||
class HTTPProxyHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this<HTTPProxyHandler>
|
class HTTPProxyHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this<HTTPProxyHandler>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
enum state
|
enum state
|
||||||
{
|
{
|
||||||
GET_METHOD,
|
GET_METHOD,
|
||||||
GET_HOSTNAME,
|
GET_HOSTNAME,
|
||||||
GET_HTTPV,
|
GET_HTTPV,
|
||||||
GET_HTTPVNL, //TODO: fallback to finding HOst: header if needed
|
GET_HTTPVNL, //TODO: fallback to finding HOst: header if needed
|
||||||
DONE
|
DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
void EnterState(state nstate);
|
void EnterState(state nstate);
|
||||||
bool HandleData(uint8_t *http_buff, std::size_t len);
|
bool HandleData(uint8_t *http_buff, std::size_t len);
|
||||||
void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
|
void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
|
||||||
void Terminate();
|
void Terminate();
|
||||||
void AsyncSockRead();
|
void AsyncSockRead();
|
||||||
void HTTPRequestFailed(/*std::string message*/);
|
void HTTPRequestFailed(/*std::string message*/);
|
||||||
void ExtractRequest();
|
void ExtractRequest();
|
||||||
bool ValidateHTTPRequest();
|
bool ValidateHTTPRequest();
|
||||||
void HandleJumpServices();
|
void HandleJumpServices();
|
||||||
bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len);
|
bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len);
|
||||||
void SentHTTPFailed(const boost::system::error_code & ecode);
|
void SentHTTPFailed(const boost::system::error_code & ecode);
|
||||||
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
|
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
|
||||||
|
|
||||||
uint8_t m_http_buff[http_buffer_size];
|
uint8_t m_http_buff[http_buffer_size];
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> m_sock;
|
std::shared_ptr<boost::asio::ip::tcp::socket> m_sock;
|
||||||
std::string m_request; //Data left to be sent
|
std::string m_request; //Data left to be sent
|
||||||
std::string m_url; //URL
|
std::string m_url; //URL
|
||||||
std::string m_method; //Method
|
std::string m_method; //Method
|
||||||
std::string m_version; //HTTP version
|
std::string m_version; //HTTP version
|
||||||
std::string m_address; //Address
|
std::string m_address; //Address
|
||||||
std::string m_path; //Path
|
std::string m_path; //Path
|
||||||
int m_port; //Port
|
int m_port; //Port
|
||||||
state m_state;//Parsing state
|
state m_state;//Parsing state
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HTTPProxyHandler(HTTPProxyServer * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
|
HTTPProxyHandler(HTTPProxyServer * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
|
||||||
I2PServiceHandler(parent), m_sock(sock)
|
I2PServiceHandler(parent), m_sock(sock)
|
||||||
{ EnterState(GET_METHOD); }
|
{ EnterState(GET_METHOD); }
|
||||||
~HTTPProxyHandler() { Terminate(); }
|
~HTTPProxyHandler() { Terminate(); }
|
||||||
void Handle () { AsyncSockRead(); }
|
void Handle () { AsyncSockRead(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
void HTTPProxyHandler::AsyncSockRead()
|
void HTTPProxyHandler::AsyncSockRead()
|
||||||
{
|
{
|
||||||
LogPrint(eLogDebug,"--- HTTP Proxy async sock read");
|
LogPrint(eLogDebug,"--- HTTP Proxy async sock read");
|
||||||
if(m_sock) {
|
if(m_sock) {
|
||||||
m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size),
|
m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size),
|
||||||
std::bind(&HTTPProxyHandler::HandleSockRecv, shared_from_this(),
|
std::bind(&HTTPProxyHandler::HandleSockRecv, shared_from_this(),
|
||||||
std::placeholders::_1, std::placeholders::_2));
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
} else {
|
} else {
|
||||||
LogPrint(eLogError,"--- HTTP Proxy no socket for read");
|
LogPrint(eLogError,"--- HTTP Proxy no socket for read");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPProxyHandler::Terminate() {
|
void HTTPProxyHandler::Terminate() {
|
||||||
if (Kill()) return;
|
if (Kill()) return;
|
||||||
if (m_sock)
|
if (m_sock)
|
||||||
{
|
{
|
||||||
LogPrint(eLogDebug,"--- HTTP Proxy close sock");
|
LogPrint(eLogDebug,"--- HTTP Proxy close sock");
|
||||||
m_sock->close();
|
m_sock->close();
|
||||||
m_sock = nullptr;
|
m_sock = nullptr;
|
||||||
}
|
}
|
||||||
Done(shared_from_this());
|
Done(shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All hope is lost beyond this point */
|
/* All hope is lost beyond this point */
|
||||||
//TODO: handle this apropriately
|
//TODO: handle this apropriately
|
||||||
void HTTPProxyHandler::HTTPRequestFailed(/*HTTPProxyHandler::errTypes error*/)
|
void HTTPProxyHandler::HTTPRequestFailed(/*HTTPProxyHandler::errTypes error*/)
|
||||||
{
|
{
|
||||||
static std::string response = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\nContent-length: 0\r\n";
|
static std::string response = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\nContent-length: 0\r\n";
|
||||||
boost::asio::async_write(*m_sock, boost::asio::buffer(response,response.size()),
|
boost::asio::async_write(*m_sock, boost::asio::buffer(response,response.size()),
|
||||||
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
|
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPProxyHandler::EnterState(HTTPProxyHandler::state nstate)
|
void HTTPProxyHandler::EnterState(HTTPProxyHandler::state nstate)
|
||||||
{
|
{
|
||||||
m_state = nstate;
|
m_state = nstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPProxyHandler::ExtractRequest()
|
void HTTPProxyHandler::ExtractRequest()
|
||||||
{
|
{
|
||||||
LogPrint(eLogDebug,"--- HTTP Proxy method is: ", m_method, "\nRequest is: ", m_url);
|
LogPrint(eLogDebug,"--- HTTP Proxy method is: ", m_method, "\nRequest is: ", m_url);
|
||||||
std::string server="";
|
std::string server="";
|
||||||
std::string port="80";
|
std::string port="80";
|
||||||
boost::regex rHTTP("http://(.*?)(:(\\d+))?(/.*)");
|
boost::regex rHTTP("http://(.*?)(:(\\d+))?(/.*)");
|
||||||
boost::smatch m;
|
boost::smatch m;
|
||||||
std::string path;
|
std::string path;
|
||||||
if(boost::regex_search(m_url, m, rHTTP, boost::match_extra))
|
if(boost::regex_search(m_url, m, rHTTP, boost::match_extra))
|
||||||
{
|
{
|
||||||
server=m[1].str();
|
server=m[1].str();
|
||||||
if (m[2].str() != "") port=m[3].str();
|
if (m[2].str() != "") port=m[3].str();
|
||||||
path=m[4].str();
|
path=m[4].str();
|
||||||
}
|
}
|
||||||
LogPrint(eLogDebug,"--- HTTP Proxy server is: ",server, " port is: ", port, "\n path is: ",path);
|
LogPrint(eLogDebug,"--- HTTP Proxy server is: ",server, " port is: ", port, "\n path is: ",path);
|
||||||
m_address = server;
|
m_address = server;
|
||||||
m_port = boost::lexical_cast<int>(port);
|
m_port = boost::lexical_cast<int>(port);
|
||||||
m_path = path;
|
m_path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPProxyHandler::ValidateHTTPRequest()
|
bool HTTPProxyHandler::ValidateHTTPRequest()
|
||||||
{
|
{
|
||||||
if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" )
|
if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" )
|
||||||
{
|
{
|
||||||
LogPrint(eLogError,"--- HTTP Proxy unsupported version: ", m_version);
|
LogPrint(eLogError,"--- HTTP Proxy unsupported version: ", m_version);
|
||||||
HTTPRequestFailed(); //TODO: send right stuff
|
HTTPRequestFailed(); //TODO: send right stuff
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPProxyHandler::HandleJumpServices()
|
void HTTPProxyHandler::HandleJumpServices()
|
||||||
{
|
{
|
||||||
static const char * helpermark1 = "?i2paddresshelper=";
|
static const char * helpermark1 = "?i2paddresshelper=";
|
||||||
static const char * helpermark2 = "&i2paddresshelper=";
|
static const char * helpermark2 = "&i2paddresshelper=";
|
||||||
size_t addressHelperPos1 = m_path.rfind (helpermark1);
|
size_t addressHelperPos1 = m_path.rfind (helpermark1);
|
||||||
size_t addressHelperPos2 = m_path.rfind (helpermark2);
|
size_t addressHelperPos2 = m_path.rfind (helpermark2);
|
||||||
size_t addressHelperPos;
|
size_t addressHelperPos;
|
||||||
if (addressHelperPos1 == std::string::npos)
|
if (addressHelperPos1 == std::string::npos)
|
||||||
{
|
{
|
||||||
if (addressHelperPos2 == std::string::npos)
|
if (addressHelperPos2 == std::string::npos)
|
||||||
return; //Not a jump service
|
return; //Not a jump service
|
||||||
else
|
else
|
||||||
addressHelperPos = addressHelperPos2;
|
addressHelperPos = addressHelperPos2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (addressHelperPos2 == std::string::npos)
|
if (addressHelperPos2 == std::string::npos)
|
||||||
addressHelperPos = addressHelperPos1;
|
addressHelperPos = addressHelperPos1;
|
||||||
else if ( addressHelperPos1 > addressHelperPos2 )
|
else if ( addressHelperPos1 > addressHelperPos2 )
|
||||||
addressHelperPos = addressHelperPos1;
|
addressHelperPos = addressHelperPos1;
|
||||||
else
|
else
|
||||||
addressHelperPos = addressHelperPos2;
|
addressHelperPos = addressHelperPos2;
|
||||||
}
|
}
|
||||||
auto base64 = m_path.substr (addressHelperPos + strlen(helpermark1));
|
auto base64 = m_path.substr (addressHelperPos + strlen(helpermark1));
|
||||||
base64 = i2p::util::http::urlDecode(base64); //Some of the symbols may be urlencoded
|
base64 = i2p::util::http::urlDecode(base64); //Some of the symbols may be urlencoded
|
||||||
LogPrint (eLogDebug,"Jump service for ", m_address, " found at ", base64, ". Inserting to address book");
|
LogPrint (eLogDebug,"Jump service for ", m_address, " found at ", base64, ". Inserting to address book");
|
||||||
//TODO: this is very dangerous and broken. We should ask the user before doing anything see http://pastethis.i2p/raw/pn5fL4YNJL7OSWj3Sc6N/
|
//TODO: this is very dangerous and broken. We should ask the user before doing anything see http://pastethis.i2p/raw/pn5fL4YNJL7OSWj3Sc6N/
|
||||||
//TODO: we could redirect the user again to avoid dirtiness in the browser
|
//TODO: we could redirect the user again to avoid dirtiness in the browser
|
||||||
i2p::client::context.GetAddressBook ().InsertAddress (m_address, base64);
|
i2p::client::context.GetAddressBook ().InsertAddress (m_address, base64);
|
||||||
m_path.erase(addressHelperPos);
|
m_path.erase(addressHelperPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPProxyHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len)
|
bool HTTPProxyHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len)
|
||||||
{
|
{
|
||||||
ExtractRequest(); //TODO: parse earlier
|
ExtractRequest(); //TODO: parse earlier
|
||||||
if (!ValidateHTTPRequest()) return false;
|
if (!ValidateHTTPRequest()) return false;
|
||||||
HandleJumpServices();
|
HandleJumpServices();
|
||||||
m_request = m_method;
|
m_request = m_method;
|
||||||
m_request.push_back(' ');
|
m_request.push_back(' ');
|
||||||
m_request += m_path;
|
m_request += m_path;
|
||||||
m_request.push_back(' ');
|
m_request.push_back(' ');
|
||||||
m_request += m_version;
|
m_request += m_version;
|
||||||
m_request.push_back('\r');
|
m_request.push_back('\r');
|
||||||
m_request.push_back('\n');
|
m_request.push_back('\n');
|
||||||
m_request.append("Connection: close\r\n");
|
m_request.append("Connection: close\r\n");
|
||||||
m_request.append(reinterpret_cast<const char *>(http_buff),len);
|
m_request.append(reinterpret_cast<const char *>(http_buff),len);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPProxyHandler::HandleData(uint8_t *http_buff, std::size_t len)
|
bool HTTPProxyHandler::HandleData(uint8_t *http_buff, std::size_t len)
|
||||||
{
|
{
|
||||||
assert(len); // This should always be called with a least a byte left to parse
|
assert(len); // This should always be called with a least a byte left to parse
|
||||||
while (len > 0)
|
while (len > 0)
|
||||||
{
|
{
|
||||||
//TODO: fallback to finding HOst: header if needed
|
//TODO: fallback to finding HOst: header if needed
|
||||||
switch (m_state)
|
switch (m_state)
|
||||||
{
|
{
|
||||||
case GET_METHOD:
|
case GET_METHOD:
|
||||||
switch (*http_buff)
|
switch (*http_buff)
|
||||||
{
|
{
|
||||||
case ' ': EnterState(GET_HOSTNAME); break;
|
case ' ': EnterState(GET_HOSTNAME); break;
|
||||||
default: m_method.push_back(*http_buff); break;
|
default: m_method.push_back(*http_buff); break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GET_HOSTNAME:
|
case GET_HOSTNAME:
|
||||||
switch (*http_buff)
|
switch (*http_buff)
|
||||||
{
|
{
|
||||||
case ' ': EnterState(GET_HTTPV); break;
|
case ' ': EnterState(GET_HTTPV); break;
|
||||||
default: m_url.push_back(*http_buff); break;
|
default: m_url.push_back(*http_buff); break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GET_HTTPV:
|
case GET_HTTPV:
|
||||||
switch (*http_buff)
|
switch (*http_buff)
|
||||||
{
|
{
|
||||||
case '\r': EnterState(GET_HTTPVNL); break;
|
case '\r': EnterState(GET_HTTPVNL); break;
|
||||||
default: m_version.push_back(*http_buff); break;
|
default: m_version.push_back(*http_buff); break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GET_HTTPVNL:
|
case GET_HTTPVNL:
|
||||||
switch (*http_buff)
|
switch (*http_buff)
|
||||||
{
|
{
|
||||||
case '\n': EnterState(DONE); break;
|
case '\n': EnterState(DONE); break;
|
||||||
default:
|
default:
|
||||||
LogPrint(eLogError,"--- HTTP Proxy rejected invalid request ending with: ", ((int)*http_buff));
|
LogPrint(eLogError,"--- HTTP Proxy rejected invalid request ending with: ", ((int)*http_buff));
|
||||||
HTTPRequestFailed(); //TODO: add correct code
|
HTTPRequestFailed(); //TODO: add correct code
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint(eLogError,"--- HTTP Proxy invalid state: ", m_state);
|
LogPrint(eLogError,"--- HTTP Proxy invalid state: ", m_state);
|
||||||
HTTPRequestFailed(); //TODO: add correct code 500
|
HTTPRequestFailed(); //TODO: add correct code 500
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
http_buff++;
|
http_buff++;
|
||||||
len--;
|
len--;
|
||||||
if (m_state == DONE)
|
if (m_state == DONE)
|
||||||
return CreateHTTPRequest(http_buff,len);
|
return CreateHTTPRequest(http_buff,len);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPProxyHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len)
|
void HTTPProxyHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len)
|
||||||
{
|
{
|
||||||
LogPrint(eLogDebug,"--- HTTP Proxy sock recv: ", len);
|
LogPrint(eLogDebug,"--- HTTP Proxy sock recv: ", len);
|
||||||
if(ecode)
|
if(ecode)
|
||||||
{
|
{
|
||||||
LogPrint(eLogWarning," --- HTTP Proxy sock recv got error: ", ecode);
|
LogPrint(eLogWarning," --- HTTP Proxy sock recv got error: ", ecode);
|
||||||
Terminate();
|
Terminate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HandleData(m_http_buff, len))
|
if (HandleData(m_http_buff, len))
|
||||||
{
|
{
|
||||||
if (m_state == DONE)
|
if (m_state == DONE)
|
||||||
{
|
{
|
||||||
LogPrint(eLogInfo,"--- HTTP Proxy requested: ", m_url);
|
LogPrint(eLogInfo,"--- HTTP Proxy requested: ", m_url);
|
||||||
GetOwner()->CreateStream (std::bind (&HTTPProxyHandler::HandleStreamRequestComplete,
|
GetOwner()->CreateStream (std::bind (&HTTPProxyHandler::HandleStreamRequestComplete,
|
||||||
shared_from_this(), std::placeholders::_1), m_address, m_port);
|
shared_from_this(), std::placeholders::_1), m_address, m_port);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
AsyncSockRead();
|
AsyncSockRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPProxyHandler::SentHTTPFailed(const boost::system::error_code & ecode)
|
void HTTPProxyHandler::SentHTTPFailed(const boost::system::error_code & ecode)
|
||||||
{
|
{
|
||||||
if (!ecode)
|
if (!ecode)
|
||||||
Terminate();
|
Terminate();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogError,"--- HTTP Proxy Closing socket after sending failure because: ", ecode.message ());
|
LogPrint (eLogError,"--- HTTP Proxy Closing socket after sending failure because: ", ecode.message ());
|
||||||
Terminate();
|
Terminate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPProxyHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
|
void HTTPProxyHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
|
||||||
{
|
{
|
||||||
if (stream)
|
if (stream)
|
||||||
{
|
{
|
||||||
if (Kill()) return;
|
if (Kill()) return;
|
||||||
LogPrint (eLogInfo,"--- HTTP Proxy New I2PTunnel connection");
|
LogPrint (eLogInfo,"--- HTTP Proxy New I2PTunnel connection");
|
||||||
auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, stream);
|
auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, stream);
|
||||||
GetOwner()->AddHandler (connection);
|
GetOwner()->AddHandler (connection);
|
||||||
connection->I2PConnect (reinterpret_cast<const uint8_t*>(m_request.data()), m_request.size());
|
connection->I2PConnect (reinterpret_cast<const uint8_t*>(m_request.data()), m_request.size());
|
||||||
Done(shared_from_this());
|
Done(shared_from_this());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogError,"--- HTTP Proxy Issue when creating the stream, check the previous warnings for more info.");
|
LogPrint (eLogError,"--- HTTP Proxy Issue when creating the stream, check the previous warnings for more info.");
|
||||||
HTTPRequestFailed(); // TODO: Send correct error message host unreachable
|
HTTPRequestFailed(); // TODO: Send correct error message host unreachable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPProxyServer::HTTPProxyServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination):
|
HTTPProxyServer::HTTPProxyServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination):
|
||||||
TCPIPAcceptor(port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
|
TCPIPAcceptor(port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<i2p::client::I2PServiceHandler> HTTPProxyServer::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
std::shared_ptr<i2p::client::I2PServiceHandler> HTTPProxyServer::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||||
{
|
{
|
||||||
return std::make_shared<HTTPProxyHandler> (this, socket);
|
return std::make_shared<HTTPProxyHandler> (this, socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
22
HTTPProxy.h
22
HTTPProxy.h
|
@ -12,20 +12,20 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace proxy
|
namespace proxy
|
||||||
{
|
{
|
||||||
class HTTPProxyServer: public i2p::client::TCPIPAcceptor
|
class HTTPProxyServer: public i2p::client::TCPIPAcceptor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HTTPProxyServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
|
HTTPProxyServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
|
||||||
~HTTPProxyServer() {};
|
~HTTPProxyServer() {};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Implements TCPIPAcceptor
|
// Implements TCPIPAcceptor
|
||||||
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
||||||
const char* GetName() { return "HTTP Proxy"; }
|
const char* GetName() { return "HTTP Proxy"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef HTTPProxyServer HTTPProxy;
|
typedef HTTPProxyServer HTTPProxy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2058
HTTPServer.cpp
2058
HTTPServer.cpp
File diff suppressed because it is too large
Load diff
196
HTTPServer.h
196
HTTPServer.h
|
@ -13,123 +13,123 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
|
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
|
||||||
const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
|
const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
|
||||||
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
|
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
struct header
|
struct header
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string value;
|
std::string value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct request
|
struct request
|
||||||
{
|
{
|
||||||
std::string method;
|
std::string method;
|
||||||
std::string uri;
|
std::string uri;
|
||||||
std::string host;
|
std::string host;
|
||||||
int port;
|
int port;
|
||||||
int http_version_major;
|
int http_version_major;
|
||||||
int http_version_minor;
|
int http_version_minor;
|
||||||
std::vector<header> headers;
|
std::vector<header> headers;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct reply
|
struct reply
|
||||||
{
|
{
|
||||||
std::vector<header> headers;
|
std::vector<header> headers;
|
||||||
std::string content;
|
std::string content;
|
||||||
|
|
||||||
std::vector<boost::asio::const_buffer> to_buffers (int status);
|
std::vector<boost::asio::const_buffer> to_buffers (int status);
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HTTPConnection (boost::asio::ip::tcp::socket * socket):
|
HTTPConnection (boost::asio::ip::tcp::socket * socket):
|
||||||
m_Socket (socket), m_Timer (socket->get_io_service ()),
|
m_Socket (socket), m_Timer (socket->get_io_service ()),
|
||||||
m_Stream (nullptr), m_BufferLen (0) {};
|
m_Stream (nullptr), m_BufferLen (0) {};
|
||||||
~HTTPConnection() { delete m_Socket; }
|
~HTTPConnection() { delete m_Socket; }
|
||||||
void Receive ();
|
void Receive ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void AsyncStreamReceive ();
|
void AsyncStreamReceive ();
|
||||||
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandleWriteReply(const boost::system::error_code& ecode);
|
void HandleWriteReply(const boost::system::error_code& ecode);
|
||||||
void HandleWrite (const boost::system::error_code& ecode);
|
void HandleWrite (const boost::system::error_code& ecode);
|
||||||
void SendReply (const std::string& content, int status = 200);
|
void SendReply (const std::string& content, int status = 200);
|
||||||
|
|
||||||
void HandleRequest (const std::string& address);
|
void HandleRequest (const std::string& address);
|
||||||
void HandleCommand (const std::string& command, std::stringstream& s);
|
void HandleCommand (const std::string& command, std::stringstream& s);
|
||||||
void ShowTransports (std::stringstream& s);
|
void ShowTransports (std::stringstream& s);
|
||||||
void ShowTunnels (std::stringstream& s);
|
void ShowTunnels (std::stringstream& s);
|
||||||
void ShowTransitTunnels (std::stringstream& s);
|
void ShowTransitTunnels (std::stringstream& s);
|
||||||
void ShowLocalDestinations (std::stringstream& s);
|
void ShowLocalDestinations (std::stringstream& s);
|
||||||
void ShowLocalDestination (const std::string& b32, std::stringstream& s);
|
void ShowLocalDestination (const std::string& b32, std::stringstream& s);
|
||||||
void ShowSAMSessions (std::stringstream& s);
|
void ShowSAMSessions (std::stringstream& s);
|
||||||
void ShowSAMSession (const std::string& id, std::stringstream& s);
|
void ShowSAMSession (const std::string& id, std::stringstream& s);
|
||||||
void StartAcceptingTunnels (std::stringstream& s);
|
void StartAcceptingTunnels (std::stringstream& s);
|
||||||
void StopAcceptingTunnels (std::stringstream& s);
|
void StopAcceptingTunnels (std::stringstream& s);
|
||||||
void FillContent (std::stringstream& s);
|
void FillContent (std::stringstream& s);
|
||||||
std::string ExtractAddress ();
|
std::string ExtractAddress ();
|
||||||
void ExtractParams (const std::string& str, std::map<std::string, std::string>& params);
|
void ExtractParams (const std::string& str, std::map<std::string, std::string>& params);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
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;
|
||||||
std::shared_ptr<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;
|
||||||
reply m_Reply;
|
reply m_Reply;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void RunRequest ();
|
virtual void RunRequest ();
|
||||||
void HandleDestinationRequest(const std::string& address, const std::string& uri);
|
void HandleDestinationRequest(const std::string& address, const std::string& uri);
|
||||||
void SendToAddress (const std::string& address, int port, const char * buf, size_t len);
|
void SendToAddress (const std::string& address, int port, const char * buf, size_t len);
|
||||||
void HandleDestinationRequestTimeout (const boost::system::error_code& ecode,
|
void HandleDestinationRequestTimeout (const boost::system::error_code& ecode,
|
||||||
i2p::data::IdentHash destination, int port, const char * buf, size_t len);
|
i2p::data::IdentHash destination, int port, const char * buf, size_t len);
|
||||||
void SendToDestination (std::shared_ptr<const i2p::data::LeaseSet> remote, int port, const char * buf, size_t len);
|
void SendToDestination (std::shared_ptr<const i2p::data::LeaseSet> remote, int port, const char * buf, size_t len);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static const std::string itoopieImage;
|
static const std::string itoopieImage;
|
||||||
static const std::string itoopieFavicon;
|
static const std::string itoopieFavicon;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HTTPServer
|
class HTTPServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HTTPServer (int port);
|
HTTPServer (int port);
|
||||||
virtual ~HTTPServer ();
|
virtual ~HTTPServer ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void Accept ();
|
void Accept ();
|
||||||
void HandleAccept(const boost::system::error_code& ecode);
|
void HandleAccept(const boost::system::error_code& ecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
boost::asio::io_service m_Service;
|
boost::asio::io_service m_Service;
|
||||||
boost::asio::io_service::work m_Work;
|
boost::asio::io_service::work m_Work;
|
||||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||||
boost::asio::ip::tcp::socket * m_NewSocket;
|
boost::asio::ip::tcp::socket * m_NewSocket;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket);
|
virtual void CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1158
I2NPProtocol.cpp
1158
I2NPProtocol.cpp
File diff suppressed because it is too large
Load diff
425
I2NPProtocol.h
425
I2NPProtocol.h
|
@ -12,240 +12,241 @@
|
||||||
#include "LeaseSet.h"
|
#include "LeaseSet.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
// I2NP header
|
// I2NP header
|
||||||
const size_t I2NP_HEADER_TYPEID_OFFSET = 0;
|
const size_t I2NP_HEADER_TYPEID_OFFSET = 0;
|
||||||
const size_t I2NP_HEADER_MSGID_OFFSET = I2NP_HEADER_TYPEID_OFFSET + 1;
|
const size_t I2NP_HEADER_MSGID_OFFSET = I2NP_HEADER_TYPEID_OFFSET + 1;
|
||||||
const size_t I2NP_HEADER_EXPIRATION_OFFSET = I2NP_HEADER_MSGID_OFFSET + 4;
|
const size_t I2NP_HEADER_EXPIRATION_OFFSET = I2NP_HEADER_MSGID_OFFSET + 4;
|
||||||
const size_t I2NP_HEADER_SIZE_OFFSET = I2NP_HEADER_EXPIRATION_OFFSET + 8;
|
const size_t I2NP_HEADER_SIZE_OFFSET = I2NP_HEADER_EXPIRATION_OFFSET + 8;
|
||||||
const size_t I2NP_HEADER_CHKS_OFFSET = I2NP_HEADER_SIZE_OFFSET + 2;
|
const size_t I2NP_HEADER_CHKS_OFFSET = I2NP_HEADER_SIZE_OFFSET + 2;
|
||||||
const size_t I2NP_HEADER_SIZE = I2NP_HEADER_CHKS_OFFSET + 1;
|
const size_t I2NP_HEADER_SIZE = I2NP_HEADER_CHKS_OFFSET + 1;
|
||||||
|
|
||||||
// I2NP short header
|
// I2NP short header
|
||||||
const size_t I2NP_SHORT_HEADER_TYPEID_OFFSET = 0;
|
const size_t I2NP_SHORT_HEADER_TYPEID_OFFSET = 0;
|
||||||
const size_t I2NP_SHORT_HEADER_EXPIRATION_OFFSET = I2NP_SHORT_HEADER_TYPEID_OFFSET + 1;
|
const size_t I2NP_SHORT_HEADER_EXPIRATION_OFFSET = I2NP_SHORT_HEADER_TYPEID_OFFSET + 1;
|
||||||
const size_t I2NP_SHORT_HEADER_SIZE = I2NP_SHORT_HEADER_EXPIRATION_OFFSET + 4;
|
const size_t I2NP_SHORT_HEADER_SIZE = I2NP_SHORT_HEADER_EXPIRATION_OFFSET + 4;
|
||||||
|
|
||||||
// Tunnel Gateway header
|
// Tunnel Gateway header
|
||||||
const size_t TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET = 0;
|
const size_t TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET = 0;
|
||||||
const size_t TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET = TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET + 4;
|
const size_t TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET = TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET + 4;
|
||||||
const size_t TUNNEL_GATEWAY_HEADER_SIZE = TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET + 2;
|
const size_t TUNNEL_GATEWAY_HEADER_SIZE = TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET + 2;
|
||||||
|
|
||||||
// DeliveryStatus
|
// DeliveryStatus
|
||||||
const size_t DELIVERY_STATUS_MSGID_OFFSET = 0;
|
const size_t DELIVERY_STATUS_MSGID_OFFSET = 0;
|
||||||
const size_t DELIVERY_STATUS_TIMESTAMP_OFFSET = DELIVERY_STATUS_MSGID_OFFSET + 4;
|
const size_t DELIVERY_STATUS_TIMESTAMP_OFFSET = DELIVERY_STATUS_MSGID_OFFSET + 4;
|
||||||
const size_t DELIVERY_STATUS_SIZE = DELIVERY_STATUS_TIMESTAMP_OFFSET + 8;
|
const size_t DELIVERY_STATUS_SIZE = DELIVERY_STATUS_TIMESTAMP_OFFSET + 8;
|
||||||
|
|
||||||
// DatabaseStore
|
// DatabaseStore
|
||||||
const size_t DATABASE_STORE_KEY_OFFSET = 0;
|
const size_t DATABASE_STORE_KEY_OFFSET = 0;
|
||||||
const size_t DATABASE_STORE_TYPE_OFFSET = DATABASE_STORE_KEY_OFFSET + 32;
|
const size_t DATABASE_STORE_TYPE_OFFSET = DATABASE_STORE_KEY_OFFSET + 32;
|
||||||
const size_t DATABASE_STORE_REPLY_TOKEN_OFFSET = DATABASE_STORE_TYPE_OFFSET + 1;
|
const size_t DATABASE_STORE_REPLY_TOKEN_OFFSET = DATABASE_STORE_TYPE_OFFSET + 1;
|
||||||
const size_t DATABASE_STORE_HEADER_SIZE = DATABASE_STORE_REPLY_TOKEN_OFFSET + 4;
|
const size_t DATABASE_STORE_HEADER_SIZE = DATABASE_STORE_REPLY_TOKEN_OFFSET + 4;
|
||||||
|
|
||||||
// TunnelBuild
|
// TunnelBuild
|
||||||
const size_t TUNNEL_BUILD_RECORD_SIZE = 528;
|
const size_t TUNNEL_BUILD_RECORD_SIZE = 528;
|
||||||
|
|
||||||
//BuildRequestRecordClearText
|
//BuildRequestRecordClearText
|
||||||
const size_t BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET = 0;
|
const size_t BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET = 0;
|
||||||
const size_t BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET = BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET + 4;
|
const size_t BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET = BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET + 4;
|
||||||
const size_t BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET = BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET + 32;
|
const size_t BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET = BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET + 32;
|
||||||
const size_t BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET = BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET + 4;
|
const size_t BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET = BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET + 4;
|
||||||
const size_t BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET = BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET + 32;
|
const size_t BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET = BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET + 32;
|
||||||
const size_t BUILD_REQUEST_RECORD_IV_KEY_OFFSET = BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET + 32;
|
const size_t BUILD_REQUEST_RECORD_IV_KEY_OFFSET = BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET + 32;
|
||||||
const size_t BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET = BUILD_REQUEST_RECORD_IV_KEY_OFFSET + 32;
|
const size_t BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET = BUILD_REQUEST_RECORD_IV_KEY_OFFSET + 32;
|
||||||
const size_t BUILD_REQUEST_RECORD_REPLY_IV_OFFSET = BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET + 32;
|
const size_t BUILD_REQUEST_RECORD_REPLY_IV_OFFSET = BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET + 32;
|
||||||
const size_t BUILD_REQUEST_RECORD_FLAG_OFFSET = BUILD_REQUEST_RECORD_REPLY_IV_OFFSET + 16;
|
const size_t BUILD_REQUEST_RECORD_FLAG_OFFSET = BUILD_REQUEST_RECORD_REPLY_IV_OFFSET + 16;
|
||||||
const size_t BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET = BUILD_REQUEST_RECORD_FLAG_OFFSET + 1;
|
const size_t BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET = BUILD_REQUEST_RECORD_FLAG_OFFSET + 1;
|
||||||
const size_t BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET = BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET + 4;
|
const size_t BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET = BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET + 4;
|
||||||
const size_t BUILD_REQUEST_RECORD_PADDING_OFFSET = BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET + 4;
|
const size_t BUILD_REQUEST_RECORD_PADDING_OFFSET = BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET + 4;
|
||||||
const size_t BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 222;
|
const size_t BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 222;
|
||||||
|
|
||||||
// BuildRequestRecordEncrypted
|
// BuildRequestRecordEncrypted
|
||||||
const size_t BUILD_REQUEST_RECORD_TO_PEER_OFFSET = 0;
|
const size_t BUILD_REQUEST_RECORD_TO_PEER_OFFSET = 0;
|
||||||
const size_t BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16;
|
const size_t BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16;
|
||||||
|
|
||||||
// BuildResponseRecord
|
// BuildResponseRecord
|
||||||
const size_t BUILD_RESPONSE_RECORD_HASH_OFFSET = 0;
|
const size_t BUILD_RESPONSE_RECORD_HASH_OFFSET = 0;
|
||||||
const size_t BUILD_RESPONSE_RECORD_PADDING_OFFSET = 32;
|
const size_t BUILD_RESPONSE_RECORD_PADDING_OFFSET = 32;
|
||||||
const size_t BUILD_RESPONSE_RECORD_PADDING_SIZE = 495;
|
const size_t BUILD_RESPONSE_RECORD_PADDING_SIZE = 495;
|
||||||
const size_t BUILD_RESPONSE_RECORD_RET_OFFSET = BUILD_RESPONSE_RECORD_PADDING_OFFSET + BUILD_RESPONSE_RECORD_PADDING_SIZE;
|
const size_t BUILD_RESPONSE_RECORD_RET_OFFSET = BUILD_RESPONSE_RECORD_PADDING_OFFSET + BUILD_RESPONSE_RECORD_PADDING_SIZE;
|
||||||
|
|
||||||
enum I2NPMessageType
|
enum I2NPMessageType
|
||||||
{
|
{
|
||||||
eI2NPDatabaseStore = 1,
|
eI2NPDatabaseStore = 1,
|
||||||
eI2NPDatabaseLookup = 2,
|
eI2NPDatabaseLookup = 2,
|
||||||
eI2NPDatabaseSearchReply = 3,
|
eI2NPDatabaseSearchReply = 3,
|
||||||
eI2NPDeliveryStatus = 10,
|
eI2NPDeliveryStatus = 10,
|
||||||
eI2NPGarlic = 11,
|
eI2NPGarlic = 11,
|
||||||
eI2NPTunnelData = 18,
|
eI2NPTunnelData = 18,
|
||||||
eI2NPTunnelGateway = 19,
|
eI2NPTunnelGateway = 19,
|
||||||
eI2NPData = 20,
|
eI2NPData = 20,
|
||||||
eI2NPTunnelBuild = 21,
|
eI2NPTunnelBuild = 21,
|
||||||
eI2NPTunnelBuildReply = 22,
|
eI2NPTunnelBuildReply = 22,
|
||||||
eI2NPVariableTunnelBuild = 23,
|
eI2NPVariableTunnelBuild = 23,
|
||||||
eI2NPVariableTunnelBuildReply = 24
|
eI2NPVariableTunnelBuildReply = 24
|
||||||
};
|
};
|
||||||
|
|
||||||
const int NUM_TUNNEL_BUILD_RECORDS = 8;
|
const int NUM_TUNNEL_BUILD_RECORDS = 8;
|
||||||
|
|
||||||
// DatabaseLookup flags
|
// DatabaseLookup flags
|
||||||
const uint8_t DATABASE_LOOKUP_DELIVERY_FLAG = 0x01;
|
const uint8_t DATABASE_LOOKUP_DELIVERY_FLAG = 0x01;
|
||||||
const uint8_t DATABASE_LOOKUP_ENCYPTION_FLAG = 0x02;
|
const uint8_t DATABASE_LOOKUP_ENCYPTION_FLAG = 0x02;
|
||||||
const uint8_t DATABASE_LOOKUP_TYPE_FLAGS_MASK = 0x0C;
|
const uint8_t DATABASE_LOOKUP_TYPE_FLAGS_MASK = 0x0C;
|
||||||
const uint8_t DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP = 0;
|
const uint8_t DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP = 0;
|
||||||
const uint8_t DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP = 0x04; // 0100
|
const uint8_t DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP = 0x04; // 0100
|
||||||
const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000
|
const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000
|
||||||
const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100
|
const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100
|
||||||
|
|
||||||
const int MAX_NUM_TRANSIT_TUNNELS = 2500;
|
const int MAX_NUM_TRANSIT_TUNNELS = 2500;
|
||||||
|
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
class InboundTunnel;
|
class InboundTunnel;
|
||||||
class TunnelPool;
|
class TunnelPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t I2NP_MAX_MESSAGE_SIZE = 32768;
|
const size_t I2NP_MAX_MESSAGE_SIZE = 32768;
|
||||||
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096;
|
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096;
|
||||||
struct I2NPMessage
|
struct I2NPMessage
|
||||||
{
|
{
|
||||||
uint8_t * buf;
|
uint8_t * buf;
|
||||||
size_t len, offset, maxLen;
|
size_t len, offset, maxLen;
|
||||||
std::shared_ptr<i2p::tunnel::InboundTunnel> from;
|
std::shared_ptr<i2p::tunnel::InboundTunnel> from;
|
||||||
|
|
||||||
I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2),
|
I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2),
|
||||||
offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header
|
offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header
|
||||||
|
|
||||||
// header accessors
|
// header accessors
|
||||||
uint8_t * GetHeader () { return GetBuffer (); };
|
uint8_t * GetHeader () { return GetBuffer (); };
|
||||||
const uint8_t * GetHeader () const { return GetBuffer (); };
|
const uint8_t * GetHeader () const { return GetBuffer (); };
|
||||||
void SetTypeID (uint8_t typeID) { GetHeader ()[I2NP_HEADER_TYPEID_OFFSET] = typeID; };
|
void SetTypeID (uint8_t typeID) { GetHeader ()[I2NP_HEADER_TYPEID_OFFSET] = typeID; };
|
||||||
uint8_t GetTypeID () const { return GetHeader ()[I2NP_HEADER_TYPEID_OFFSET]; };
|
uint8_t GetTypeID () const { return GetHeader ()[I2NP_HEADER_TYPEID_OFFSET]; };
|
||||||
void SetMsgID (uint32_t msgID) { htobe32buf (GetHeader () + I2NP_HEADER_MSGID_OFFSET, msgID); };
|
void SetMsgID (uint32_t msgID) { htobe32buf (GetHeader () + I2NP_HEADER_MSGID_OFFSET, msgID); };
|
||||||
uint32_t GetMsgID () const { return bufbe32toh (GetHeader () + I2NP_HEADER_MSGID_OFFSET); };
|
uint32_t GetMsgID () const { return bufbe32toh (GetHeader () + I2NP_HEADER_MSGID_OFFSET); };
|
||||||
void SetExpiration (uint64_t expiration) { htobe64buf (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET, expiration); };
|
void SetExpiration (uint64_t expiration) { htobe64buf (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET, expiration); };
|
||||||
uint64_t GetExpiration () const { return bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET); };
|
uint64_t GetExpiration () const { return bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET); };
|
||||||
void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); };
|
void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); };
|
||||||
uint16_t GetSize () const { return bufbe16toh (GetHeader () + I2NP_HEADER_SIZE_OFFSET); };
|
uint16_t GetSize () const { return bufbe16toh (GetHeader () + I2NP_HEADER_SIZE_OFFSET); };
|
||||||
void UpdateSize () { SetSize (GetPayloadLength ()); };
|
void UpdateSize () { SetSize (GetPayloadLength ()); };
|
||||||
void SetChks (uint8_t chks) { GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = chks; };
|
void SetChks (uint8_t chks) { GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = chks; };
|
||||||
void UpdateChks ()
|
void UpdateChks ()
|
||||||
{
|
{
|
||||||
uint8_t hash[32];
|
uint8_t hash[32];
|
||||||
CryptoPP::SHA256().CalculateDigest(hash, GetPayload (), GetPayloadLength ());
|
CryptoPP::SHA256().CalculateDigest(hash, GetPayload (), GetPayloadLength ());
|
||||||
GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = hash[0];
|
GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = hash[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// payload
|
// payload
|
||||||
uint8_t * GetPayload () { return GetBuffer () + I2NP_HEADER_SIZE; };
|
uint8_t * GetPayload () { return GetBuffer () + I2NP_HEADER_SIZE; };
|
||||||
const uint8_t * GetPayload () const { return GetBuffer () + I2NP_HEADER_SIZE; };
|
const uint8_t * GetPayload () const { return GetBuffer () + I2NP_HEADER_SIZE; };
|
||||||
uint8_t * GetBuffer () { return buf + offset; };
|
uint8_t * GetBuffer () { return buf + offset; };
|
||||||
const uint8_t * GetBuffer () const { return buf + offset; };
|
const uint8_t * GetBuffer () const { return buf + offset; };
|
||||||
size_t GetLength () const { return len - offset; };
|
size_t GetLength () const { return len - offset; };
|
||||||
size_t GetPayloadLength () const { return GetLength () - I2NP_HEADER_SIZE; };
|
size_t GetPayloadLength () const { return GetLength () - I2NP_HEADER_SIZE; };
|
||||||
|
|
||||||
void Align (size_t alignment)
|
void Align (size_t alignment)
|
||||||
{
|
{
|
||||||
if (len + alignment > maxLen) return;
|
if (len + alignment > maxLen) return;
|
||||||
size_t rem = ((size_t)GetBuffer ()) % alignment;
|
size_t rem = ((size_t)GetBuffer ()) % alignment;
|
||||||
if (rem)
|
if (rem)
|
||||||
{
|
{
|
||||||
offset += (alignment - rem);
|
offset += (alignment - rem);
|
||||||
len += (alignment - rem);
|
len += (alignment - rem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
I2NPMessage& operator=(const I2NPMessage& other)
|
I2NPMessage& operator=(const I2NPMessage& other)
|
||||||
{
|
{
|
||||||
memcpy (buf + offset, other.buf + other.offset, other.GetLength ());
|
memcpy (buf + offset, other.buf + other.offset, other.GetLength ());
|
||||||
len = offset + other.GetLength ();
|
len = offset + other.GetLength ();
|
||||||
from = other.from;
|
from = other.from;
|
||||||
return *this;
|
maxLen = other.maxLen;
|
||||||
}
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
// for SSU only
|
// for SSU only
|
||||||
uint8_t * GetSSUHeader () { return buf + offset + I2NP_HEADER_SIZE - I2NP_SHORT_HEADER_SIZE; };
|
uint8_t * GetSSUHeader () { return buf + offset + I2NP_HEADER_SIZE - I2NP_SHORT_HEADER_SIZE; };
|
||||||
void FromSSU (uint32_t msgID) // we have received SSU message and convert it to regular
|
void FromSSU (uint32_t msgID) // we have received SSU message and convert it to regular
|
||||||
{
|
{
|
||||||
const uint8_t * ssu = GetSSUHeader ();
|
const uint8_t * ssu = GetSSUHeader ();
|
||||||
GetHeader ()[I2NP_HEADER_TYPEID_OFFSET] = ssu[I2NP_SHORT_HEADER_TYPEID_OFFSET]; // typeid
|
GetHeader ()[I2NP_HEADER_TYPEID_OFFSET] = ssu[I2NP_SHORT_HEADER_TYPEID_OFFSET]; // typeid
|
||||||
SetMsgID (msgID);
|
SetMsgID (msgID);
|
||||||
SetExpiration (bufbe32toh (ssu + I2NP_SHORT_HEADER_EXPIRATION_OFFSET)*1000LL);
|
SetExpiration (bufbe32toh (ssu + I2NP_SHORT_HEADER_EXPIRATION_OFFSET)*1000LL);
|
||||||
SetSize (len - offset - I2NP_HEADER_SIZE);
|
SetSize (len - offset - I2NP_HEADER_SIZE);
|
||||||
SetChks (0);
|
SetChks (0);
|
||||||
}
|
}
|
||||||
uint32_t ToSSU () // return msgID
|
uint32_t ToSSU () // return msgID
|
||||||
{
|
{
|
||||||
uint8_t header[I2NP_HEADER_SIZE];
|
uint8_t header[I2NP_HEADER_SIZE];
|
||||||
memcpy (header, GetHeader (), I2NP_HEADER_SIZE);
|
memcpy (header, GetHeader (), I2NP_HEADER_SIZE);
|
||||||
uint8_t * ssu = GetSSUHeader ();
|
uint8_t * ssu = GetSSUHeader ();
|
||||||
ssu[I2NP_SHORT_HEADER_TYPEID_OFFSET] = header[I2NP_HEADER_TYPEID_OFFSET]; // typeid
|
ssu[I2NP_SHORT_HEADER_TYPEID_OFFSET] = header[I2NP_HEADER_TYPEID_OFFSET]; // typeid
|
||||||
htobe32buf (ssu + I2NP_SHORT_HEADER_EXPIRATION_OFFSET, bufbe64toh (header + I2NP_HEADER_EXPIRATION_OFFSET)/1000LL);
|
htobe32buf (ssu + I2NP_SHORT_HEADER_EXPIRATION_OFFSET, bufbe64toh (header + I2NP_HEADER_EXPIRATION_OFFSET)/1000LL);
|
||||||
len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET);
|
len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET);
|
||||||
return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET);
|
return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0);
|
void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0);
|
||||||
void RenewI2NPMessageHeader ();
|
void RenewI2NPMessageHeader ();
|
||||||
};
|
};
|
||||||
|
|
||||||
template<int sz>
|
template<int sz>
|
||||||
struct I2NPMessageBuffer: public I2NPMessage
|
struct I2NPMessageBuffer: public I2NPMessage
|
||||||
{
|
{
|
||||||
I2NPMessageBuffer () { buf = m_Buffer; maxLen = sz; };
|
I2NPMessageBuffer () { buf = m_Buffer; maxLen = sz; };
|
||||||
uint8_t m_Buffer[sz + 16];
|
uint8_t m_Buffer[sz + 16] = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
I2NPMessage * NewI2NPMessage ();
|
I2NPMessage * NewI2NPMessage ();
|
||||||
I2NPMessage * NewI2NPShortMessage ();
|
I2NPMessage * NewI2NPShortMessage ();
|
||||||
I2NPMessage * NewI2NPMessage (size_t len);
|
I2NPMessage * NewI2NPMessage (size_t len);
|
||||||
void DeleteI2NPMessage (I2NPMessage * msg);
|
void DeleteI2NPMessage (I2NPMessage * msg);
|
||||||
std::shared_ptr<I2NPMessage> ToSharedI2NPMessage (I2NPMessage * msg);
|
std::shared_ptr<I2NPMessage> ToSharedI2NPMessage (I2NPMessage * msg);
|
||||||
|
|
||||||
I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID = 0);
|
I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID = 0);
|
||||||
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
|
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID);
|
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID);
|
||||||
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
||||||
uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
|
uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
|
||||||
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
|
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
|
||||||
const std::set<i2p::data::IdentHash>& excludedFloodfills,
|
const std::set<i2p::data::IdentHash>& excludedFloodfills,
|
||||||
const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag);
|
const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag);
|
||||||
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
|
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0);
|
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0);
|
||||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet, uint32_t replyToken = 0);
|
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet, uint32_t replyToken = 0);
|
||||||
|
|
||||||
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText);
|
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText);
|
||||||
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
|
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
|
||||||
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
|
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
|
||||||
void HandleTunnelBuildMsg (uint8_t * buf, size_t len);
|
void HandleTunnelBuildMsg (uint8_t * buf, size_t len);
|
||||||
|
|
||||||
I2NPMessage * CreateTunnelDataMsg (const uint8_t * buf);
|
I2NPMessage * CreateTunnelDataMsg (const uint8_t * buf);
|
||||||
I2NPMessage * CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload);
|
I2NPMessage * CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload);
|
||||||
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg ();
|
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg ();
|
||||||
|
|
||||||
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len);
|
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len);
|
||||||
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
|
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
|
||||||
const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
|
const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
|
||||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
|
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
size_t GetI2NPMessageLength (const uint8_t * msg);
|
size_t GetI2NPMessageLength (const uint8_t * msg);
|
||||||
void HandleI2NPMessage (uint8_t * msg, size_t len);
|
void HandleI2NPMessage (uint8_t * msg, size_t len);
|
||||||
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
class I2NPMessagesHandler
|
class I2NPMessagesHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
~I2NPMessagesHandler ();
|
~I2NPMessagesHandler ();
|
||||||
void PutNextMessage (std::shared_ptr<I2NPMessage> msg);
|
void PutNextMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void Flush ();
|
void Flush ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs;
|
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
678
I2PControl.cpp
678
I2PControl.cpp
|
@ -22,395 +22,395 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
I2PControlService::I2PControlService (int port):
|
I2PControlService::I2PControlService (int port):
|
||||||
m_Password (I2P_CONTROL_DEFAULT_PASSWORD), m_IsRunning (false), m_Thread (nullptr),
|
m_Password (I2P_CONTROL_DEFAULT_PASSWORD), 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_ShutdownTimer (m_Service)
|
m_ShutdownTimer (m_Service)
|
||||||
{
|
{
|
||||||
m_MethodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlService::AuthenticateHandler;
|
m_MethodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlService::AuthenticateHandler;
|
||||||
m_MethodHandlers[I2P_CONTROL_METHOD_ECHO] = &I2PControlService::EchoHandler;
|
m_MethodHandlers[I2P_CONTROL_METHOD_ECHO] = &I2PControlService::EchoHandler;
|
||||||
m_MethodHandlers[I2P_CONTROL_METHOD_I2PCONTROL] = &I2PControlService::I2PControlHandler;
|
m_MethodHandlers[I2P_CONTROL_METHOD_I2PCONTROL] = &I2PControlService::I2PControlHandler;
|
||||||
m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_INFO] = &I2PControlService::RouterInfoHandler;
|
m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_INFO] = &I2PControlService::RouterInfoHandler;
|
||||||
m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlService::RouterManagerHandler;
|
m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlService::RouterManagerHandler;
|
||||||
m_MethodHandlers[I2P_CONTROL_METHOD_NETWORK_SETTING] = &I2PControlService::NetworkSettingHandler;
|
m_MethodHandlers[I2P_CONTROL_METHOD_NETWORK_SETTING] = &I2PControlService::NetworkSettingHandler;
|
||||||
|
|
||||||
// RouterInfo
|
// RouterInfo
|
||||||
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_UPTIME] = &I2PControlService::UptimeHandler;
|
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_UPTIME] = &I2PControlService::UptimeHandler;
|
||||||
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_VERSION] = &I2PControlService::VersionHandler;
|
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_VERSION] = &I2PControlService::VersionHandler;
|
||||||
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_STATUS] = &I2PControlService::StatusHandler;
|
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_STATUS] = &I2PControlService::StatusHandler;
|
||||||
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS] = &I2PControlService::NetDbKnownPeersHandler;
|
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS] = &I2PControlService::NetDbKnownPeersHandler;
|
||||||
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS] = &I2PControlService::NetDbActivePeersHandler;
|
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS] = &I2PControlService::NetDbActivePeersHandler;
|
||||||
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_STATUS] = &I2PControlService::NetStatusHandler;
|
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_STATUS] = &I2PControlService::NetStatusHandler;
|
||||||
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING] = &I2PControlService::TunnelsParticipatingHandler;
|
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING] = &I2PControlService::TunnelsParticipatingHandler;
|
||||||
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_IB_1S] = &I2PControlService::InboundBandwidth1S ;
|
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_IB_1S] = &I2PControlService::InboundBandwidth1S ;
|
||||||
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_OB_1S] = &I2PControlService::OutboundBandwidth1S ;
|
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_OB_1S] = &I2PControlService::OutboundBandwidth1S ;
|
||||||
|
|
||||||
// RouterManager
|
// RouterManager
|
||||||
m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN] = &I2PControlService::ShutdownHandler;
|
m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN] = &I2PControlService::ShutdownHandler;
|
||||||
m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL] = &I2PControlService::ShutdownGracefulHandler;
|
m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL] = &I2PControlService::ShutdownGracefulHandler;
|
||||||
m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlService::ReseedHandler;
|
m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlService::ReseedHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PControlService::~I2PControlService ()
|
I2PControlService::~I2PControlService ()
|
||||||
{
|
{
|
||||||
Stop ();
|
Stop ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::Start ()
|
void I2PControlService::Start ()
|
||||||
{
|
{
|
||||||
if (!m_IsRunning)
|
if (!m_IsRunning)
|
||||||
{
|
{
|
||||||
Accept ();
|
Accept ();
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
m_Thread = new std::thread (std::bind (&I2PControlService::Run, this));
|
m_Thread = new std::thread (std::bind (&I2PControlService::Run, this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::Stop ()
|
void I2PControlService::Stop ()
|
||||||
{
|
{
|
||||||
if (m_IsRunning)
|
if (m_IsRunning)
|
||||||
{
|
{
|
||||||
m_IsRunning = false;
|
m_IsRunning = false;
|
||||||
m_Acceptor.cancel ();
|
m_Acceptor.cancel ();
|
||||||
m_Service.stop ();
|
m_Service.stop ();
|
||||||
if (m_Thread)
|
if (m_Thread)
|
||||||
{
|
{
|
||||||
m_Thread->join ();
|
m_Thread->join ();
|
||||||
delete m_Thread;
|
delete m_Thread;
|
||||||
m_Thread = nullptr;
|
m_Thread = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::Run ()
|
void I2PControlService::Run ()
|
||||||
{
|
{
|
||||||
while (m_IsRunning)
|
while (m_IsRunning)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_Service.run ();
|
m_Service.run ();
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "I2PControl: ", ex.what ());
|
LogPrint (eLogError, "I2PControl: ", ex.what ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::Accept ()
|
void I2PControlService::Accept ()
|
||||||
{
|
{
|
||||||
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (m_Service);
|
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (m_Service);
|
||||||
m_Acceptor.async_accept (*newSocket, std::bind (&I2PControlService::HandleAccept, this,
|
m_Acceptor.async_accept (*newSocket, std::bind (&I2PControlService::HandleAccept, this,
|
||||||
std::placeholders::_1, newSocket));
|
std::placeholders::_1, newSocket));
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
Accept ();
|
Accept ();
|
||||||
|
|
||||||
if (!ecode)
|
if (!ecode)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "New I2PControl request from ", socket->remote_endpoint ());
|
LogPrint (eLogInfo, "New I2PControl request from ", socket->remote_endpoint ());
|
||||||
std::this_thread::sleep_for (std::chrono::milliseconds(5));
|
std::this_thread::sleep_for (std::chrono::milliseconds(5));
|
||||||
ReadRequest (socket);
|
ReadRequest (socket);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "I2PControl accept error: ", ecode.message ());
|
LogPrint (eLogError, "I2PControl accept error: ", ecode.message ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::ReadRequest (std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
void I2PControlService::ReadRequest (std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||||
{
|
{
|
||||||
auto request = std::make_shared<I2PControlBuffer>();
|
auto request = std::make_shared<I2PControlBuffer>();
|
||||||
socket->async_read_some (
|
socket->async_read_some (
|
||||||
#if BOOST_VERSION >= 104900
|
#if BOOST_VERSION >= 104900
|
||||||
boost::asio::buffer (*request),
|
boost::asio::buffer (*request),
|
||||||
#else
|
#else
|
||||||
boost::asio::buffer (request->data (), request->size ()),
|
boost::asio::buffer (request->data (), request->size ()),
|
||||||
#endif
|
#endif
|
||||||
std::bind(&I2PControlService::HandleRequestReceived, this,
|
std::bind(&I2PControlService::HandleRequestReceived, this,
|
||||||
std::placeholders::_1, std::placeholders::_2, socket, request));
|
std::placeholders::_1, std::placeholders::_2, socket, request));
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode,
|
void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode,
|
||||||
size_t bytes_transferred, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
size_t bytes_transferred, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||||
std::shared_ptr<I2PControlBuffer> buf)
|
std::shared_ptr<I2PControlBuffer> buf)
|
||||||
{
|
{
|
||||||
if (ecode)
|
if (ecode)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "I2PControl read error: ", ecode.message ());
|
LogPrint (eLogError, "I2PControl read error: ", ecode.message ());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool isHtml = !memcmp (buf->data (), "POST", 4);
|
bool isHtml = !memcmp (buf->data (), "POST", 4);
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss.write (buf->data (), bytes_transferred);
|
ss.write (buf->data (), bytes_transferred);
|
||||||
if (isHtml)
|
if (isHtml)
|
||||||
{
|
{
|
||||||
std::string header;
|
std::string header;
|
||||||
while (!ss.eof () && header != "\r")
|
while (!ss.eof () && header != "\r")
|
||||||
std::getline(ss, header);
|
std::getline(ss, header);
|
||||||
if (ss.eof ())
|
if (ss.eof ())
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Malformed I2PControl request. HTTP header expected");
|
LogPrint (eLogError, "Malformed I2PControl request. HTTP header expected");
|
||||||
return; // TODO:
|
return; // TODO:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if GCC47_BOOST149
|
#if GCC47_BOOST149
|
||||||
LogPrint (eLogError, "json_read is not supported due bug in boost 1.49 with gcc 4.7");
|
LogPrint (eLogError, "json_read is not supported due bug in boost 1.49 with gcc 4.7");
|
||||||
#else
|
#else
|
||||||
boost::property_tree::ptree pt;
|
boost::property_tree::ptree pt;
|
||||||
boost::property_tree::read_json (ss, pt);
|
boost::property_tree::read_json (ss, pt);
|
||||||
|
|
||||||
std::string method = pt.get<std::string>(I2P_CONTROL_PROPERTY_METHOD);
|
std::string method = pt.get<std::string>(I2P_CONTROL_PROPERTY_METHOD);
|
||||||
auto it = m_MethodHandlers.find (method);
|
auto it = m_MethodHandlers.find (method);
|
||||||
if (it != m_MethodHandlers.end ())
|
if (it != m_MethodHandlers.end ())
|
||||||
{
|
{
|
||||||
std::ostringstream response;
|
std::ostringstream response;
|
||||||
response << "{\"id\":" << pt.get<std::string>(I2P_CONTROL_PROPERTY_ID) << ",\"result\":{";
|
response << "{\"id\":" << pt.get<std::string>(I2P_CONTROL_PROPERTY_ID) << ",\"result\":{";
|
||||||
|
|
||||||
(this->*(it->second))(pt.get_child (I2P_CONTROL_PROPERTY_PARAMS), response);
|
(this->*(it->second))(pt.get_child (I2P_CONTROL_PROPERTY_PARAMS), response);
|
||||||
response << "},\"jsonrpc\":\"2.0\"}";
|
response << "},\"jsonrpc\":\"2.0\"}";
|
||||||
SendResponse (socket, buf, response, isHtml);
|
SendResponse (socket, buf, response, isHtml);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Unknown I2PControl method ", method);
|
LogPrint (eLogWarning, "Unknown I2PControl method ", method);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "I2PControl handle request: ", ex.what ());
|
LogPrint (eLogError, "I2PControl handle request: ", ex.what ());
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "I2PControl handle request unknown exception");
|
LogPrint (eLogError, "I2PControl handle request unknown exception");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, int value) const
|
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, int value) const
|
||||||
{
|
{
|
||||||
ss << "\"" << name << "\":" << value;
|
ss << "\"" << name << "\":" << value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const
|
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const
|
||||||
{
|
{
|
||||||
ss << "\"" << name << "\":";
|
ss << "\"" << name << "\":";
|
||||||
if (value.length () > 0)
|
if (value.length () > 0)
|
||||||
ss << "\"" << value << "\"";
|
ss << "\"" << value << "\"";
|
||||||
else
|
else
|
||||||
ss << "null";
|
ss << "null";
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, double value) const
|
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, double value) const
|
||||||
{
|
{
|
||||||
ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value;
|
ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::SendResponse (std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
void I2PControlService::SendResponse (std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||||
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml)
|
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml)
|
||||||
{
|
{
|
||||||
size_t len = response.str ().length (), offset = 0;
|
size_t len = response.str ().length (), offset = 0;
|
||||||
if (isHtml)
|
if (isHtml)
|
||||||
{
|
{
|
||||||
std::ostringstream header;
|
std::ostringstream header;
|
||||||
header << "HTTP/1.1 200 OK\r\n";
|
header << "HTTP/1.1 200 OK\r\n";
|
||||||
header << "Connection: close\r\n";
|
header << "Connection: close\r\n";
|
||||||
header << "Content-Length: " << boost::lexical_cast<std::string>(len) << "\r\n";
|
header << "Content-Length: " << boost::lexical_cast<std::string>(len) << "\r\n";
|
||||||
header << "Content-Type: application/json\r\n";
|
header << "Content-Type: application/json\r\n";
|
||||||
header << "Date: ";
|
header << "Date: ";
|
||||||
auto facet = new boost::local_time::local_time_facet ("%a, %d %b %Y %H:%M:%S GMT");
|
auto facet = new boost::local_time::local_time_facet ("%a, %d %b %Y %H:%M:%S GMT");
|
||||||
header.imbue(std::locale (header.getloc(), facet));
|
header.imbue(std::locale (header.getloc(), facet));
|
||||||
header << boost::posix_time::second_clock::local_time() << "\r\n";
|
header << boost::posix_time::second_clock::local_time() << "\r\n";
|
||||||
header << "\r\n";
|
header << "\r\n";
|
||||||
offset = header.str ().size ();
|
offset = header.str ().size ();
|
||||||
memcpy (buf->data (), header.str ().c_str (), offset);
|
memcpy (buf->data (), header.str ().c_str (), offset);
|
||||||
}
|
}
|
||||||
memcpy (buf->data () + offset, response.str ().c_str (), len);
|
memcpy (buf->data () + offset, response.str ().c_str (), len);
|
||||||
boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), offset + len),
|
boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), offset + len),
|
||||||
boost::asio::transfer_all (),
|
boost::asio::transfer_all (),
|
||||||
std::bind(&I2PControlService::HandleResponseSent, this,
|
std::bind(&I2PControlService::HandleResponseSent, this,
|
||||||
std::placeholders::_1, std::placeholders::_2, socket, buf));
|
std::placeholders::_1, std::placeholders::_2, socket, buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
|
void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf)
|
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf)
|
||||||
{
|
{
|
||||||
if (ecode)
|
if (ecode)
|
||||||
LogPrint (eLogError, "I2PControl write error: ", ecode.message ());
|
LogPrint (eLogError, "I2PControl write error: ", ecode.message ());
|
||||||
socket->close ();
|
socket->close ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// handlers
|
// handlers
|
||||||
|
|
||||||
void I2PControlService::AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
void I2PControlService::AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||||
{
|
{
|
||||||
int api = params.get<int> (I2P_CONTROL_PARAM_API);
|
int api = params.get<int> (I2P_CONTROL_PARAM_API);
|
||||||
auto password = params.get<std::string> (I2P_CONTROL_PARAM_PASSWORD);
|
auto password = params.get<std::string> (I2P_CONTROL_PARAM_PASSWORD);
|
||||||
LogPrint (eLogDebug, "I2PControl Authenticate API=", api, " Password=", password);
|
LogPrint (eLogDebug, "I2PControl Authenticate API=", api, " Password=", password);
|
||||||
if (password != m_Password)
|
if (password != m_Password)
|
||||||
LogPrint (eLogError, "I2PControl Authenticate Invalid password ", password, " expected ", m_Password);
|
LogPrint (eLogError, "I2PControl Authenticate Invalid password ", password, " expected ", m_Password);
|
||||||
InsertParam (results, I2P_CONTROL_PARAM_API, api);
|
InsertParam (results, I2P_CONTROL_PARAM_API, api);
|
||||||
results << ",";
|
results << ",";
|
||||||
std::string token = boost::lexical_cast<std::string>(i2p::util::GetSecondsSinceEpoch ());
|
std::string token = boost::lexical_cast<std::string>(i2p::util::GetSecondsSinceEpoch ());
|
||||||
m_Tokens.insert (token);
|
m_Tokens.insert (token);
|
||||||
InsertParam (results, I2P_CONTROL_PARAM_TOKEN, token);
|
InsertParam (results, I2P_CONTROL_PARAM_TOKEN, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||||
{
|
{
|
||||||
auto echo = params.get<std::string> (I2P_CONTROL_PARAM_ECHO);
|
auto echo = params.get<std::string> (I2P_CONTROL_PARAM_ECHO);
|
||||||
LogPrint (eLogDebug, "I2PControl Echo Echo=", echo);
|
LogPrint (eLogDebug, "I2PControl Echo Echo=", echo);
|
||||||
InsertParam (results, I2P_CONTROL_PARAM_RESULT, echo);
|
InsertParam (results, I2P_CONTROL_PARAM_RESULT, echo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// I2PControl
|
// I2PControl
|
||||||
|
|
||||||
void I2PControlService::I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
void I2PControlService::I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "I2PControl I2PControl");
|
LogPrint (eLogDebug, "I2PControl I2PControl");
|
||||||
for (auto& it: params)
|
for (auto& it: params)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, it.first);
|
LogPrint (eLogDebug, it.first);
|
||||||
auto it1 = m_I2PControlHandlers.find (it.first);
|
auto it1 = m_I2PControlHandlers.find (it.first);
|
||||||
if (it1 != m_I2PControlHandlers.end ())
|
if (it1 != m_I2PControlHandlers.end ())
|
||||||
(this->*(it1->second))(it.second.data ());
|
(this->*(it1->second))(it.second.data ());
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it.first);
|
LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RouterInfo
|
// RouterInfo
|
||||||
|
|
||||||
void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "I2PControl RouterInfo");
|
LogPrint (eLogDebug, "I2PControl RouterInfo");
|
||||||
for (auto it = params.begin (); it != params.end (); it++)
|
for (auto it = params.begin (); it != params.end (); it++)
|
||||||
{
|
{
|
||||||
if (it != params.begin ()) results << ",";
|
if (it != params.begin ()) results << ",";
|
||||||
LogPrint (eLogDebug, it->first);
|
LogPrint (eLogDebug, it->first);
|
||||||
auto it1 = m_RouterInfoHandlers.find (it->first);
|
auto it1 = m_RouterInfoHandlers.find (it->first);
|
||||||
if (it1 != m_RouterInfoHandlers.end ())
|
if (it1 != m_RouterInfoHandlers.end ())
|
||||||
(this->*(it1->second))(results);
|
(this->*(it1->second))(results);
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "I2PControl RouterInfo unknown request ", it->first);
|
LogPrint (eLogError, "I2PControl RouterInfo unknown request ", it->first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::UptimeHandler (std::ostringstream& results)
|
void I2PControlService::UptimeHandler (std::ostringstream& results)
|
||||||
{
|
{
|
||||||
InsertParam (results, I2P_CONTROL_ROUTER_INFO_UPTIME, (int)i2p::context.GetUptime ()*1000);
|
InsertParam (results, I2P_CONTROL_ROUTER_INFO_UPTIME, (int)i2p::context.GetUptime ()*1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::VersionHandler (std::ostringstream& results)
|
void I2PControlService::VersionHandler (std::ostringstream& results)
|
||||||
{
|
{
|
||||||
InsertParam (results, I2P_CONTROL_ROUTER_INFO_VERSION, VERSION);
|
InsertParam (results, I2P_CONTROL_ROUTER_INFO_VERSION, VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::StatusHandler (std::ostringstream& results)
|
void I2PControlService::StatusHandler (std::ostringstream& results)
|
||||||
{
|
{
|
||||||
InsertParam (results, I2P_CONTROL_ROUTER_INFO_STATUS, "???"); // TODO:
|
InsertParam (results, I2P_CONTROL_ROUTER_INFO_STATUS, "???"); // TODO:
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results)
|
void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results)
|
||||||
{
|
{
|
||||||
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS, i2p::data::netdb.GetNumRouters ());
|
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS, i2p::data::netdb.GetNumRouters ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results)
|
void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results)
|
||||||
{
|
{
|
||||||
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS, (int)i2p::transport::transports.GetPeers ().size ());
|
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS, (int)i2p::transport::transports.GetPeers ().size ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::NetStatusHandler (std::ostringstream& results)
|
void I2PControlService::NetStatusHandler (std::ostringstream& results)
|
||||||
{
|
{
|
||||||
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NET_STATUS, (int)i2p::context.GetStatus ());
|
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NET_STATUS, (int)i2p::context.GetStatus ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::TunnelsParticipatingHandler (std::ostringstream& results)
|
void I2PControlService::TunnelsParticipatingHandler (std::ostringstream& results)
|
||||||
{
|
{
|
||||||
InsertParam (results, I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING, (int)i2p::tunnel::tunnels.GetTransitTunnels ().size ());
|
InsertParam (results, I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING, (int)i2p::tunnel::tunnels.GetTransitTunnels ().size ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::InboundBandwidth1S (std::ostringstream& results)
|
void I2PControlService::InboundBandwidth1S (std::ostringstream& results)
|
||||||
{
|
{
|
||||||
InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_IB_1S, (double)i2p::transport::transports.GetInBandwidth ());
|
InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_IB_1S, (double)i2p::transport::transports.GetInBandwidth ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::OutboundBandwidth1S (std::ostringstream& results)
|
void I2PControlService::OutboundBandwidth1S (std::ostringstream& results)
|
||||||
{
|
{
|
||||||
InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_OB_1S, (double)i2p::transport::transports.GetOutBandwidth ());
|
InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_OB_1S, (double)i2p::transport::transports.GetOutBandwidth ());
|
||||||
}
|
}
|
||||||
|
|
||||||
// RouterManager
|
// RouterManager
|
||||||
|
|
||||||
void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "I2PControl RouterManager");
|
LogPrint (eLogDebug, "I2PControl RouterManager");
|
||||||
for (auto it = params.begin (); it != params.end (); it++)
|
for (auto it = params.begin (); it != params.end (); it++)
|
||||||
{
|
{
|
||||||
if (it != params.begin ()) results << ",";
|
if (it != params.begin ()) results << ",";
|
||||||
LogPrint (eLogDebug, it->first);
|
LogPrint (eLogDebug, it->first);
|
||||||
auto it1 = m_RouterManagerHandlers.find (it->first);
|
auto it1 = m_RouterManagerHandlers.find (it->first);
|
||||||
if (it1 != m_RouterManagerHandlers.end ())
|
if (it1 != m_RouterManagerHandlers.end ())
|
||||||
(this->*(it1->second))(results);
|
(this->*(it1->second))(results);
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "I2PControl RouterManager unknown request ", it->first);
|
LogPrint (eLogError, "I2PControl RouterManager unknown request ", it->first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void I2PControlService::ShutdownHandler (std::ostringstream& results)
|
void I2PControlService::ShutdownHandler (std::ostringstream& results)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Shutdown requested");
|
LogPrint (eLogInfo, "Shutdown requested");
|
||||||
InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, "");
|
InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, "");
|
||||||
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent
|
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent
|
||||||
m_ShutdownTimer.async_wait (
|
m_ShutdownTimer.async_wait (
|
||||||
[](const boost::system::error_code& ecode)
|
[](const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
Daemon.running = 0;
|
Daemon.running = 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::ShutdownGracefulHandler (std::ostringstream& results)
|
void I2PControlService::ShutdownGracefulHandler (std::ostringstream& results)
|
||||||
{
|
{
|
||||||
i2p::context.SetAcceptsTunnels (false);
|
i2p::context.SetAcceptsTunnels (false);
|
||||||
int timeout = i2p::tunnel::tunnels.GetTransitTunnelsExpirationTimeout ();
|
int timeout = i2p::tunnel::tunnels.GetTransitTunnelsExpirationTimeout ();
|
||||||
LogPrint (eLogInfo, "Graceful shutdown requested. Will shutdown after ", timeout, " seconds");
|
LogPrint (eLogInfo, "Graceful shutdown requested. Will shutdown after ", timeout, " seconds");
|
||||||
InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL, "");
|
InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL, "");
|
||||||
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second
|
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second
|
||||||
m_ShutdownTimer.async_wait (
|
m_ShutdownTimer.async_wait (
|
||||||
[](const boost::system::error_code& ecode)
|
[](const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
Daemon.running = 0;
|
Daemon.running = 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::ReseedHandler (std::ostringstream& results)
|
void I2PControlService::ReseedHandler (std::ostringstream& results)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Reseed requested");
|
LogPrint (eLogInfo, "Reseed requested");
|
||||||
InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, "");
|
InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, "");
|
||||||
i2p::data::netdb.Reseed ();
|
i2p::data::netdb.Reseed ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// network setting
|
// network setting
|
||||||
void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "I2PControl NetworkSetting");
|
LogPrint (eLogDebug, "I2PControl NetworkSetting");
|
||||||
for (auto it = params.begin (); it != params.end (); it++)
|
for (auto it = params.begin (); it != params.end (); it++)
|
||||||
{
|
{
|
||||||
if (it != params.begin ()) results << ",";
|
if (it != params.begin ()) results << ",";
|
||||||
LogPrint (eLogDebug, it->first);
|
LogPrint (eLogDebug, it->first);
|
||||||
auto it1 = m_NetworkSettingHandlers.find (it->first);
|
auto it1 = m_NetworkSettingHandlers.find (it->first);
|
||||||
if (it1 != m_NetworkSettingHandlers.end ())
|
if (it1 != m_NetworkSettingHandlers.end ())
|
||||||
(this->*(it1->second))(it->second.data (), results);
|
(this->*(it1->second))(it->second.data (), results);
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it->first);
|
LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it->first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
206
I2PControl.h
206
I2PControl.h
|
@ -16,132 +16,132 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024;
|
const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024;
|
||||||
typedef std::array<char, I2P_CONTROL_MAX_REQUEST_SIZE> I2PControlBuffer;
|
typedef std::array<char, I2P_CONTROL_MAX_REQUEST_SIZE> I2PControlBuffer;
|
||||||
|
|
||||||
const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie";
|
const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie";
|
||||||
|
|
||||||
const char I2P_CONTROL_PROPERTY_ID[] = "id";
|
const char I2P_CONTROL_PROPERTY_ID[] = "id";
|
||||||
const char I2P_CONTROL_PROPERTY_METHOD[] = "method";
|
const char I2P_CONTROL_PROPERTY_METHOD[] = "method";
|
||||||
const char I2P_CONTROL_PROPERTY_PARAMS[] = "params";
|
const char I2P_CONTROL_PROPERTY_PARAMS[] = "params";
|
||||||
const char I2P_CONTROL_PROPERTY_RESULT[] = "result";
|
const char I2P_CONTROL_PROPERTY_RESULT[] = "result";
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
const char I2P_CONTROL_METHOD_AUTHENTICATE[] = "Authenticate";
|
const char I2P_CONTROL_METHOD_AUTHENTICATE[] = "Authenticate";
|
||||||
const char I2P_CONTROL_METHOD_ECHO[] = "Echo";
|
const char I2P_CONTROL_METHOD_ECHO[] = "Echo";
|
||||||
const char I2P_CONTROL_METHOD_I2PCONTROL[] = "I2PControl";
|
const char I2P_CONTROL_METHOD_I2PCONTROL[] = "I2PControl";
|
||||||
const char I2P_CONTROL_METHOD_ROUTER_INFO[] = "RouterInfo";
|
const char I2P_CONTROL_METHOD_ROUTER_INFO[] = "RouterInfo";
|
||||||
const char I2P_CONTROL_METHOD_ROUTER_MANAGER[] = "RouterManager";
|
const char I2P_CONTROL_METHOD_ROUTER_MANAGER[] = "RouterManager";
|
||||||
const char I2P_CONTROL_METHOD_NETWORK_SETTING[] = "NetworkSetting";
|
const char I2P_CONTROL_METHOD_NETWORK_SETTING[] = "NetworkSetting";
|
||||||
|
|
||||||
// params
|
// params
|
||||||
const char I2P_CONTROL_PARAM_API[] = "API";
|
const char I2P_CONTROL_PARAM_API[] = "API";
|
||||||
const char I2P_CONTROL_PARAM_PASSWORD[] = "Password";
|
const char I2P_CONTROL_PARAM_PASSWORD[] = "Password";
|
||||||
const char I2P_CONTROL_PARAM_TOKEN[] = "Token";
|
const char I2P_CONTROL_PARAM_TOKEN[] = "Token";
|
||||||
const char I2P_CONTROL_PARAM_ECHO[] = "Echo";
|
const char I2P_CONTROL_PARAM_ECHO[] = "Echo";
|
||||||
const char I2P_CONTROL_PARAM_RESULT[] = "Result";
|
const char I2P_CONTROL_PARAM_RESULT[] = "Result";
|
||||||
|
|
||||||
// I2PControl
|
// I2PControl
|
||||||
const char I2P_CONTROL_I2PCONTROL_ADDRESS[] = "i2pcontrol.address";
|
const char I2P_CONTROL_I2PCONTROL_ADDRESS[] = "i2pcontrol.address";
|
||||||
const char I2P_CONTROL_I2PCONTROL_PASSWORD[] = "i2pcontrol.password";
|
const char I2P_CONTROL_I2PCONTROL_PASSWORD[] = "i2pcontrol.password";
|
||||||
const char I2P_CONTROL_I2PCONTROL_PORT[] = "i2pcontrol.port";
|
const char I2P_CONTROL_I2PCONTROL_PORT[] = "i2pcontrol.port";
|
||||||
|
|
||||||
// RouterInfo requests
|
// RouterInfo requests
|
||||||
const char I2P_CONTROL_ROUTER_INFO_UPTIME[] = "i2p.router.uptime";
|
const char I2P_CONTROL_ROUTER_INFO_UPTIME[] = "i2p.router.uptime";
|
||||||
const char I2P_CONTROL_ROUTER_INFO_VERSION[] = "i2p.router.version";
|
const char I2P_CONTROL_ROUTER_INFO_VERSION[] = "i2p.router.version";
|
||||||
const char I2P_CONTROL_ROUTER_INFO_STATUS[] = "i2p.router.status";
|
const char I2P_CONTROL_ROUTER_INFO_STATUS[] = "i2p.router.status";
|
||||||
const char I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS[] = "i2p.router.netdb.knownpeers";
|
const char I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS[] = "i2p.router.netdb.knownpeers";
|
||||||
const char I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS[] = "i2p.router.netdb.activepeers";
|
const char I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS[] = "i2p.router.netdb.activepeers";
|
||||||
const char I2P_CONTROL_ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status";
|
const char I2P_CONTROL_ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status";
|
||||||
const char I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating";
|
const char I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating";
|
||||||
const char I2P_CONTROL_ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s";
|
const char I2P_CONTROL_ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s";
|
||||||
const char I2P_CONTROL_ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s";
|
const char I2P_CONTROL_ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s";
|
||||||
|
|
||||||
// RouterManager requests
|
// RouterManager requests
|
||||||
const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN[] = "Shutdown";
|
const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN[] = "Shutdown";
|
||||||
const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful";
|
const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful";
|
||||||
const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed";
|
const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed";
|
||||||
|
|
||||||
class I2PControlService
|
class I2PControlService
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
I2PControlService (int port);
|
I2PControlService (int port);
|
||||||
~I2PControlService ();
|
~I2PControlService ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void Accept ();
|
void Accept ();
|
||||||
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
||||||
void ReadRequest (std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
void ReadRequest (std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
||||||
void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred,
|
void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf);
|
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf);
|
||||||
void SendResponse (std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
void SendResponse (std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||||
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml);
|
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml);
|
||||||
void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
|
void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf);
|
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void InsertParam (std::ostringstream& ss, const std::string& name, int value) const;
|
void InsertParam (std::ostringstream& ss, const std::string& name, int value) const;
|
||||||
void InsertParam (std::ostringstream& ss, const std::string& name, double value) const;
|
void InsertParam (std::ostringstream& ss, const std::string& name, double value) const;
|
||||||
void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const;
|
void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const;
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
typedef void (I2PControlService::*MethodHandler)(const boost::property_tree::ptree& params, std::ostringstream& results);
|
typedef void (I2PControlService::*MethodHandler)(const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
|
|
||||||
void AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
void AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
void EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
void EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
void I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
void I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
void RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
void RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
|
|
||||||
// I2PControl
|
// I2PControl
|
||||||
typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value);
|
typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value);
|
||||||
|
|
||||||
// RouterInfo
|
// RouterInfo
|
||||||
typedef void (I2PControlService::*RouterInfoRequestHandler)(std::ostringstream& results);
|
typedef void (I2PControlService::*RouterInfoRequestHandler)(std::ostringstream& results);
|
||||||
void UptimeHandler (std::ostringstream& results);
|
void UptimeHandler (std::ostringstream& results);
|
||||||
void VersionHandler (std::ostringstream& results);
|
void VersionHandler (std::ostringstream& results);
|
||||||
void StatusHandler (std::ostringstream& results);
|
void StatusHandler (std::ostringstream& results);
|
||||||
void NetDbKnownPeersHandler (std::ostringstream& results);
|
void NetDbKnownPeersHandler (std::ostringstream& results);
|
||||||
void NetDbActivePeersHandler (std::ostringstream& results);
|
void NetDbActivePeersHandler (std::ostringstream& results);
|
||||||
void NetStatusHandler (std::ostringstream& results);
|
void NetStatusHandler (std::ostringstream& results);
|
||||||
void TunnelsParticipatingHandler (std::ostringstream& results);
|
void TunnelsParticipatingHandler (std::ostringstream& results);
|
||||||
void InboundBandwidth1S (std::ostringstream& results);
|
void InboundBandwidth1S (std::ostringstream& results);
|
||||||
void OutboundBandwidth1S (std::ostringstream& results);
|
void OutboundBandwidth1S (std::ostringstream& results);
|
||||||
|
|
||||||
// RouterManager
|
// RouterManager
|
||||||
typedef void (I2PControlService::*RouterManagerRequestHandler)(std::ostringstream& results);
|
typedef void (I2PControlService::*RouterManagerRequestHandler)(std::ostringstream& results);
|
||||||
void ShutdownHandler (std::ostringstream& results);
|
void ShutdownHandler (std::ostringstream& results);
|
||||||
void ShutdownGracefulHandler (std::ostringstream& results);
|
void ShutdownGracefulHandler (std::ostringstream& results);
|
||||||
void ReseedHandler (std::ostringstream& results);
|
void ReseedHandler (std::ostringstream& results);
|
||||||
|
|
||||||
// NetworkSetting
|
// NetworkSetting
|
||||||
typedef void (I2PControlService::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results);
|
typedef void (I2PControlService::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::string m_Password;
|
std::string m_Password;
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
|
|
||||||
boost::asio::io_service m_Service;
|
boost::asio::io_service m_Service;
|
||||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||||
boost::asio::deadline_timer m_ShutdownTimer;
|
boost::asio::deadline_timer m_ShutdownTimer;
|
||||||
std::set<std::string> m_Tokens;
|
std::set<std::string> m_Tokens;
|
||||||
|
|
||||||
std::map<std::string, MethodHandler> m_MethodHandlers;
|
std::map<std::string, MethodHandler> m_MethodHandlers;
|
||||||
std::map<std::string, I2PControlRequestHandler> m_I2PControlHandlers;
|
std::map<std::string, I2PControlRequestHandler> m_I2PControlHandlers;
|
||||||
std::map<std::string, RouterInfoRequestHandler> m_RouterInfoHandlers;
|
std::map<std::string, RouterInfoRequestHandler> m_RouterInfoHandlers;
|
||||||
std::map<std::string, RouterManagerRequestHandler> m_RouterManagerHandlers;
|
std::map<std::string, RouterManagerRequestHandler> m_RouterManagerHandlers;
|
||||||
std::map<std::string, NetworkSettingRequestHandler> m_NetworkSettingHandlers;
|
std::map<std::string, NetworkSettingRequestHandler> m_NetworkSettingHandlers;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,38 +8,38 @@
|
||||||
#ifdef NEEDS_LOCAL_ENDIAN
|
#ifdef NEEDS_LOCAL_ENDIAN
|
||||||
uint16_t htobe16(uint16_t int16)
|
uint16_t htobe16(uint16_t int16)
|
||||||
{
|
{
|
||||||
BigEndian<uint16_t> u16(int16);
|
BigEndian<uint16_t> u16(int16);
|
||||||
return u16.raw_value;
|
return u16.raw_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t htobe32(uint32_t int32)
|
uint32_t htobe32(uint32_t int32)
|
||||||
{
|
{
|
||||||
BigEndian<uint32_t> u32(int32);
|
BigEndian<uint32_t> u32(int32);
|
||||||
return u32.raw_value;
|
return u32.raw_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t htobe64(uint64_t int64)
|
uint64_t htobe64(uint64_t int64)
|
||||||
{
|
{
|
||||||
BigEndian<uint64_t> u64(int64);
|
BigEndian<uint64_t> u64(int64);
|
||||||
return u64.raw_value;
|
return u64.raw_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t be16toh(uint16_t big16)
|
uint16_t be16toh(uint16_t big16)
|
||||||
{
|
{
|
||||||
LittleEndian<uint16_t> u16(big16);
|
LittleEndian<uint16_t> u16(big16);
|
||||||
return u16.raw_value;
|
return u16.raw_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t be32toh(uint32_t big32)
|
uint32_t be32toh(uint32_t big32)
|
||||||
{
|
{
|
||||||
LittleEndian<uint32_t> u32(big32);
|
LittleEndian<uint32_t> u32(big32);
|
||||||
return u32.raw_value;
|
return u32.raw_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t be64toh(uint64_t big64)
|
uint64_t be64toh(uint64_t big64)
|
||||||
{
|
{
|
||||||
LittleEndian<uint64_t> u64(big64);
|
LittleEndian<uint64_t> u64(big64);
|
||||||
return u64.raw_value;
|
return u64.raw_value;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -48,36 +48,36 @@ uint64_t be64toh(uint64_t big64)
|
||||||
|
|
||||||
uint16_t htobe16(uint16_t int16)
|
uint16_t htobe16(uint16_t int16)
|
||||||
{
|
{
|
||||||
return htons(int16);
|
return htons(int16);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t htobe32(uint32_t int32)
|
uint32_t htobe32(uint32_t int32)
|
||||||
{
|
{
|
||||||
return htonl(int32);
|
return htonl(int32);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t htobe64(uint64_t int64)
|
uint64_t htobe64(uint64_t int64)
|
||||||
{
|
{
|
||||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
||||||
//return htonll(int64);
|
//return htonll(int64);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint16_t be16toh(uint16_t big16)
|
uint16_t be16toh(uint16_t big16)
|
||||||
{
|
{
|
||||||
return ntohs(big16);
|
return ntohs(big16);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t be32toh(uint32_t big32)
|
uint32_t be32toh(uint32_t big32)
|
||||||
{
|
{
|
||||||
return ntohl(big32);
|
return ntohl(big32);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t be64toh(uint64_t big64)
|
uint64_t be64toh(uint64_t big64)
|
||||||
{
|
{
|
||||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
||||||
//return ntohll(big64);
|
//return ntohll(big64);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
36
I2PEndian.h
36
I2PEndian.h
|
@ -49,68 +49,68 @@ uint64_t be64toh(uint64_t big64);
|
||||||
|
|
||||||
inline uint16_t buf16toh(const void *buf)
|
inline uint16_t buf16toh(const void *buf)
|
||||||
{
|
{
|
||||||
uint16_t b16;
|
uint16_t b16;
|
||||||
memcpy(&b16, buf, sizeof(uint16_t));
|
memcpy(&b16, buf, sizeof(uint16_t));
|
||||||
return b16;
|
return b16;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t buf32toh(const void *buf)
|
inline uint32_t buf32toh(const void *buf)
|
||||||
{
|
{
|
||||||
uint32_t b32;
|
uint32_t b32;
|
||||||
memcpy(&b32, buf, sizeof(uint32_t));
|
memcpy(&b32, buf, sizeof(uint32_t));
|
||||||
return b32;
|
return b32;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t buf64toh(const void *buf)
|
inline uint64_t buf64toh(const void *buf)
|
||||||
{
|
{
|
||||||
uint64_t b64;
|
uint64_t b64;
|
||||||
memcpy(&b64, buf, sizeof(uint64_t));
|
memcpy(&b64, buf, sizeof(uint64_t));
|
||||||
return b64;
|
return b64;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint16_t bufbe16toh(const void *buf)
|
inline uint16_t bufbe16toh(const void *buf)
|
||||||
{
|
{
|
||||||
return be16toh(buf16toh(buf));
|
return be16toh(buf16toh(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t bufbe32toh(const void *buf)
|
inline uint32_t bufbe32toh(const void *buf)
|
||||||
{
|
{
|
||||||
return be32toh(buf32toh(buf));
|
return be32toh(buf32toh(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t bufbe64toh(const void *buf)
|
inline uint64_t bufbe64toh(const void *buf)
|
||||||
{
|
{
|
||||||
return be64toh(buf64toh(buf));
|
return be64toh(buf64toh(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void htobuf16(void *buf, uint16_t b16)
|
inline void htobuf16(void *buf, uint16_t b16)
|
||||||
{
|
{
|
||||||
memcpy(buf, &b16, sizeof(uint16_t));
|
memcpy(buf, &b16, sizeof(uint16_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void htobuf32(void *buf, uint32_t b32)
|
inline void htobuf32(void *buf, uint32_t b32)
|
||||||
{
|
{
|
||||||
memcpy(buf, &b32, sizeof(uint32_t));
|
memcpy(buf, &b32, sizeof(uint32_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void htobuf64(void *buf, uint64_t b64)
|
inline void htobuf64(void *buf, uint64_t b64)
|
||||||
{
|
{
|
||||||
memcpy(buf, &b64, sizeof(uint64_t));
|
memcpy(buf, &b64, sizeof(uint64_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void htobe16buf(void *buf, uint16_t big16)
|
inline void htobe16buf(void *buf, uint16_t big16)
|
||||||
{
|
{
|
||||||
htobuf16(buf, htobe16(big16));
|
htobuf16(buf, htobe16(big16));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void htobe32buf(void *buf, uint32_t big32)
|
inline void htobe32buf(void *buf, uint32_t big32)
|
||||||
{
|
{
|
||||||
htobuf32(buf, htobe32(big32));
|
htobuf32(buf, htobe32(big32));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void htobe64buf(void *buf, uint64_t big64)
|
inline void htobe64buf(void *buf, uint64_t big64)
|
||||||
{
|
{
|
||||||
htobuf64(buf, htobe64(big64));
|
htobuf64(buf, htobe64(big64));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
122
I2PService.cpp
122
I2PService.cpp
|
@ -8,72 +8,72 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
static const i2p::data::SigningKeyType I2P_SERVICE_DEFAULT_KEY_TYPE = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256;
|
static const i2p::data::SigningKeyType I2P_SERVICE_DEFAULT_KEY_TYPE = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256;
|
||||||
|
|
||||||
I2PService::I2PService (std::shared_ptr<ClientDestination> localDestination):
|
I2PService::I2PService (std::shared_ptr<ClientDestination> localDestination):
|
||||||
m_LocalDestination (localDestination ? localDestination :
|
m_LocalDestination (localDestination ? localDestination :
|
||||||
i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE))
|
i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PService::I2PService (i2p::data::SigningKeyType kt):
|
I2PService::I2PService (i2p::data::SigningKeyType kt):
|
||||||
m_LocalDestination (i2p::client::context.CreateNewLocalDestination (false, kt))
|
m_LocalDestination (i2p::client::context.CreateNewLocalDestination (false, kt))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) {
|
void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) {
|
||||||
assert(streamRequestComplete);
|
assert(streamRequestComplete);
|
||||||
i2p::data::IdentHash identHash;
|
i2p::data::IdentHash identHash;
|
||||||
if (i2p::client::context.GetAddressBook ().GetIdentHash (dest, identHash))
|
if (i2p::client::context.GetAddressBook ().GetIdentHash (dest, identHash))
|
||||||
m_LocalDestination->CreateStream (streamRequestComplete, identHash, port);
|
m_LocalDestination->CreateStream (streamRequestComplete, identHash, port);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Remote destination ", dest, " not found");
|
LogPrint (eLogWarning, "Remote destination ", dest, " not found");
|
||||||
streamRequestComplete (nullptr);
|
streamRequestComplete (nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPIPAcceptor::Start ()
|
void TCPIPAcceptor::Start ()
|
||||||
{
|
{
|
||||||
m_Acceptor.listen ();
|
m_Acceptor.listen ();
|
||||||
Accept ();
|
Accept ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPIPAcceptor::Stop ()
|
void TCPIPAcceptor::Stop ()
|
||||||
{
|
{
|
||||||
m_Acceptor.close();
|
m_Acceptor.close();
|
||||||
m_Timer.cancel ();
|
m_Timer.cancel ();
|
||||||
ClearHandlers();
|
ClearHandlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPIPAcceptor::Accept ()
|
void TCPIPAcceptor::Accept ()
|
||||||
{
|
{
|
||||||
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (GetService ());
|
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (GetService ());
|
||||||
m_Acceptor.async_accept (*newSocket, std::bind (&TCPIPAcceptor::HandleAccept, this,
|
m_Acceptor.async_accept (*newSocket, std::bind (&TCPIPAcceptor::HandleAccept, this,
|
||||||
std::placeholders::_1, newSocket));
|
std::placeholders::_1, newSocket));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPIPAcceptor::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
void TCPIPAcceptor::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||||
{
|
{
|
||||||
if (!ecode)
|
if (!ecode)
|
||||||
{
|
{
|
||||||
LogPrint(eLogDebug,"--- ",GetName()," accepted");
|
LogPrint(eLogDebug,"--- ",GetName()," accepted");
|
||||||
auto handler = CreateHandler(socket);
|
auto handler = CreateHandler(socket);
|
||||||
if (handler)
|
if (handler)
|
||||||
{
|
{
|
||||||
AddHandler(handler);
|
AddHandler(handler);
|
||||||
handler->Handle();
|
handler->Handle();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
socket->close();
|
socket->close();
|
||||||
Accept();
|
Accept();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
LogPrint (eLogError,"--- ",GetName()," Closing socket on accept because: ", ecode.message ());
|
LogPrint (eLogError,"--- ",GetName()," Closing socket on accept because: ", ecode.message ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
162
I2PService.h
162
I2PService.h
|
@ -13,96 +13,96 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
class I2PServiceHandler;
|
class I2PServiceHandler;
|
||||||
class I2PService
|
class I2PService
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
I2PService (std::shared_ptr<ClientDestination> localDestination = nullptr);
|
I2PService (std::shared_ptr<ClientDestination> localDestination = nullptr);
|
||||||
I2PService (i2p::data::SigningKeyType kt);
|
I2PService (i2p::data::SigningKeyType kt);
|
||||||
virtual ~I2PService () { ClearHandlers (); }
|
virtual ~I2PService () { ClearHandlers (); }
|
||||||
|
|
||||||
inline void AddHandler (std::shared_ptr<I2PServiceHandler> conn)
|
inline void AddHandler (std::shared_ptr<I2PServiceHandler> conn)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_HandlersMutex);
|
std::unique_lock<std::mutex> l(m_HandlersMutex);
|
||||||
m_Handlers.insert(conn);
|
m_Handlers.insert(conn);
|
||||||
}
|
}
|
||||||
inline void RemoveHandler (std::shared_ptr<I2PServiceHandler> conn)
|
inline void RemoveHandler (std::shared_ptr<I2PServiceHandler> conn)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_HandlersMutex);
|
std::unique_lock<std::mutex> l(m_HandlersMutex);
|
||||||
m_Handlers.erase(conn);
|
m_Handlers.erase(conn);
|
||||||
}
|
}
|
||||||
inline void ClearHandlers ()
|
inline void ClearHandlers ()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_HandlersMutex);
|
std::unique_lock<std::mutex> l(m_HandlersMutex);
|
||||||
m_Handlers.clear();
|
m_Handlers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<ClientDestination> GetLocalDestination () { return m_LocalDestination; }
|
inline std::shared_ptr<ClientDestination> GetLocalDestination () { return m_LocalDestination; }
|
||||||
inline void SetLocalDestination (std::shared_ptr<ClientDestination> dest) { m_LocalDestination = dest; }
|
inline void SetLocalDestination (std::shared_ptr<ClientDestination> dest) { m_LocalDestination = dest; }
|
||||||
void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port = 0);
|
void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port = 0);
|
||||||
|
|
||||||
inline boost::asio::io_service& GetService () { return m_LocalDestination->GetService (); }
|
inline boost::asio::io_service& GetService () { return m_LocalDestination->GetService (); }
|
||||||
|
|
||||||
virtual void Start () = 0;
|
virtual void Start () = 0;
|
||||||
virtual void Stop () = 0;
|
virtual void Stop () = 0;
|
||||||
|
|
||||||
virtual const char* GetName() { return "Generic I2P Service"; }
|
virtual const char* GetName() { return "Generic I2P Service"; }
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> m_LocalDestination;
|
std::shared_ptr<ClientDestination> m_LocalDestination;
|
||||||
std::unordered_set<std::shared_ptr<I2PServiceHandler> > m_Handlers;
|
std::unordered_set<std::shared_ptr<I2PServiceHandler> > m_Handlers;
|
||||||
std::mutex m_HandlersMutex;
|
std::mutex m_HandlersMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Simple interface for I2PHandlers, allows detection of finalization amongst other things */
|
/*Simple interface for I2PHandlers, allows detection of finalization amongst other things */
|
||||||
class I2PServiceHandler
|
class I2PServiceHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
I2PServiceHandler(I2PService * parent) : m_Service(parent), m_Dead(false) { }
|
I2PServiceHandler(I2PService * parent) : m_Service(parent), m_Dead(false) { }
|
||||||
virtual ~I2PServiceHandler() { }
|
virtual ~I2PServiceHandler() { }
|
||||||
//If you override this make sure you call it from the children
|
//If you override this make sure you call it from the children
|
||||||
virtual void Handle() {}; //Start handling the socket
|
virtual void Handle() {}; //Start handling the socket
|
||||||
protected:
|
protected:
|
||||||
// Call when terminating or handing over to avoid race conditions
|
// Call when terminating or handing over to avoid race conditions
|
||||||
inline bool Kill () { return m_Dead.exchange(true); }
|
inline bool Kill () { return m_Dead.exchange(true); }
|
||||||
// Call to know if the handler is dead
|
// Call to know if the handler is dead
|
||||||
inline bool Dead () { return m_Dead; }
|
inline bool Dead () { return m_Dead; }
|
||||||
// Call when done to clean up (make sure Kill is called first)
|
// Call when done to clean up (make sure Kill is called first)
|
||||||
inline void Done (std::shared_ptr<I2PServiceHandler> me) { if(m_Service) m_Service->RemoveHandler(me); }
|
inline void Done (std::shared_ptr<I2PServiceHandler> me) { if(m_Service) m_Service->RemoveHandler(me); }
|
||||||
// Call to talk with the owner
|
// Call to talk with the owner
|
||||||
inline I2PService * GetOwner() { return m_Service; }
|
inline I2PService * GetOwner() { return m_Service; }
|
||||||
private:
|
private:
|
||||||
I2PService *m_Service;
|
I2PService *m_Service;
|
||||||
std::atomic<bool> m_Dead; //To avoid cleaning up multiple times
|
std::atomic<bool> m_Dead; //To avoid cleaning up multiple times
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TODO: support IPv6 too */
|
/* TODO: support IPv6 too */
|
||||||
//This is a service that listens for connections on the IP network and interacts with I2P
|
//This is a service that listens for connections on the IP network and interacts with I2P
|
||||||
class TCPIPAcceptor: public I2PService
|
class TCPIPAcceptor: public I2PService
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TCPIPAcceptor (int port, std::shared_ptr<ClientDestination> localDestination = nullptr) :
|
TCPIPAcceptor (int port, std::shared_ptr<ClientDestination> localDestination = nullptr) :
|
||||||
I2PService(localDestination),
|
I2PService(localDestination),
|
||||||
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)),
|
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)),
|
||||||
m_Timer (GetService ()) {}
|
m_Timer (GetService ()) {}
|
||||||
TCPIPAcceptor (int port, i2p::data::SigningKeyType kt) :
|
TCPIPAcceptor (int port, i2p::data::SigningKeyType kt) :
|
||||||
I2PService(kt),
|
I2PService(kt),
|
||||||
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)),
|
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)),
|
||||||
m_Timer (GetService ()) {}
|
m_Timer (GetService ()) {}
|
||||||
virtual ~TCPIPAcceptor () { TCPIPAcceptor::Stop(); }
|
virtual ~TCPIPAcceptor () { TCPIPAcceptor::Stop(); }
|
||||||
//If you override this make sure you call it from the children
|
//If you override this make sure you call it from the children
|
||||||
void Start ();
|
void Start ();
|
||||||
//If you override this make sure you call it from the children
|
//If you override this make sure you call it from the children
|
||||||
void Stop ();
|
void Stop ();
|
||||||
protected:
|
protected:
|
||||||
virtual std::shared_ptr<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket) = 0;
|
virtual std::shared_ptr<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket) = 0;
|
||||||
virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; }
|
virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; }
|
||||||
private:
|
private:
|
||||||
void Accept();
|
void Accept();
|
||||||
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
||||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||||
boost::asio::deadline_timer m_Timer;
|
boost::asio::deadline_timer m_Timer;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
718
I2PTunnel.cpp
718
I2PTunnel.cpp
|
@ -9,394 +9,394 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port):
|
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port):
|
||||||
I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()),
|
I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()),
|
||||||
m_IsQuiet (true)
|
m_IsQuiet (true)
|
||||||
{
|
{
|
||||||
m_Stream = GetOwner()->GetLocalDestination ()->CreateStream (leaseSet, port);
|
m_Stream = GetOwner()->GetLocalDestination ()->CreateStream (leaseSet, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner,
|
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<i2p::stream::Stream> stream):
|
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<i2p::stream::Stream> stream):
|
||||||
I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream),
|
I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream),
|
||||||
m_RemoteEndpoint (socket->remote_endpoint ()), m_IsQuiet (true)
|
m_RemoteEndpoint (socket->remote_endpoint ()), m_IsQuiet (true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket, const boost::asio::ip::tcp::endpoint& target, bool quiet):
|
std::shared_ptr<boost::asio::ip::tcp::socket> socket, const boost::asio::ip::tcp::endpoint& target, bool quiet):
|
||||||
I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream),
|
I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream),
|
||||||
m_RemoteEndpoint (target), m_IsQuiet (quiet)
|
m_RemoteEndpoint (target), m_IsQuiet (quiet)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PTunnelConnection::~I2PTunnelConnection ()
|
I2PTunnelConnection::~I2PTunnelConnection ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PTunnelConnection::I2PConnect (const uint8_t * msg, size_t len)
|
void I2PTunnelConnection::I2PConnect (const uint8_t * msg, size_t len)
|
||||||
{
|
{
|
||||||
if (m_Stream)
|
if (m_Stream)
|
||||||
{
|
{
|
||||||
if (msg)
|
if (msg)
|
||||||
m_Stream->Send (msg, len); // connect and send
|
m_Stream->Send (msg, len); // connect and send
|
||||||
else
|
else
|
||||||
m_Stream->Send (m_Buffer, 0); // connect
|
m_Stream->Send (m_Buffer, 0); // connect
|
||||||
}
|
}
|
||||||
StreamReceive ();
|
StreamReceive ();
|
||||||
Receive ();
|
Receive ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PTunnelConnection::Connect ()
|
void I2PTunnelConnection::Connect ()
|
||||||
{
|
{
|
||||||
if (m_Socket)
|
if (m_Socket)
|
||||||
m_Socket->async_connect (m_RemoteEndpoint, std::bind (&I2PTunnelConnection::HandleConnect,
|
m_Socket->async_connect (m_RemoteEndpoint, std::bind (&I2PTunnelConnection::HandleConnect,
|
||||||
shared_from_this (), std::placeholders::_1));
|
shared_from_this (), std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PTunnelConnection::Terminate ()
|
void I2PTunnelConnection::Terminate ()
|
||||||
{
|
{
|
||||||
if (Kill()) return;
|
if (Kill()) return;
|
||||||
if (m_Stream)
|
if (m_Stream)
|
||||||
{
|
{
|
||||||
m_Stream->Close ();
|
m_Stream->Close ();
|
||||||
m_Stream.reset ();
|
m_Stream.reset ();
|
||||||
}
|
}
|
||||||
m_Socket->close ();
|
m_Socket->close ();
|
||||||
Done(shared_from_this ());
|
Done(shared_from_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),
|
||||||
std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (),
|
std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (),
|
||||||
std::placeholders::_1, std::placeholders::_2));
|
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)
|
||||||
{
|
{
|
||||||
if (ecode)
|
if (ecode)
|
||||||
{
|
{
|
||||||
LogPrint ("I2PTunnel read error: ", ecode.message ());
|
LogPrint ("I2PTunnel read error: ", ecode.message ());
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
Terminate ();
|
Terminate ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_Stream)
|
if (m_Stream)
|
||||||
{
|
{
|
||||||
auto s = shared_from_this ();
|
auto s = shared_from_this ();
|
||||||
m_Stream->AsyncSend (m_Buffer, bytes_transferred,
|
m_Stream->AsyncSend (m_Buffer, bytes_transferred,
|
||||||
[s](const boost::system::error_code& ecode)
|
[s](const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
if (!ecode)
|
if (!ecode)
|
||||||
s->Receive ();
|
s->Receive ();
|
||||||
else
|
else
|
||||||
s->Terminate ();
|
s->Terminate ();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PTunnelConnection::HandleWrite (const boost::system::error_code& ecode)
|
void I2PTunnelConnection::HandleWrite (const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
if (ecode)
|
if (ecode)
|
||||||
{
|
{
|
||||||
LogPrint ("I2PTunnel write error: ", ecode.message ());
|
LogPrint ("I2PTunnel write error: ", ecode.message ());
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
Terminate ();
|
Terminate ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
StreamReceive ();
|
StreamReceive ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PTunnelConnection::StreamReceive ()
|
void I2PTunnelConnection::StreamReceive ()
|
||||||
{
|
{
|
||||||
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),
|
||||||
std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (),
|
std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (),
|
||||||
std::placeholders::_1, std::placeholders::_2),
|
std::placeholders::_1, std::placeholders::_2),
|
||||||
I2P_TUNNEL_CONNECTION_MAX_IDLE);
|
I2P_TUNNEL_CONNECTION_MAX_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PTunnelConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
void I2PTunnelConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
{
|
{
|
||||||
if (ecode)
|
if (ecode)
|
||||||
{
|
{
|
||||||
LogPrint ("I2PTunnel stream read error: ", ecode.message ());
|
LogPrint ("I2PTunnel stream read error: ", ecode.message ());
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
Terminate ();
|
Terminate ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Write (m_StreamBuffer, bytes_transferred);
|
Write (m_StreamBuffer, bytes_transferred);
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PTunnelConnection::Write (const uint8_t * buf, size_t len)
|
void I2PTunnelConnection::Write (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
m_Socket->async_send (boost::asio::buffer (buf, len),
|
m_Socket->async_send (boost::asio::buffer (buf, len),
|
||||||
std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
|
std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PTunnelConnection::HandleConnect (const boost::system::error_code& ecode)
|
void I2PTunnelConnection::HandleConnect (const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
if (ecode)
|
if (ecode)
|
||||||
{
|
{
|
||||||
LogPrint ("I2PTunnel connect error: ", ecode.message ());
|
LogPrint ("I2PTunnel connect error: ", ecode.message ());
|
||||||
Terminate ();
|
Terminate ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint ("I2PTunnel connected");
|
LogPrint ("I2PTunnel connected");
|
||||||
if (m_IsQuiet)
|
if (m_IsQuiet)
|
||||||
StreamReceive ();
|
StreamReceive ();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// send destination first like received from I2P
|
// send destination first like received from I2P
|
||||||
std::string dest = m_Stream->GetRemoteIdentity ().ToBase64 ();
|
std::string dest = m_Stream->GetRemoteIdentity ().ToBase64 ();
|
||||||
dest += "\n";
|
dest += "\n";
|
||||||
memcpy (m_StreamBuffer, dest.c_str (), dest.size ());
|
memcpy (m_StreamBuffer, dest.c_str (), dest.size ());
|
||||||
HandleStreamReceive (boost::system::error_code (), dest.size ());
|
HandleStreamReceive (boost::system::error_code (), dest.size ());
|
||||||
}
|
}
|
||||||
Receive ();
|
Receive ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PTunnelConnectionHTTP::I2PTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
I2PTunnelConnectionHTTP::I2PTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||||
const boost::asio::ip::tcp::endpoint& target, const std::string& host):
|
const boost::asio::ip::tcp::endpoint& target, const std::string& host):
|
||||||
I2PTunnelConnection (owner, stream, socket, target), m_Host (host), m_HeaderSent (false)
|
I2PTunnelConnection (owner, stream, socket, target), m_Host (host), m_HeaderSent (false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len)
|
void I2PTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
if (m_HeaderSent)
|
if (m_HeaderSent)
|
||||||
I2PTunnelConnection::Write (buf, len);
|
I2PTunnelConnection::Write (buf, len);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_InHeader.clear ();
|
m_InHeader.clear ();
|
||||||
m_InHeader.write ((const char *)buf, len);
|
m_InHeader.write ((const char *)buf, len);
|
||||||
std::string line;
|
std::string line;
|
||||||
bool endOfHeader = false;
|
bool endOfHeader = false;
|
||||||
while (!endOfHeader)
|
while (!endOfHeader)
|
||||||
{
|
{
|
||||||
std::getline(m_InHeader, line);
|
std::getline(m_InHeader, line);
|
||||||
if (!m_InHeader.fail ())
|
if (!m_InHeader.fail ())
|
||||||
{
|
{
|
||||||
if (line.find ("Host:") != std::string::npos)
|
if (line.find ("Host:") != std::string::npos)
|
||||||
m_OutHeader << "Host: " << m_Host << "\r\n";
|
m_OutHeader << "Host: " << m_Host << "\r\n";
|
||||||
else
|
else
|
||||||
m_OutHeader << line << "\n";
|
m_OutHeader << line << "\n";
|
||||||
if (line == "\r") endOfHeader = true;
|
if (line == "\r") endOfHeader = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endOfHeader)
|
if (endOfHeader)
|
||||||
{
|
{
|
||||||
m_OutHeader << m_InHeader.str (); // data right after header
|
m_OutHeader << m_InHeader.str (); // data right after header
|
||||||
m_HeaderSent = true;
|
m_HeaderSent = true;
|
||||||
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
|
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This handler tries to stablish a connection with the desired server and dies if it fails to do so */
|
/* This handler tries to stablish a connection with the desired server and dies if it fails to do so */
|
||||||
class I2PClientTunnelHandler: public I2PServiceHandler, public std::enable_shared_from_this<I2PClientTunnelHandler>
|
class I2PClientTunnelHandler: public I2PServiceHandler, public std::enable_shared_from_this<I2PClientTunnelHandler>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
I2PClientTunnelHandler (I2PClientTunnel * parent, i2p::data::IdentHash destination,
|
I2PClientTunnelHandler (I2PClientTunnel * parent, i2p::data::IdentHash destination,
|
||||||
int destinationPort, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
int destinationPort, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
||||||
I2PServiceHandler(parent), m_DestinationIdentHash(destination),
|
I2PServiceHandler(parent), m_DestinationIdentHash(destination),
|
||||||
m_DestinationPort (destinationPort), m_Socket(socket) {};
|
m_DestinationPort (destinationPort), m_Socket(socket) {};
|
||||||
void Handle();
|
void Handle();
|
||||||
void Terminate();
|
void Terminate();
|
||||||
private:
|
private:
|
||||||
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
|
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
|
||||||
i2p::data::IdentHash m_DestinationIdentHash;
|
i2p::data::IdentHash m_DestinationIdentHash;
|
||||||
int m_DestinationPort;
|
int m_DestinationPort;
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
||||||
};
|
};
|
||||||
|
|
||||||
void I2PClientTunnelHandler::Handle()
|
void I2PClientTunnelHandler::Handle()
|
||||||
{
|
{
|
||||||
GetOwner()->GetLocalDestination ()->CreateStream (
|
GetOwner()->GetLocalDestination ()->CreateStream (
|
||||||
std::bind (&I2PClientTunnelHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1),
|
std::bind (&I2PClientTunnelHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1),
|
||||||
m_DestinationIdentHash, m_DestinationPort);
|
m_DestinationIdentHash, m_DestinationPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PClientTunnelHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
|
void I2PClientTunnelHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
|
||||||
{
|
{
|
||||||
if (stream)
|
if (stream)
|
||||||
{
|
{
|
||||||
if (Kill()) return;
|
if (Kill()) return;
|
||||||
LogPrint (eLogInfo,"New I2PTunnel connection");
|
LogPrint (eLogInfo,"New I2PTunnel connection");
|
||||||
auto connection = std::make_shared<I2PTunnelConnection>(GetOwner(), m_Socket, stream);
|
auto connection = std::make_shared<I2PTunnelConnection>(GetOwner(), m_Socket, stream);
|
||||||
GetOwner()->AddHandler (connection);
|
GetOwner()->AddHandler (connection);
|
||||||
connection->I2PConnect ();
|
connection->I2PConnect ();
|
||||||
Done(shared_from_this());
|
Done(shared_from_this());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogError,"I2P Client Tunnel Issue when creating the stream, check the previous warnings for more info.");
|
LogPrint (eLogError,"I2P Client Tunnel Issue when creating the stream, check the previous warnings for more info.");
|
||||||
Terminate();
|
Terminate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PClientTunnelHandler::Terminate()
|
void I2PClientTunnelHandler::Terminate()
|
||||||
{
|
{
|
||||||
if (Kill()) return;
|
if (Kill()) return;
|
||||||
if (m_Socket)
|
if (m_Socket)
|
||||||
{
|
{
|
||||||
m_Socket->close();
|
m_Socket->close();
|
||||||
m_Socket = nullptr;
|
m_Socket = nullptr;
|
||||||
}
|
}
|
||||||
Done(shared_from_this());
|
Done(shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PClientTunnel::I2PClientTunnel (const std::string& destination, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort):
|
I2PClientTunnel::I2PClientTunnel (const std::string& destination, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort):
|
||||||
TCPIPAcceptor (port,localDestination), m_Destination (destination), m_DestinationIdentHash (nullptr), m_DestinationPort (destinationPort)
|
TCPIPAcceptor (port,localDestination), m_Destination (destination), m_DestinationIdentHash (nullptr), m_DestinationPort (destinationPort)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void I2PClientTunnel::Start ()
|
void I2PClientTunnel::Start ()
|
||||||
{
|
{
|
||||||
TCPIPAcceptor::Start ();
|
TCPIPAcceptor::Start ();
|
||||||
GetIdentHash();
|
GetIdentHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PClientTunnel::Stop ()
|
void I2PClientTunnel::Stop ()
|
||||||
{
|
{
|
||||||
TCPIPAcceptor::Stop();
|
TCPIPAcceptor::Stop();
|
||||||
auto *originalIdentHash = m_DestinationIdentHash;
|
auto *originalIdentHash = m_DestinationIdentHash;
|
||||||
m_DestinationIdentHash = nullptr;
|
m_DestinationIdentHash = nullptr;
|
||||||
delete originalIdentHash;
|
delete originalIdentHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HACK: maybe we should create a caching IdentHash provider in AddressBook */
|
/* HACK: maybe we should create a caching IdentHash provider in AddressBook */
|
||||||
const i2p::data::IdentHash * I2PClientTunnel::GetIdentHash ()
|
const i2p::data::IdentHash * I2PClientTunnel::GetIdentHash ()
|
||||||
{
|
{
|
||||||
if (!m_DestinationIdentHash)
|
if (!m_DestinationIdentHash)
|
||||||
{
|
{
|
||||||
i2p::data::IdentHash identHash;
|
i2p::data::IdentHash identHash;
|
||||||
if (i2p::client::context.GetAddressBook ().GetIdentHash (m_Destination, identHash))
|
if (i2p::client::context.GetAddressBook ().GetIdentHash (m_Destination, identHash))
|
||||||
m_DestinationIdentHash = new i2p::data::IdentHash (identHash);
|
m_DestinationIdentHash = new i2p::data::IdentHash (identHash);
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning,"Remote destination ", m_Destination, " not found");
|
LogPrint (eLogWarning,"Remote destination ", m_Destination, " not found");
|
||||||
}
|
}
|
||||||
return m_DestinationIdentHash;
|
return m_DestinationIdentHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<I2PServiceHandler> I2PClientTunnel::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
std::shared_ptr<I2PServiceHandler> I2PClientTunnel::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||||
{
|
{
|
||||||
const i2p::data::IdentHash *identHash = GetIdentHash();
|
const i2p::data::IdentHash *identHash = GetIdentHash();
|
||||||
if (identHash)
|
if (identHash)
|
||||||
return std::make_shared<I2PClientTunnelHandler>(this, *identHash, m_DestinationPort, socket);
|
return std::make_shared<I2PClientTunnelHandler>(this, *identHash, m_DestinationPort, socket);
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PServerTunnel::I2PServerTunnel (const std::string& address, int port,
|
I2PServerTunnel::I2PServerTunnel (const std::string& address, int port,
|
||||||
std::shared_ptr<ClientDestination> localDestination, int inport):
|
std::shared_ptr<ClientDestination> localDestination, int inport):
|
||||||
I2PService (localDestination), m_Address (address), m_Port (port), m_IsAccessList (false)
|
I2PService (localDestination), m_Address (address), m_Port (port), m_IsAccessList (false)
|
||||||
{
|
{
|
||||||
m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port);
|
m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PServerTunnel::Start ()
|
void I2PServerTunnel::Start ()
|
||||||
{
|
{
|
||||||
m_Endpoint.port (m_Port);
|
m_Endpoint.port (m_Port);
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
auto addr = boost::asio::ip::address::from_string (m_Address, ec);
|
auto addr = boost::asio::ip::address::from_string (m_Address, ec);
|
||||||
if (!ec)
|
if (!ec)
|
||||||
{
|
{
|
||||||
m_Endpoint.address (addr);
|
m_Endpoint.address (addr);
|
||||||
Accept ();
|
Accept ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(GetService ());
|
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(GetService ());
|
||||||
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (m_Address, ""),
|
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (m_Address, ""),
|
||||||
std::bind (&I2PServerTunnel::HandleResolve, this,
|
std::bind (&I2PServerTunnel::HandleResolve, this,
|
||||||
std::placeholders::_1, std::placeholders::_2, resolver));
|
std::placeholders::_1, std::placeholders::_2, resolver));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PServerTunnel::Stop ()
|
void I2PServerTunnel::Stop ()
|
||||||
{
|
{
|
||||||
ClearHandlers ();
|
ClearHandlers ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PServerTunnel::HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
void I2PServerTunnel::HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
|
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
|
||||||
{
|
{
|
||||||
if (!ecode)
|
if (!ecode)
|
||||||
{
|
{
|
||||||
auto addr = (*it).endpoint ().address ();
|
auto addr = (*it).endpoint ().address ();
|
||||||
LogPrint (eLogInfo, "server tunnel ", (*it).host_name (), " has been resolved to ", addr);
|
LogPrint (eLogInfo, "server tunnel ", (*it).host_name (), " has been resolved to ", addr);
|
||||||
m_Endpoint.address (addr);
|
m_Endpoint.address (addr);
|
||||||
Accept ();
|
Accept ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "Unable to resolve server tunnel address: ", ecode.message ());
|
LogPrint (eLogError, "Unable to resolve server tunnel address: ", ecode.message ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PServerTunnel::SetAccessList (const std::set<i2p::data::IdentHash>& accessList)
|
void I2PServerTunnel::SetAccessList (const std::set<i2p::data::IdentHash>& accessList)
|
||||||
{
|
{
|
||||||
m_AccessList = accessList;
|
m_AccessList = accessList;
|
||||||
m_IsAccessList = true;
|
m_IsAccessList = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PServerTunnel::Accept ()
|
void I2PServerTunnel::Accept ()
|
||||||
{
|
{
|
||||||
if (m_PortDestination)
|
if (m_PortDestination)
|
||||||
m_PortDestination->SetAcceptor (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
|
m_PortDestination->SetAcceptor (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
|
||||||
|
|
||||||
auto localDestination = GetLocalDestination ();
|
auto localDestination = GetLocalDestination ();
|
||||||
if (localDestination)
|
if (localDestination)
|
||||||
{
|
{
|
||||||
if (!localDestination->IsAcceptingStreams ()) // set it as default if not set yet
|
if (!localDestination->IsAcceptingStreams ()) // set it as default if not set yet
|
||||||
localDestination->AcceptStreams (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
|
localDestination->AcceptStreams (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint ("Local destination not set for server tunnel");
|
LogPrint ("Local destination not set for server tunnel");
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PServerTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
|
void I2PServerTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
|
||||||
{
|
{
|
||||||
if (stream)
|
if (stream)
|
||||||
{
|
{
|
||||||
if (m_IsAccessList)
|
if (m_IsAccessList)
|
||||||
{
|
{
|
||||||
if (!m_AccessList.count (stream->GetRemoteIdentity ().GetIdentHash ()))
|
if (!m_AccessList.count (stream->GetRemoteIdentity ().GetIdentHash ()))
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Address ", stream->GetRemoteIdentity ().GetIdentHash ().ToBase32 (), " is not in white list. Incoming connection dropped");
|
LogPrint (eLogWarning, "Address ", stream->GetRemoteIdentity ().GetIdentHash ().ToBase32 (), " is not in white list. Incoming connection dropped");
|
||||||
stream->Close ();
|
stream->Close ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CreateI2PConnection (stream);
|
CreateI2PConnection (stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PServerTunnel::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
void I2PServerTunnel::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
||||||
{
|
{
|
||||||
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint ());
|
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint ());
|
||||||
AddHandler (conn);
|
AddHandler (conn);
|
||||||
conn->Connect ();
|
conn->Connect ();
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int inport):
|
I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int inport):
|
||||||
I2PServerTunnel (address, port, localDestination, inport)
|
I2PServerTunnel (address, port, localDestination, inport)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
void I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
||||||
{
|
{
|
||||||
auto conn = std::make_shared<I2PTunnelConnectionHTTP> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), GetAddress ());
|
auto conn = std::make_shared<I2PTunnelConnectionHTTP> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), GetAddress ());
|
||||||
AddHandler (conn);
|
AddHandler (conn);
|
||||||
conn->Connect ();
|
conn->Connect ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
198
I2PTunnel.h
198
I2PTunnel.h
|
@ -16,138 +16,138 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
const size_t I2P_TUNNEL_CONNECTION_BUFFER_SIZE = 8192;
|
const size_t I2P_TUNNEL_CONNECTION_BUFFER_SIZE = 8192;
|
||||||
const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds
|
const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds
|
||||||
const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
|
const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
|
||||||
|
|
||||||
|
|
||||||
class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this<I2PTunnelConnection>
|
class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this<I2PTunnelConnection>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port = 0); // to I2P
|
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port = 0); // to I2P
|
||||||
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||||
std::shared_ptr<i2p::stream::Stream> stream); // to I2P using simplified API
|
std::shared_ptr<i2p::stream::Stream> stream); // to I2P using simplified API
|
||||||
I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||||
const boost::asio::ip::tcp::endpoint& target, bool quiet = true); // from I2P
|
const boost::asio::ip::tcp::endpoint& target, bool quiet = true); // from I2P
|
||||||
~I2PTunnelConnection ();
|
~I2PTunnelConnection ();
|
||||||
void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0);
|
void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0);
|
||||||
void Connect ();
|
void Connect ();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
|
|
||||||
void Receive ();
|
void Receive ();
|
||||||
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
virtual void Write (const uint8_t * buf, size_t len); // can be overloaded
|
virtual void Write (const uint8_t * buf, size_t len); // can be overloaded
|
||||||
void HandleWrite (const boost::system::error_code& ecode);
|
void HandleWrite (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
void StreamReceive ();
|
void StreamReceive ();
|
||||||
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandleConnect (const boost::system::error_code& ecode);
|
void HandleConnect (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
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];
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
||||||
std::shared_ptr<i2p::stream::Stream> m_Stream;
|
std::shared_ptr<i2p::stream::Stream> m_Stream;
|
||||||
boost::asio::ip::tcp::endpoint m_RemoteEndpoint;
|
boost::asio::ip::tcp::endpoint m_RemoteEndpoint;
|
||||||
bool m_IsQuiet; // don't send destination
|
bool m_IsQuiet; // don't send destination
|
||||||
};
|
};
|
||||||
|
|
||||||
class I2PTunnelConnectionHTTP: public I2PTunnelConnection
|
class I2PTunnelConnectionHTTP: public I2PTunnelConnection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
I2PTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
I2PTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||||
const boost::asio::ip::tcp::endpoint& target, const std::string& host);
|
const boost::asio::ip::tcp::endpoint& target, const std::string& host);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void Write (const uint8_t * buf, size_t len);
|
void Write (const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::string m_Host;
|
std::string m_Host;
|
||||||
std::stringstream m_InHeader, m_OutHeader;
|
std::stringstream m_InHeader, m_OutHeader;
|
||||||
bool m_HeaderSent;
|
bool m_HeaderSent;
|
||||||
};
|
};
|
||||||
|
|
||||||
class I2PClientTunnel: public TCPIPAcceptor
|
class I2PClientTunnel: public TCPIPAcceptor
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// Implements TCPIPAcceptor
|
// Implements TCPIPAcceptor
|
||||||
std::shared_ptr<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
std::shared_ptr<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
||||||
const char* GetName() { return "I2P Client Tunnel"; }
|
const char* GetName() { return "I2P Client Tunnel"; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
I2PClientTunnel (const std::string& destination, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort = 0);
|
I2PClientTunnel (const std::string& destination, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort = 0);
|
||||||
~I2PClientTunnel () {}
|
~I2PClientTunnel () {}
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const i2p::data::IdentHash * GetIdentHash ();
|
const i2p::data::IdentHash * GetIdentHash ();
|
||||||
|
|
||||||
std::string m_Destination;
|
std::string m_Destination;
|
||||||
const i2p::data::IdentHash * m_DestinationIdentHash;
|
const i2p::data::IdentHash * m_DestinationIdentHash;
|
||||||
int m_DestinationPort;
|
int m_DestinationPort;
|
||||||
};
|
};
|
||||||
|
|
||||||
class I2PServerTunnel: public I2PService
|
class I2PServerTunnel: public I2PService
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
I2PServerTunnel (const std::string& address, int port,
|
I2PServerTunnel (const std::string& address, int port,
|
||||||
std::shared_ptr<ClientDestination> localDestination, int inport = 0);
|
std::shared_ptr<ClientDestination> localDestination, int inport = 0);
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
void SetAccessList (const std::set<i2p::data::IdentHash>& accessList);
|
void SetAccessList (const std::set<i2p::data::IdentHash>& accessList);
|
||||||
|
|
||||||
const std::string& GetAddress() const { return m_Address; }
|
const std::string& GetAddress() const { return m_Address; }
|
||||||
int GetPort () const { return m_Port; };
|
int GetPort () const { return m_Port; };
|
||||||
const boost::asio::ip::tcp::endpoint& GetEndpoint () const { return m_Endpoint; }
|
const boost::asio::ip::tcp::endpoint& GetEndpoint () const { return m_Endpoint; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
|
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
|
||||||
|
|
||||||
void Accept ();
|
void Accept ();
|
||||||
void HandleAccept (std::shared_ptr<i2p::stream::Stream> stream);
|
void HandleAccept (std::shared_ptr<i2p::stream::Stream> stream);
|
||||||
virtual void CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
|
virtual void CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::string m_Address;
|
std::string m_Address;
|
||||||
int m_Port;
|
int m_Port;
|
||||||
boost::asio::ip::tcp::endpoint m_Endpoint;
|
boost::asio::ip::tcp::endpoint m_Endpoint;
|
||||||
std::shared_ptr<i2p::stream::StreamingDestination> m_PortDestination;
|
std::shared_ptr<i2p::stream::StreamingDestination> m_PortDestination;
|
||||||
std::set<i2p::data::IdentHash> m_AccessList;
|
std::set<i2p::data::IdentHash> m_AccessList;
|
||||||
bool m_IsAccessList;
|
bool m_IsAccessList;
|
||||||
};
|
};
|
||||||
|
|
||||||
class I2PServerTunnelHTTP: public I2PServerTunnel
|
class I2PServerTunnelHTTP: public I2PServerTunnel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
I2PServerTunnelHTTP (const std::string& address, int port,
|
I2PServerTunnelHTTP (const std::string& address, int port,
|
||||||
std::shared_ptr<ClientDestination> localDestination, int inport = 0);
|
std::shared_ptr<ClientDestination> localDestination, int inport = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
|
void CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
1052
Identity.cpp
1052
Identity.cpp
File diff suppressed because it is too large
Load diff
436
Identity.h
436
Identity.h
|
@ -13,261 +13,261 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
template<int sz>
|
template<int sz>
|
||||||
class Tag
|
class Tag
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); };
|
Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); };
|
||||||
Tag (const Tag<sz>& ) = default;
|
Tag (const Tag<sz>& ) = default;
|
||||||
#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it
|
#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it
|
||||||
Tag (Tag<sz>&& ) = default;
|
Tag (Tag<sz>&& ) = default;
|
||||||
#endif
|
#endif
|
||||||
Tag () = default;
|
Tag () = default;
|
||||||
|
|
||||||
Tag<sz>& operator= (const Tag<sz>& ) = default;
|
Tag<sz>& operator= (const Tag<sz>& ) = default;
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
Tag<sz>& operator= (Tag<sz>&& ) = default;
|
Tag<sz>& operator= (Tag<sz>&& ) = default;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t * operator()() { return m_Buf; };
|
uint8_t * operator()() { return m_Buf; };
|
||||||
const uint8_t * operator()() const { return m_Buf; };
|
const uint8_t * operator()() const { return m_Buf; };
|
||||||
|
|
||||||
operator uint8_t * () { return m_Buf; };
|
operator uint8_t * () { return m_Buf; };
|
||||||
operator const uint8_t * () const { return m_Buf; };
|
operator const uint8_t * () const { return m_Buf; };
|
||||||
|
|
||||||
const uint64_t * GetLL () const { return ll; };
|
const uint64_t * GetLL () const { return ll; };
|
||||||
|
|
||||||
bool operator== (const Tag<sz>& other) const { return !memcmp (m_Buf, other.m_Buf, sz); };
|
bool operator== (const Tag<sz>& other) const { return !memcmp (m_Buf, other.m_Buf, sz); };
|
||||||
bool operator< (const Tag<sz>& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; };
|
bool operator< (const Tag<sz>& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; };
|
||||||
|
|
||||||
bool IsZero () const
|
bool IsZero () const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < sz/8; i++)
|
for (int i = 0; i < sz/8; i++)
|
||||||
if (ll[i]) return false;
|
if (ll[i]) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ToBase64 () const
|
std::string ToBase64 () const
|
||||||
{
|
{
|
||||||
char str[sz*2];
|
char str[sz*2];
|
||||||
int l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2);
|
int l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2);
|
||||||
str[l] = 0;
|
str[l] = 0;
|
||||||
return std::string (str);
|
return std::string (str);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ToBase32 () const
|
std::string ToBase32 () const
|
||||||
{
|
{
|
||||||
char str[sz*2];
|
char str[sz*2];
|
||||||
int l = i2p::data::ByteStreamToBase32 (m_Buf, sz, str, sz*2);
|
int l = i2p::data::ByteStreamToBase32 (m_Buf, sz, str, sz*2);
|
||||||
str[l] = 0;
|
str[l] = 0;
|
||||||
return std::string (str);
|
return std::string (str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FromBase32 (const std::string& s)
|
void FromBase32 (const std::string& s)
|
||||||
{
|
{
|
||||||
i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FromBase64 (const std::string& s)
|
void FromBase64 (const std::string& s)
|
||||||
{
|
{
|
||||||
i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
union // 8 bytes alignment
|
union // 8 bytes alignment
|
||||||
{
|
{
|
||||||
uint8_t m_Buf[sz];
|
uint8_t m_Buf[sz];
|
||||||
uint64_t ll[sz/8];
|
uint64_t ll[sz/8];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
typedef Tag<32> IdentHash;
|
typedef Tag<32> IdentHash;
|
||||||
|
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
struct Keys
|
struct Keys
|
||||||
{
|
{
|
||||||
uint8_t privateKey[256];
|
uint8_t privateKey[256];
|
||||||
uint8_t signingPrivateKey[20];
|
uint8_t signingPrivateKey[20];
|
||||||
uint8_t publicKey[256];
|
uint8_t publicKey[256];
|
||||||
uint8_t signingKey[128];
|
uint8_t signingKey[128];
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8_t CERTIFICATE_TYPE_NULL = 0;
|
const uint8_t CERTIFICATE_TYPE_NULL = 0;
|
||||||
const uint8_t CERTIFICATE_TYPE_HASHCASH = 1;
|
const uint8_t CERTIFICATE_TYPE_HASHCASH = 1;
|
||||||
const uint8_t CERTIFICATE_TYPE_HIDDEN = 2;
|
const uint8_t CERTIFICATE_TYPE_HIDDEN = 2;
|
||||||
const uint8_t CERTIFICATE_TYPE_SIGNED = 3;
|
const uint8_t CERTIFICATE_TYPE_SIGNED = 3;
|
||||||
const uint8_t CERTIFICATE_TYPE_MULTIPLE = 4;
|
const uint8_t CERTIFICATE_TYPE_MULTIPLE = 4;
|
||||||
const uint8_t CERTIFICATE_TYPE_KEY = 5;
|
const uint8_t CERTIFICATE_TYPE_KEY = 5;
|
||||||
|
|
||||||
struct Identity
|
struct Identity
|
||||||
{
|
{
|
||||||
uint8_t publicKey[256];
|
uint8_t publicKey[256];
|
||||||
uint8_t signingKey[128];
|
uint8_t signingKey[128];
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
} certificate;
|
} certificate;
|
||||||
|
|
||||||
Identity () = default;
|
Identity () = default;
|
||||||
Identity (const Keys& keys) { *this = keys; };
|
Identity (const Keys& keys) { *this = keys; };
|
||||||
Identity& operator=(const Keys& keys);
|
Identity& operator=(const Keys& keys);
|
||||||
size_t FromBuffer (const uint8_t * buf, size_t len);
|
size_t FromBuffer (const uint8_t * buf, size_t len);
|
||||||
IdentHash Hash () const;
|
IdentHash Hash () const;
|
||||||
};
|
};
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
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_SHA384_P384 = 2;
|
||||||
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA512_P521 = 3;
|
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA512_P521 = 3;
|
||||||
const uint16_t SIGNING_KEY_TYPE_RSA_SHA256_2048 = 4;
|
const uint16_t SIGNING_KEY_TYPE_RSA_SHA256_2048 = 4;
|
||||||
const uint16_t SIGNING_KEY_TYPE_RSA_SHA384_3072 = 5;
|
const uint16_t SIGNING_KEY_TYPE_RSA_SHA384_3072 = 5;
|
||||||
const uint16_t SIGNING_KEY_TYPE_RSA_SHA512_4096 = 6;
|
const uint16_t SIGNING_KEY_TYPE_RSA_SHA512_4096 = 6;
|
||||||
const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 = 7;
|
const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 = 7;
|
||||||
typedef uint16_t SigningKeyType;
|
typedef uint16_t SigningKeyType;
|
||||||
typedef uint16_t CryptoKeyType;
|
typedef uint16_t CryptoKeyType;
|
||||||
|
|
||||||
class IdentityEx
|
class IdentityEx
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
IdentityEx ();
|
IdentityEx ();
|
||||||
IdentityEx (const uint8_t * publicKey, const uint8_t * signingKey,
|
IdentityEx (const uint8_t * publicKey, const uint8_t * signingKey,
|
||||||
SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1);
|
SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1);
|
||||||
IdentityEx (const uint8_t * buf, size_t len);
|
IdentityEx (const uint8_t * buf, size_t len);
|
||||||
IdentityEx (const IdentityEx& other);
|
IdentityEx (const IdentityEx& other);
|
||||||
~IdentityEx ();
|
~IdentityEx ();
|
||||||
IdentityEx& operator=(const IdentityEx& other);
|
IdentityEx& operator=(const IdentityEx& other);
|
||||||
IdentityEx& operator=(const Identity& standard);
|
IdentityEx& operator=(const Identity& standard);
|
||||||
|
|
||||||
size_t FromBuffer (const uint8_t * buf, size_t len);
|
size_t FromBuffer (const uint8_t * buf, size_t len);
|
||||||
size_t ToBuffer (uint8_t * buf, size_t len) const;
|
size_t ToBuffer (uint8_t * buf, size_t len) const;
|
||||||
size_t FromBase64(const std::string& s);
|
size_t FromBase64(const std::string& s);
|
||||||
std::string ToBase64 () const;
|
std::string ToBase64 () const;
|
||||||
const Identity& GetStandardIdentity () const { return m_StandardIdentity; };
|
const Identity& GetStandardIdentity () const { return m_StandardIdentity; };
|
||||||
const IdentHash& GetIdentHash () const { return m_IdentHash; };
|
const IdentHash& GetIdentHash () const { return m_IdentHash; };
|
||||||
size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; };
|
size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; };
|
||||||
size_t GetSigningPublicKeyLen () const;
|
size_t GetSigningPublicKeyLen () const;
|
||||||
size_t GetSigningPrivateKeyLen () const;
|
size_t GetSigningPrivateKeyLen () const;
|
||||||
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;
|
CryptoKeyType GetCryptoKeyType () const;
|
||||||
void DropVerifier (); // to save memory
|
void DropVerifier (); // to save memory
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateVerifier () const;
|
void CreateVerifier () const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Identity m_StandardIdentity;
|
Identity m_StandardIdentity;
|
||||||
IdentHash m_IdentHash;
|
IdentHash m_IdentHash;
|
||||||
mutable i2p::crypto::Verifier * m_Verifier;
|
mutable i2p::crypto::Verifier * m_Verifier;
|
||||||
size_t m_ExtendedLen;
|
size_t m_ExtendedLen;
|
||||||
uint8_t * m_ExtendedBuffer;
|
uint8_t * m_ExtendedBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PrivateKeys // for eepsites
|
class PrivateKeys // for eepsites
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PrivateKeys (): m_Signer (nullptr) {};
|
PrivateKeys (): m_Signer (nullptr) {};
|
||||||
PrivateKeys (const PrivateKeys& other): m_Signer (nullptr) { *this = other; };
|
PrivateKeys (const PrivateKeys& other): m_Signer (nullptr) { *this = other; };
|
||||||
PrivateKeys (const Keys& keys): m_Signer (nullptr) { *this = keys; };
|
PrivateKeys (const Keys& keys): m_Signer (nullptr) { *this = keys; };
|
||||||
PrivateKeys& operator=(const Keys& keys);
|
PrivateKeys& operator=(const Keys& keys);
|
||||||
PrivateKeys& operator=(const PrivateKeys& other);
|
PrivateKeys& operator=(const PrivateKeys& other);
|
||||||
~PrivateKeys () { delete m_Signer; };
|
~PrivateKeys () { delete m_Signer; };
|
||||||
|
|
||||||
const IdentityEx& GetPublic () const { return m_Public; };
|
const IdentityEx& GetPublic () const { return m_Public; };
|
||||||
const uint8_t * GetPrivateKey () const { return m_PrivateKey; };
|
const uint8_t * GetPrivateKey () const { return m_PrivateKey; };
|
||||||
const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; };
|
const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; };
|
||||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
|
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
|
||||||
|
|
||||||
size_t GetFullLen () const { return m_Public.GetFullLen () + 256 + m_Public.GetSigningPrivateKeyLen (); };
|
size_t GetFullLen () const { return m_Public.GetFullLen () + 256 + m_Public.GetSigningPrivateKeyLen (); };
|
||||||
size_t FromBuffer (const uint8_t * buf, size_t len);
|
size_t FromBuffer (const uint8_t * buf, size_t len);
|
||||||
size_t ToBuffer (uint8_t * buf, size_t len) const;
|
size_t ToBuffer (uint8_t * buf, size_t len) const;
|
||||||
|
|
||||||
size_t FromBase64(const std::string& s);
|
size_t FromBase64(const std::string& s);
|
||||||
std::string ToBase64 () const;
|
std::string ToBase64 () const;
|
||||||
|
|
||||||
static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1);
|
static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateSigner ();
|
void CreateSigner ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
IdentityEx m_Public;
|
IdentityEx m_Public;
|
||||||
uint8_t m_PrivateKey[256];
|
uint8_t m_PrivateKey[256];
|
||||||
uint8_t m_SigningPrivateKey[1024]; // assume private key doesn't exceed 1024 bytes
|
uint8_t m_SigningPrivateKey[1024]; // assume private key doesn't exceed 1024 bytes
|
||||||
i2p::crypto::Signer * m_Signer;
|
i2p::crypto::Signer * m_Signer;
|
||||||
};
|
};
|
||||||
|
|
||||||
// kademlia
|
// kademlia
|
||||||
struct XORMetric
|
struct XORMetric
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
uint8_t metric[32];
|
uint8_t metric[32];
|
||||||
uint64_t metric_ll[4];
|
uint64_t metric_ll[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetMin () { memset (metric, 0, 32); };
|
void SetMin () { memset (metric, 0, 32); };
|
||||||
void SetMax () { memset (metric, 0xFF, 32); };
|
void SetMax () { memset (metric, 0xFF, 32); };
|
||||||
bool operator< (const XORMetric& other) const { return memcmp (metric, other.metric, 32) < 0; };
|
bool operator< (const XORMetric& other) const { return memcmp (metric, other.metric, 32) < 0; };
|
||||||
};
|
};
|
||||||
|
|
||||||
IdentHash CreateRoutingKey (const IdentHash& ident);
|
IdentHash CreateRoutingKey (const IdentHash& ident);
|
||||||
XORMetric operator^(const IdentHash& key1, const IdentHash& key2);
|
XORMetric operator^(const IdentHash& key1, const IdentHash& key2);
|
||||||
|
|
||||||
// destination for delivery instuctions
|
// destination for delivery instuctions
|
||||||
class RoutingDestination
|
class RoutingDestination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RoutingDestination () {};
|
RoutingDestination () {};
|
||||||
virtual ~RoutingDestination () {};
|
virtual ~RoutingDestination () {};
|
||||||
|
|
||||||
virtual const IdentHash& GetIdentHash () const = 0;
|
virtual const IdentHash& GetIdentHash () const = 0;
|
||||||
virtual const uint8_t * GetEncryptionPublicKey () const = 0;
|
virtual const uint8_t * GetEncryptionPublicKey () const = 0;
|
||||||
virtual bool IsDestination () const = 0; // for garlic
|
virtual bool IsDestination () const = 0; // for garlic
|
||||||
|
|
||||||
std::unique_ptr<const i2p::crypto::ElGamalEncryption>& GetElGamalEncryption () const
|
std::unique_ptr<const i2p::crypto::ElGamalEncryption>& GetElGamalEncryption () const
|
||||||
{
|
{
|
||||||
if (!m_ElGamalEncryption)
|
if (!m_ElGamalEncryption)
|
||||||
m_ElGamalEncryption.reset (new i2p::crypto::ElGamalEncryption (GetEncryptionPublicKey ()));
|
m_ElGamalEncryption.reset (new i2p::crypto::ElGamalEncryption (GetEncryptionPublicKey ()));
|
||||||
return m_ElGamalEncryption;
|
return m_ElGamalEncryption;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
mutable std::unique_ptr<const i2p::crypto::ElGamalEncryption> m_ElGamalEncryption; // use lazy initialization
|
mutable std::unique_ptr<const i2p::crypto::ElGamalEncryption> m_ElGamalEncryption; // use lazy initialization
|
||||||
};
|
};
|
||||||
|
|
||||||
class LocalDestination
|
class LocalDestination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~LocalDestination() {};
|
virtual ~LocalDestination() {};
|
||||||
virtual const PrivateKeys& GetPrivateKeys () const = 0;
|
virtual const PrivateKeys& GetPrivateKeys () const = 0;
|
||||||
virtual const uint8_t * GetEncryptionPrivateKey () const = 0;
|
virtual const uint8_t * GetEncryptionPrivateKey () const = 0;
|
||||||
virtual const uint8_t * GetEncryptionPublicKey () const = 0;
|
virtual const uint8_t * GetEncryptionPublicKey () const = 0;
|
||||||
|
|
||||||
const IdentityEx& GetIdentity () const { return GetPrivateKeys ().GetPublic (); };
|
const IdentityEx& GetIdentity () const { return GetPrivateKeys ().GetPublic (); };
|
||||||
const IdentHash& GetIdentHash () const { return GetIdentity ().GetIdentHash (); };
|
const IdentHash& GetIdentHash () const { return GetIdentity ().GetIdentHash (); };
|
||||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
void Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||||
{
|
{
|
||||||
GetPrivateKeys ().Sign (buf, len, signature);
|
GetPrivateKeys ().Sign (buf, len, signature);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
270
LeaseSet.cpp
270
LeaseSet.cpp
|
@ -13,145 +13,145 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
|
|
||||||
LeaseSet::LeaseSet (const uint8_t * buf, size_t len):
|
LeaseSet::LeaseSet (const uint8_t * buf, size_t len):
|
||||||
m_IsValid (true)
|
m_IsValid (true)
|
||||||
{
|
{
|
||||||
m_Buffer = new uint8_t[len];
|
m_Buffer = new uint8_t[len];
|
||||||
memcpy (m_Buffer, buf, len);
|
memcpy (m_Buffer, buf, len);
|
||||||
m_BufferLen = len;
|
m_BufferLen = len;
|
||||||
ReadFromBuffer ();
|
ReadFromBuffer ();
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaseSet::LeaseSet (const i2p::tunnel::TunnelPool& pool):
|
LeaseSet::LeaseSet (const i2p::tunnel::TunnelPool& pool):
|
||||||
m_IsValid (true)
|
m_IsValid (true)
|
||||||
{
|
{
|
||||||
// header
|
// header
|
||||||
const i2p::data::LocalDestination * localDestination = pool.GetLocalDestination ();
|
const i2p::data::LocalDestination * localDestination = pool.GetLocalDestination ();
|
||||||
if (!localDestination)
|
if (!localDestination)
|
||||||
{
|
{
|
||||||
m_Buffer = nullptr;
|
m_Buffer = nullptr;
|
||||||
m_BufferLen = 0;
|
m_BufferLen = 0;
|
||||||
m_IsValid = false;
|
m_IsValid = false;
|
||||||
LogPrint (eLogError, "Destination for local LeaseSet doesn't exist");
|
LogPrint (eLogError, "Destination for local LeaseSet doesn't exist");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_Buffer = new uint8_t[MAX_LS_BUFFER_SIZE];
|
m_Buffer = new uint8_t[MAX_LS_BUFFER_SIZE];
|
||||||
m_BufferLen = localDestination->GetIdentity ().ToBuffer (m_Buffer, MAX_LS_BUFFER_SIZE);
|
m_BufferLen = localDestination->GetIdentity ().ToBuffer (m_Buffer, MAX_LS_BUFFER_SIZE);
|
||||||
memcpy (m_Buffer + m_BufferLen, localDestination->GetEncryptionPublicKey (), 256);
|
memcpy (m_Buffer + m_BufferLen, localDestination->GetEncryptionPublicKey (), 256);
|
||||||
m_BufferLen += 256;
|
m_BufferLen += 256;
|
||||||
auto signingKeyLen = localDestination->GetIdentity ().GetSigningPublicKeyLen ();
|
auto signingKeyLen = localDestination->GetIdentity ().GetSigningPublicKeyLen ();
|
||||||
memset (m_Buffer + m_BufferLen, 0, signingKeyLen);
|
memset (m_Buffer + m_BufferLen, 0, signingKeyLen);
|
||||||
m_BufferLen += signingKeyLen;
|
m_BufferLen += signingKeyLen;
|
||||||
auto tunnels = pool.GetInboundTunnels (5); // 5 tunnels maximum
|
auto tunnels = pool.GetInboundTunnels (5); // 5 tunnels maximum
|
||||||
m_Buffer[m_BufferLen] = tunnels.size (); // num leases
|
m_Buffer[m_BufferLen] = tunnels.size (); // num leases
|
||||||
m_BufferLen++;
|
m_BufferLen++;
|
||||||
// leases
|
// leases
|
||||||
CryptoPP::AutoSeededRandomPool rnd;
|
CryptoPP::AutoSeededRandomPool rnd;
|
||||||
for (auto it: tunnels)
|
for (auto it: tunnels)
|
||||||
{
|
{
|
||||||
memcpy (m_Buffer + m_BufferLen, it->GetNextIdentHash (), 32);
|
memcpy (m_Buffer + m_BufferLen, it->GetNextIdentHash (), 32);
|
||||||
m_BufferLen += 32; // gateway id
|
m_BufferLen += 32; // gateway id
|
||||||
htobe32buf (m_Buffer + m_BufferLen, it->GetNextTunnelID ());
|
htobe32buf (m_Buffer + m_BufferLen, it->GetNextTunnelID ());
|
||||||
m_BufferLen += 4; // tunnel id
|
m_BufferLen += 4; // tunnel id
|
||||||
uint64_t ts = it->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration
|
uint64_t ts = it->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration
|
||||||
ts *= 1000; // in milliseconds
|
ts *= 1000; // in milliseconds
|
||||||
ts += rnd.GenerateWord32 (0, 5); // + random milliseconds
|
ts += rnd.GenerateWord32 (0, 5); // + random milliseconds
|
||||||
htobe64buf (m_Buffer + m_BufferLen, ts);
|
htobe64buf (m_Buffer + m_BufferLen, ts);
|
||||||
m_BufferLen += 8; // end date
|
m_BufferLen += 8; // end date
|
||||||
}
|
}
|
||||||
// signature
|
// signature
|
||||||
localDestination->Sign (m_Buffer, m_BufferLen, m_Buffer + m_BufferLen);
|
localDestination->Sign (m_Buffer, m_BufferLen, m_Buffer + m_BufferLen);
|
||||||
m_BufferLen += localDestination->GetIdentity ().GetSignatureLen ();
|
m_BufferLen += localDestination->GetIdentity ().GetSignatureLen ();
|
||||||
LogPrint ("Local LeaseSet of ", tunnels.size (), " leases created");
|
LogPrint ("Local LeaseSet of ", tunnels.size (), " leases created");
|
||||||
|
|
||||||
ReadFromBuffer ();
|
ReadFromBuffer ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSet::Update (const uint8_t * buf, size_t len)
|
void LeaseSet::Update (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
m_Leases.clear ();
|
m_Leases.clear ();
|
||||||
if (len > m_BufferLen)
|
if (len > m_BufferLen)
|
||||||
{
|
{
|
||||||
auto oldBuffer = m_Buffer;
|
auto oldBuffer = m_Buffer;
|
||||||
m_Buffer = new uint8_t[len];
|
m_Buffer = new uint8_t[len];
|
||||||
delete[] oldBuffer;
|
delete[] oldBuffer;
|
||||||
}
|
}
|
||||||
memcpy (m_Buffer, buf, len);
|
memcpy (m_Buffer, buf, len);
|
||||||
m_BufferLen = len;
|
m_BufferLen = len;
|
||||||
ReadFromBuffer ();
|
ReadFromBuffer ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSet::ReadFromBuffer ()
|
void LeaseSet::ReadFromBuffer ()
|
||||||
{
|
{
|
||||||
size_t size = m_Identity.FromBuffer (m_Buffer, m_BufferLen);
|
size_t size = m_Identity.FromBuffer (m_Buffer, m_BufferLen);
|
||||||
memcpy (m_EncryptionKey, m_Buffer + size, 256);
|
memcpy (m_EncryptionKey, m_Buffer + size, 256);
|
||||||
size += 256; // encryption key
|
size += 256; // encryption key
|
||||||
size += m_Identity.GetSigningPublicKeyLen (); // unused signing key
|
size += m_Identity.GetSigningPublicKeyLen (); // unused signing key
|
||||||
uint8_t num = m_Buffer[size];
|
uint8_t num = m_Buffer[size];
|
||||||
size++; // num
|
size++; // num
|
||||||
LogPrint ("LeaseSet num=", (int)num);
|
LogPrint ("LeaseSet num=", (int)num);
|
||||||
if (!num) m_IsValid = false;
|
if (!num) m_IsValid = false;
|
||||||
|
|
||||||
// process leases
|
// process leases
|
||||||
const uint8_t * leases = m_Buffer + size;
|
const uint8_t * leases = m_Buffer + size;
|
||||||
for (int i = 0; i < num; i++)
|
for (int i = 0; i < num; i++)
|
||||||
{
|
{
|
||||||
Lease lease;
|
Lease lease;
|
||||||
lease.tunnelGateway = leases;
|
lease.tunnelGateway = leases;
|
||||||
leases += 32; // gateway
|
leases += 32; // gateway
|
||||||
lease.tunnelID = bufbe32toh (leases);
|
lease.tunnelID = bufbe32toh (leases);
|
||||||
leases += 4; // tunnel ID
|
leases += 4; // tunnel ID
|
||||||
lease.endDate = bufbe64toh (leases);
|
lease.endDate = bufbe64toh (leases);
|
||||||
leases += 8; // end date
|
leases += 8; // end date
|
||||||
m_Leases.push_back (lease);
|
m_Leases.push_back (lease);
|
||||||
|
|
||||||
// check if lease's gateway is in our netDb
|
// check if lease's gateway is in our netDb
|
||||||
if (!netdb.FindRouter (lease.tunnelGateway))
|
if (!netdb.FindRouter (lease.tunnelGateway))
|
||||||
{
|
{
|
||||||
// if not found request it
|
// if not found request it
|
||||||
LogPrint (eLogInfo, "Lease's tunnel gateway not found. Requested");
|
LogPrint (eLogInfo, "Lease's tunnel gateway not found. Requested");
|
||||||
netdb.RequestDestination (lease.tunnelGateway);
|
netdb.RequestDestination (lease.tunnelGateway);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
if (!m_Identity.Verify (m_Buffer, leases - m_Buffer, leases))
|
if (!m_Identity.Verify (m_Buffer, leases - m_Buffer, leases))
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "LeaseSet verification failed");
|
LogPrint (eLogWarning, "LeaseSet verification failed");
|
||||||
m_IsValid = false;
|
m_IsValid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<Lease> LeaseSet::GetNonExpiredLeases (bool withThreshold) const
|
const std::vector<Lease> LeaseSet::GetNonExpiredLeases (bool withThreshold) const
|
||||||
{
|
{
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
std::vector<Lease> leases;
|
std::vector<Lease> leases;
|
||||||
for (auto& it: m_Leases)
|
for (auto& it: m_Leases)
|
||||||
{
|
{
|
||||||
auto endDate = it.endDate;
|
auto endDate = it.endDate;
|
||||||
if (!withThreshold)
|
if (!withThreshold)
|
||||||
endDate -= i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD*1000;
|
endDate -= i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD*1000;
|
||||||
if (ts < endDate)
|
if (ts < endDate)
|
||||||
leases.push_back (it);
|
leases.push_back (it);
|
||||||
}
|
}
|
||||||
return leases;
|
return leases;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LeaseSet::HasExpiredLeases () const
|
bool LeaseSet::HasExpiredLeases () const
|
||||||
{
|
{
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
for (auto& it: m_Leases)
|
for (auto& it: m_Leases)
|
||||||
if (ts >= it.endDate) return true;
|
if (ts >= it.endDate) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LeaseSet::HasNonExpiredLeases () const
|
bool LeaseSet::HasNonExpiredLeases () const
|
||||||
{
|
{
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
for (auto& it: m_Leases)
|
for (auto& it: m_Leases)
|
||||||
if (ts < it.endDate) return true;
|
if (ts < it.endDate) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
96
LeaseSet.h
96
LeaseSet.h
|
@ -11,64 +11,64 @@ namespace i2p
|
||||||
|
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
class TunnelPool;
|
class TunnelPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
struct Lease
|
struct Lease
|
||||||
{
|
{
|
||||||
IdentHash tunnelGateway;
|
IdentHash tunnelGateway;
|
||||||
uint32_t tunnelID;
|
uint32_t tunnelID;
|
||||||
uint64_t endDate;
|
uint64_t endDate;
|
||||||
|
|
||||||
bool operator< (const Lease& other) const
|
bool operator< (const Lease& other) const
|
||||||
{
|
{
|
||||||
if (endDate != other.endDate)
|
if (endDate != other.endDate)
|
||||||
return endDate > other.endDate;
|
return endDate > other.endDate;
|
||||||
else
|
else
|
||||||
return tunnelID < other.tunnelID;
|
return tunnelID < other.tunnelID;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const int MAX_LS_BUFFER_SIZE = 3072;
|
const int MAX_LS_BUFFER_SIZE = 3072;
|
||||||
class LeaseSet: public RoutingDestination
|
class LeaseSet: public RoutingDestination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LeaseSet (const uint8_t * buf, size_t len);
|
LeaseSet (const uint8_t * buf, size_t len);
|
||||||
LeaseSet (const i2p::tunnel::TunnelPool& pool);
|
LeaseSet (const i2p::tunnel::TunnelPool& pool);
|
||||||
~LeaseSet () { delete[] m_Buffer; };
|
~LeaseSet () { delete[] m_Buffer; };
|
||||||
void Update (const uint8_t * buf, size_t len);
|
void Update (const uint8_t * buf, size_t len);
|
||||||
const IdentityEx& GetIdentity () const { return m_Identity; };
|
const IdentityEx& GetIdentity () const { return m_Identity; };
|
||||||
|
|
||||||
const uint8_t * GetBuffer () const { return m_Buffer; };
|
const uint8_t * GetBuffer () const { return m_Buffer; };
|
||||||
size_t GetBufferLen () const { return m_BufferLen; };
|
size_t GetBufferLen () const { return m_BufferLen; };
|
||||||
bool IsValid () const { return m_IsValid; };
|
bool IsValid () const { return m_IsValid; };
|
||||||
|
|
||||||
// implements RoutingDestination
|
// implements RoutingDestination
|
||||||
const IdentHash& GetIdentHash () const { return m_Identity.GetIdentHash (); };
|
const IdentHash& GetIdentHash () const { return m_Identity.GetIdentHash (); };
|
||||||
const std::vector<Lease>& GetLeases () const { return m_Leases; };
|
const std::vector<Lease>& GetLeases () const { return m_Leases; };
|
||||||
const std::vector<Lease> GetNonExpiredLeases (bool withThreshold = true) const;
|
const std::vector<Lease> GetNonExpiredLeases (bool withThreshold = true) const;
|
||||||
bool HasExpiredLeases () const;
|
bool HasExpiredLeases () const;
|
||||||
bool HasNonExpiredLeases () const;
|
bool HasNonExpiredLeases () const;
|
||||||
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; };
|
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; };
|
||||||
bool IsDestination () const { return true; };
|
bool IsDestination () const { return true; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void ReadFromBuffer ();
|
void ReadFromBuffer ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_IsValid;
|
bool m_IsValid;
|
||||||
std::vector<Lease> m_Leases;
|
std::vector<Lease> m_Leases;
|
||||||
IdentityEx m_Identity;
|
IdentityEx m_Identity;
|
||||||
uint8_t m_EncryptionKey[256];
|
uint8_t m_EncryptionKey[256];
|
||||||
uint8_t * m_Buffer;
|
uint8_t * m_Buffer;
|
||||||
size_t m_BufferLen;
|
size_t m_BufferLen;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -59,12 +59,12 @@ struct LittleEndian
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
const T operator = (const T t)
|
const T operator = (const T t)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < sizeof(T); i++)
|
for (unsigned i = 0; i < sizeof(T); i++)
|
||||||
bytes[sizeof(T)-1 - i] = static_cast<unsigned char>(t >> (i << 3));
|
bytes[sizeof(T)-1 - i] = static_cast<unsigned char>(t >> (i << 3));
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
// operators
|
// operators
|
||||||
|
|
||||||
|
|
4
Log.cpp
4
Log.cpp
|
@ -43,8 +43,8 @@ const std::string& Log::GetTimestamp ()
|
||||||
|
|
||||||
void Log::Flush ()
|
void Log::Flush ()
|
||||||
{
|
{
|
||||||
if (m_LogStream)
|
if (m_LogStream)
|
||||||
m_LogStream->flush();
|
m_LogStream->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::SetLogFile (const std::string& fullFilePath)
|
void Log::SetLogFile (const std::string& fullFilePath)
|
||||||
|
|
16
Log.h
16
Log.h
|
@ -32,19 +32,19 @@ struct LogMsg
|
||||||
|
|
||||||
class Log: public i2p::util::MsgQueue<LogMsg>
|
class Log: public i2p::util::MsgQueue<LogMsg>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Log (): m_LogStream (nullptr) { SetOnEmpty (std::bind (&Log::Flush, this)); };
|
Log (): m_LogStream (nullptr) { SetOnEmpty (std::bind (&Log::Flush, this)); };
|
||||||
~Log () { delete m_LogStream; };
|
~Log () { delete m_LogStream; };
|
||||||
|
|
||||||
void SetLogFile (const std::string& fullFilePath);
|
void SetLogFile (const std::string& fullFilePath);
|
||||||
void SetLogStream (std::ostream * logStream);
|
void SetLogStream (std::ostream * logStream);
|
||||||
std::ostream * GetLogStream () const { return m_LogStream; };
|
std::ostream * GetLogStream () const { return m_LogStream; };
|
||||||
const std::string& GetTimestamp ();
|
const std::string& GetTimestamp ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Flush ();
|
void Flush ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -99,14 +99,14 @@ inline void StopLog ()
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
void LogPrint (std::stringstream& s, TValue arg)
|
void LogPrint (std::stringstream& s, TValue arg)
|
||||||
{
|
{
|
||||||
s << arg;
|
s << arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TValue, typename... TArgs>
|
template<typename TValue, typename... TArgs>
|
||||||
void LogPrint (std::stringstream& s, TValue arg, TArgs... args)
|
void LogPrint (std::stringstream& s, TValue arg, TArgs... args)
|
||||||
{
|
{
|
||||||
LogPrint (s, arg);
|
LogPrint (s, arg);
|
||||||
LogPrint (s, args...);
|
LogPrint (s, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... TArgs>
|
template<typename... TArgs>
|
||||||
|
|
12
Makefile
12
Makefile
|
@ -1,6 +1,7 @@
|
||||||
UNAME := $(shell uname -s)
|
UNAME := $(shell uname -s)
|
||||||
SHLIB := libi2pd.so
|
SHLIB := libi2pd.so
|
||||||
I2PD := i2p
|
I2PD := i2p
|
||||||
|
TESTS := tests/tests
|
||||||
GREP := fgrep
|
GREP := fgrep
|
||||||
DEPS := obj/make.dep
|
DEPS := obj/make.dep
|
||||||
|
|
||||||
|
@ -22,10 +23,11 @@ else # win32
|
||||||
DAEMON_SRC += DaemonWin32.cpp
|
DAEMON_SRC += DaemonWin32.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: mk_build_dir $(SHLIB) $(I2PD)
|
all: mk_build_dir $(SHLIB) $(I2PD) $(TESTS)
|
||||||
|
|
||||||
mk_build_dir:
|
mk_build_dir:
|
||||||
mkdir -p obj
|
mkdir -p obj
|
||||||
|
mkdir -p obj/tests
|
||||||
|
|
||||||
api: $(SHLIB)
|
api: $(SHLIB)
|
||||||
|
|
||||||
|
@ -38,11 +40,13 @@ api: $(SHLIB)
|
||||||
|
|
||||||
deps:
|
deps:
|
||||||
@mkdir -p obj
|
@mkdir -p obj
|
||||||
|
@mkdir -p obj/tests
|
||||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS)
|
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS)
|
||||||
@sed -i -e '/\.o:/ s/^/obj\//' $(DEPS)
|
@sed -i -e '/\.o:/ s/^/obj\//' $(DEPS)
|
||||||
|
|
||||||
obj/%.o : %.cpp
|
obj/%.o : %.cpp
|
||||||
@mkdir -p obj
|
@mkdir -p obj
|
||||||
|
@mkdir -p obj/tests
|
||||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $<
|
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $<
|
||||||
|
|
||||||
# '-' is 'ignore if missing' on first run
|
# '-' is 'ignore if missing' on first run
|
||||||
|
@ -56,9 +60,13 @@ ifneq ($(USE_STATIC),yes)
|
||||||
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
|
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
$(TESTS): $(patsubst %.cpp,obj/%.o,$(TESTS_SRC))
|
||||||
|
$(CXX) -o $@ $^ $(LDLIBS) $(LDTESTLIBS) $(LDFLAGS)
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf obj
|
rm -rf obj
|
||||||
$(RM) $(I2PD) $(SHLIB)
|
$(RM) $(I2PD) $(SHLIB) $(TESTS)
|
||||||
|
|
||||||
LATEST_TAG=$(shell git describe --tags --abbrev=0 master)
|
LATEST_TAG=$(shell git describe --tags --abbrev=0 master)
|
||||||
dist:
|
dist:
|
||||||
|
|
|
@ -10,3 +10,4 @@ NEEDED_CXXFLAGS = -std=c++11
|
||||||
INCFLAGS = -I/usr/include/ -I/usr/local/include/
|
INCFLAGS = -I/usr/include/ -I/usr/local/include/
|
||||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||||
LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
||||||
|
LDTESTLIBS = -lboost_unit_test_framework
|
||||||
|
|
|
@ -40,6 +40,9 @@ else
|
||||||
LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Always link with test framework dynamically
|
||||||
|
LDTESTLIBS = -lboost_unit_test_framework
|
||||||
|
|
||||||
# UPNP Support (miniupnpc 1.5 or 1.6)
|
# UPNP Support (miniupnpc 1.5 or 1.6)
|
||||||
ifeq ($(USE_UPNP),1)
|
ifeq ($(USE_UPNP),1)
|
||||||
LDFLAGS += -ldl
|
LDFLAGS += -ldl
|
||||||
|
|
|
@ -4,6 +4,7 @@ CXXFLAGS = -g -Wall -std=c++11 -DCRYPTOPP_DISABLE_ASM -DMAC_OSX
|
||||||
INCFLAGS = -I/usr/local/include
|
INCFLAGS = -I/usr/local/include
|
||||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||||
LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
||||||
|
LDTESTLIBS = -lboost_unit_test_framework
|
||||||
|
|
||||||
ifeq ($(USE_UPNP),1)
|
ifeq ($(USE_UPNP),1)
|
||||||
LDFLAGS += -ldl
|
LDFLAGS += -ldl
|
||||||
|
|
1752
NTCPSession.cpp
1752
NTCPSession.cpp
File diff suppressed because it is too large
Load diff
274
NTCPSession.h
274
NTCPSession.h
|
@ -21,163 +21,163 @@ namespace transport
|
||||||
{
|
{
|
||||||
|
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
struct NTCPPhase1
|
struct NTCPPhase1
|
||||||
{
|
{
|
||||||
uint8_t pubKey[256];
|
uint8_t pubKey[256];
|
||||||
uint8_t HXxorHI[32];
|
uint8_t HXxorHI[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NTCPPhase2
|
struct NTCPPhase2
|
||||||
{
|
{
|
||||||
uint8_t pubKey[256];
|
uint8_t pubKey[256];
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
uint8_t hxy[32];
|
uint8_t hxy[32];
|
||||||
uint32_t timestamp;
|
uint32_t timestamp;
|
||||||
uint8_t filler[12];
|
uint8_t filler[12];
|
||||||
} encrypted;
|
} encrypted;
|
||||||
};
|
};
|
||||||
|
|
||||||
#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 = 4160; // fits 4 tunnel messages (4*1028)
|
const size_t NTCP_BUFFER_SIZE = 4160; // fits 4 tunnel messages (4*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*/; // 448
|
const size_t NTCP_DEFAULT_PHASE3_SIZE = 2/*size*/ + i2p::data::DEFAULT_IDENTITY_SIZE/*387*/ + 4/*ts*/ + 15/*padding*/ + 40/*signature*/; // 448
|
||||||
const int NTCP_BAN_EXPIRATION_TIMEOUT = 70; // in second
|
const int NTCP_BAN_EXPIRATION_TIMEOUT = 70; // in second
|
||||||
|
|
||||||
class NTCPServer;
|
class NTCPServer;
|
||||||
class NTCPSession: public TransportSession, public std::enable_shared_from_this<NTCPSession>
|
class NTCPSession: public TransportSession, public std::enable_shared_from_this<NTCPSession>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NTCPSession (NTCPServer& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr);
|
NTCPSession (NTCPServer& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr);
|
||||||
~NTCPSession ();
|
~NTCPSession ();
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
void Done ();
|
void Done ();
|
||||||
|
|
||||||
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
||||||
bool IsEstablished () const { return m_IsEstablished; };
|
bool IsEstablished () const { return m_IsEstablished; };
|
||||||
|
|
||||||
void ClientLogin ();
|
void ClientLogin ();
|
||||||
void ServerLogin ();
|
void ServerLogin ();
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
||||||
void Connected ();
|
void Connected ();
|
||||||
void SendTimeSyncMessage ();
|
void SendTimeSyncMessage ();
|
||||||
void SetIsEstablished (bool isEstablished) { m_IsEstablished = isEstablished; }
|
void SetIsEstablished (bool isEstablished) { m_IsEstablished = isEstablished; }
|
||||||
|
|
||||||
void CreateAESKey (uint8_t * pubKey, i2p::crypto::AESKey& key);
|
void CreateAESKey (uint8_t * pubKey, i2p::crypto::AESKey& key);
|
||||||
|
|
||||||
// client
|
// client
|
||||||
void SendPhase3 ();
|
void SendPhase3 ();
|
||||||
void HandlePhase1Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandlePhase1Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandlePhase2Received (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandlePhase2Received (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandlePhase3Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA);
|
void HandlePhase3Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA);
|
||||||
void HandlePhase4Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA);
|
void HandlePhase4Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA);
|
||||||
|
|
||||||
//server
|
//server
|
||||||
void SendPhase2 ();
|
void SendPhase2 ();
|
||||||
void SendPhase4 (uint32_t tsA, 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 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 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
|
||||||
void Receive ();
|
void Receive ();
|
||||||
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
bool DecryptNextBlock (const uint8_t * encrypted);
|
bool DecryptNextBlock (const uint8_t * encrypted);
|
||||||
|
|
||||||
void Send (std::shared_ptr<i2p::I2NPMessage> msg);
|
void Send (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||||
boost::asio::const_buffers_1 CreateMsgBuffer (std::shared_ptr<I2NPMessage> msg);
|
boost::asio::const_buffers_1 CreateMsgBuffer (std::shared_ptr<I2NPMessage> msg);
|
||||||
void Send (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
void Send (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
||||||
void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
||||||
|
|
||||||
|
|
||||||
// timer
|
// timer
|
||||||
void ScheduleTermination ();
|
void ScheduleTermination ();
|
||||||
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
NTCPServer& m_Server;
|
NTCPServer& m_Server;
|
||||||
boost::asio::ip::tcp::socket m_Socket;
|
boost::asio::ip::tcp::socket m_Socket;
|
||||||
boost::asio::deadline_timer m_TerminationTimer;
|
boost::asio::deadline_timer m_TerminationTimer;
|
||||||
bool m_IsEstablished, m_IsTerminated;
|
bool m_IsEstablished, m_IsTerminated;
|
||||||
|
|
||||||
i2p::crypto::CBCDecryption m_Decryption;
|
i2p::crypto::CBCDecryption m_Decryption;
|
||||||
i2p::crypto::CBCEncryption m_Encryption;
|
i2p::crypto::CBCEncryption m_Encryption;
|
||||||
|
|
||||||
struct Establisher
|
struct Establisher
|
||||||
{
|
{
|
||||||
NTCPPhase1 phase1;
|
NTCPPhase1 phase1;
|
||||||
NTCPPhase2 phase2;
|
NTCPPhase2 phase2;
|
||||||
} * m_Establisher;
|
} * m_Establisher;
|
||||||
|
|
||||||
i2p::crypto::AESAlignedBuffer<NTCP_BUFFER_SIZE + 16> m_ReceiveBuffer;
|
i2p::crypto::AESAlignedBuffer<NTCP_BUFFER_SIZE + 16> m_ReceiveBuffer;
|
||||||
i2p::crypto::AESAlignedBuffer<16> m_TimeSyncBuffer;
|
i2p::crypto::AESAlignedBuffer<16> m_TimeSyncBuffer;
|
||||||
int m_ReceiveBufferOffset;
|
int m_ReceiveBufferOffset;
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> m_NextMessage;
|
std::shared_ptr<I2NPMessage> m_NextMessage;
|
||||||
size_t m_NextMessageOffset;
|
size_t m_NextMessageOffset;
|
||||||
i2p::I2NPMessagesHandler m_Handler;
|
i2p::I2NPMessagesHandler m_Handler;
|
||||||
|
|
||||||
bool m_IsSending;
|
bool m_IsSending;
|
||||||
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||||
|
|
||||||
boost::asio::ip::address m_ConnectedFrom; // for ban
|
boost::asio::ip::address m_ConnectedFrom; // for ban
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: move to NTCP.h/.cpp
|
// TODO: move to NTCP.h/.cpp
|
||||||
class NTCPServer
|
class NTCPServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NTCPServer (int port);
|
NTCPServer (int port);
|
||||||
~NTCPServer ();
|
~NTCPServer ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
void AddNTCPSession (std::shared_ptr<NTCPSession> session);
|
void AddNTCPSession (std::shared_ptr<NTCPSession> session);
|
||||||
void RemoveNTCPSession (std::shared_ptr<NTCPSession> session);
|
void RemoveNTCPSession (std::shared_ptr<NTCPSession> session);
|
||||||
std::shared_ptr<NTCPSession> FindNTCPSession (const i2p::data::IdentHash& ident);
|
std::shared_ptr<NTCPSession> FindNTCPSession (const i2p::data::IdentHash& ident);
|
||||||
void Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn);
|
void Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn);
|
||||||
|
|
||||||
boost::asio::io_service& GetService () { return m_Service; };
|
boost::asio::io_service& GetService () { return m_Service; };
|
||||||
void Ban (const boost::asio::ip::address& addr);
|
void Ban (const boost::asio::ip::address& addr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void HandleAccept (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error);
|
void HandleAccept (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error);
|
||||||
void HandleAcceptV6 (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error);
|
void HandleAcceptV6 (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error);
|
||||||
|
|
||||||
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn);
|
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
boost::asio::io_service m_Service;
|
boost::asio::io_service m_Service;
|
||||||
boost::asio::io_service::work m_Work;
|
boost::asio::io_service::work m_Work;
|
||||||
boost::asio::ip::tcp::acceptor * m_NTCPAcceptor, * m_NTCPV6Acceptor;
|
boost::asio::ip::tcp::acceptor * m_NTCPAcceptor, * m_NTCPV6Acceptor;
|
||||||
std::mutex m_NTCPSessionsMutex;
|
std::mutex m_NTCPSessionsMutex;
|
||||||
std::map<i2p::data::IdentHash, std::shared_ptr<NTCPSession> > m_NTCPSessions;
|
std::map<i2p::data::IdentHash, std::shared_ptr<NTCPSession> > m_NTCPSessions;
|
||||||
std::map<boost::asio::ip::address, uint32_t> m_BanList; // IP -> ban expiration time in seconds
|
std::map<boost::asio::ip::address, uint32_t> m_BanList; // IP -> ban expiration time in seconds
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP/I2PControl
|
// for HTTP/I2PControl
|
||||||
const decltype(m_NTCPSessions)& GetNTCPSessions () const { return m_NTCPSessions; };
|
const decltype(m_NTCPSessions)& GetNTCPSessions () const { return m_NTCPSessions; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
130
NetDb.h
130
NetDb.h
|
@ -21,85 +21,85 @@
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
|
|
||||||
class NetDb
|
class NetDb
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NetDb ();
|
NetDb ();
|
||||||
~NetDb ();
|
~NetDb ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
void AddRouterInfo (const uint8_t * buf, int len);
|
void AddRouterInfo (const uint8_t * buf, int len);
|
||||||
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, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||||
std::shared_ptr<RouterInfo> FindRouter (const IdentHash& ident) const;
|
std::shared_ptr<RouterInfo> FindRouter (const IdentHash& ident) const;
|
||||||
std::shared_ptr<LeaseSet> FindLeaseSet (const IdentHash& destination) const;
|
std::shared_ptr<LeaseSet> FindLeaseSet (const IdentHash& destination) const;
|
||||||
|
|
||||||
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr);
|
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr);
|
||||||
|
|
||||||
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
|
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
|
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
|
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
|
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
|
||||||
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
|
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomPeerTestRouter () const;
|
std::shared_ptr<const RouterInfo> GetRandomPeerTestRouter () const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomIntroducer () const;
|
std::shared_ptr<const RouterInfo> GetRandomIntroducer () const;
|
||||||
std::shared_ptr<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;
|
||||||
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
|
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
|
||||||
std::set<IdentHash>& excluded) const;
|
std::set<IdentHash>& excluded) const;
|
||||||
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
||||||
void SetUnreachable (const IdentHash& ident, bool unreachable);
|
void SetUnreachable (const IdentHash& ident, bool unreachable);
|
||||||
|
|
||||||
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
|
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
|
|
||||||
void Reseed ();
|
void Reseed ();
|
||||||
|
|
||||||
// for web interface
|
// for web interface
|
||||||
int GetNumRouters () const { return m_RouterInfos.size (); };
|
int GetNumRouters () const { return m_RouterInfos.size (); };
|
||||||
int GetNumFloodfills () const { return m_Floodfills.size (); };
|
int GetNumFloodfills () const { return m_Floodfills.size (); };
|
||||||
int GetNumLeaseSets () const { return m_LeaseSets.size (); };
|
int GetNumLeaseSets () const { return m_LeaseSets.size (); };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool CreateNetDb(boost::filesystem::path directory);
|
bool CreateNetDb(boost::filesystem::path directory);
|
||||||
void Load ();
|
void Load ();
|
||||||
void SaveUpdated ();
|
void SaveUpdated ();
|
||||||
void Run (); // exploratory thread
|
void Run (); // exploratory thread
|
||||||
void Explore (int numDestinations);
|
void Explore (int numDestinations);
|
||||||
void Publish ();
|
void Publish ();
|
||||||
void ManageLeaseSets ();
|
void ManageLeaseSets ();
|
||||||
void ManageRequests ();
|
void ManageRequests ();
|
||||||
|
|
||||||
template<typename Filter>
|
template<typename Filter>
|
||||||
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
|
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::map<IdentHash, std::shared_ptr<LeaseSet> > m_LeaseSets;
|
std::map<IdentHash, std::shared_ptr<LeaseSet> > m_LeaseSets;
|
||||||
mutable std::mutex m_RouterInfosMutex;
|
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::list<std::shared_ptr<RouterInfo> > m_Floodfills;
|
std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg
|
i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg
|
||||||
|
|
||||||
Reseeder * m_Reseeder;
|
Reseeder * m_Reseeder;
|
||||||
|
|
||||||
friend class NetDbRequests;
|
friend class NetDbRequests;
|
||||||
NetDbRequests m_Requests;
|
NetDbRequests m_Requests;
|
||||||
|
|
||||||
static const char m_NetDbPath[];
|
static const char m_NetDbPath[];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern NetDb netdb;
|
extern NetDb netdb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,142 +8,142 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router,
|
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router,
|
||||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
|
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
|
||||||
{
|
{
|
||||||
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
||||||
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory,
|
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory,
|
||||||
&m_ExcludedPeers);
|
&m_ExcludedPeers);
|
||||||
m_ExcludedPeers.insert (router->GetIdentHash ());
|
m_ExcludedPeers.insert (router->GetIdentHash ());
|
||||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (const IdentHash& floodfill)
|
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (const IdentHash& floodfill)
|
||||||
{
|
{
|
||||||
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
||||||
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
|
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
|
||||||
m_ExcludedPeers.insert (floodfill);
|
m_ExcludedPeers.insert (floodfill);
|
||||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestedDestination::ClearExcludedPeers ()
|
void RequestedDestination::ClearExcludedPeers ()
|
||||||
{
|
{
|
||||||
m_ExcludedPeers.clear ();
|
m_ExcludedPeers.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
|
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
|
||||||
{
|
{
|
||||||
if (m_RequestComplete)
|
if (m_RequestComplete)
|
||||||
{
|
{
|
||||||
m_RequestComplete (r);
|
m_RequestComplete (r);
|
||||||
m_RequestComplete = nullptr;
|
m_RequestComplete = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestedDestination::Fail ()
|
void RequestedDestination::Fail ()
|
||||||
{
|
{
|
||||||
if (m_RequestComplete)
|
if (m_RequestComplete)
|
||||||
{
|
{
|
||||||
m_RequestComplete (nullptr);
|
m_RequestComplete (nullptr);
|
||||||
m_RequestComplete = nullptr;
|
m_RequestComplete = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDbRequests::Start ()
|
void NetDbRequests::Start ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDbRequests::Stop ()
|
void NetDbRequests::Stop ()
|
||||||
{
|
{
|
||||||
m_RequestedDestinations.clear ();
|
m_RequestedDestinations.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete)
|
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete)
|
||||||
{
|
{
|
||||||
// request RouterInfo directly
|
// request RouterInfo directly
|
||||||
auto dest = std::make_shared<RequestedDestination> (destination, isExploratory);
|
auto dest = std::make_shared<RequestedDestination> (destination, isExploratory);
|
||||||
dest->SetRequestComplete (requestComplete);
|
dest->SetRequestComplete (requestComplete);
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||||
if (!m_RequestedDestinations.insert (std::make_pair (destination,
|
if (!m_RequestedDestinations.insert (std::make_pair (destination,
|
||||||
std::shared_ptr<RequestedDestination> (dest))).second) // not inserted
|
std::shared_ptr<RequestedDestination> (dest))).second) // not inserted
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r)
|
void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r)
|
||||||
{
|
{
|
||||||
auto it = m_RequestedDestinations.find (ident);
|
auto it = m_RequestedDestinations.find (ident);
|
||||||
if (it != m_RequestedDestinations.end ())
|
if (it != m_RequestedDestinations.end ())
|
||||||
{
|
{
|
||||||
if (r)
|
if (r)
|
||||||
it->second->Success (r);
|
it->second->Success (r);
|
||||||
else
|
else
|
||||||
it->second->Fail ();
|
it->second->Fail ();
|
||||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||||
m_RequestedDestinations.erase (it);
|
m_RequestedDestinations.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const
|
std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const
|
||||||
{
|
{
|
||||||
auto it = m_RequestedDestinations.find (ident);
|
auto it = m_RequestedDestinations.find (ident);
|
||||||
if (it != m_RequestedDestinations.end ())
|
if (it != m_RequestedDestinations.end ())
|
||||||
return it->second;
|
return it->second;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDbRequests::ManageRequests ()
|
void NetDbRequests::ManageRequests ()
|
||||||
{
|
{
|
||||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||||
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
|
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
|
||||||
{
|
{
|
||||||
auto& dest = it->second;
|
auto& dest = it->second;
|
||||||
bool done = false;
|
bool done = false;
|
||||||
if (ts < dest->GetCreationTime () + 60) // request is worthless after 1 minute
|
if (ts < dest->GetCreationTime () + 60) // request is worthless after 1 minute
|
||||||
{
|
{
|
||||||
if (ts > dest->GetCreationTime () + 5) // no response for 5 seconds
|
if (ts > dest->GetCreationTime () + 5) // no response for 5 seconds
|
||||||
{
|
{
|
||||||
auto count = dest->GetExcludedPeers ().size ();
|
auto count = dest->GetExcludedPeers ().size ();
|
||||||
if (!dest->IsExploratory () && count < 7)
|
if (!dest->IsExploratory () && count < 7)
|
||||||
{
|
{
|
||||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||||
auto outbound = pool->GetNextOutboundTunnel ();
|
auto outbound = pool->GetNextOutboundTunnel ();
|
||||||
auto inbound = pool->GetNextInboundTunnel ();
|
auto inbound = pool->GetNextInboundTunnel ();
|
||||||
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
|
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
|
||||||
if (nextFloodfill && outbound && inbound)
|
if (nextFloodfill && outbound && inbound)
|
||||||
outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
|
outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
|
||||||
dest->CreateRequestMessage (nextFloodfill, inbound));
|
dest->CreateRequestMessage (nextFloodfill, inbound));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
done = true;
|
done = true;
|
||||||
if (!inbound) LogPrint (eLogWarning, "No inbound tunnels");
|
if (!inbound) LogPrint (eLogWarning, "No inbound tunnels");
|
||||||
if (!outbound) LogPrint (eLogWarning, "No outbound tunnels");
|
if (!outbound) LogPrint (eLogWarning, "No outbound tunnels");
|
||||||
if (!nextFloodfill) LogPrint (eLogWarning, "No more floodfills");
|
if (!nextFloodfill) LogPrint (eLogWarning, "No more floodfills");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!dest->IsExploratory ())
|
if (!dest->IsExploratory ())
|
||||||
LogPrint (eLogWarning, dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
|
LogPrint (eLogWarning, dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // delete obsolete request
|
else // delete obsolete request
|
||||||
done = true;
|
done = true;
|
||||||
|
|
||||||
if (done)
|
if (done)
|
||||||
it = m_RequestedDestinations.erase (it);
|
it = m_RequestedDestinations.erase (it);
|
||||||
else
|
else
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,57 +11,57 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
class RequestedDestination
|
class RequestedDestination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef std::function<void (std::shared_ptr<RouterInfo>)> RequestComplete;
|
typedef std::function<void (std::shared_ptr<RouterInfo>)> RequestComplete;
|
||||||
|
|
||||||
RequestedDestination (const IdentHash& destination, bool isExploratory = false):
|
RequestedDestination (const IdentHash& destination, bool isExploratory = false):
|
||||||
m_Destination (destination), m_IsExploratory (isExploratory), m_CreationTime (0) {};
|
m_Destination (destination), m_IsExploratory (isExploratory), m_CreationTime (0) {};
|
||||||
~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); };
|
~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); };
|
||||||
|
|
||||||
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 ();
|
||||||
bool IsExploratory () const { return m_IsExploratory; };
|
bool IsExploratory () const { return m_IsExploratory; };
|
||||||
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; };
|
||||||
std::shared_ptr<I2NPMessage> CreateRequestMessage (std::shared_ptr<const RouterInfo>, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel);
|
std::shared_ptr<I2NPMessage> CreateRequestMessage (std::shared_ptr<const RouterInfo>, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel);
|
||||||
std::shared_ptr<I2NPMessage> CreateRequestMessage (const IdentHash& floodfill);
|
std::shared_ptr<I2NPMessage> CreateRequestMessage (const IdentHash& floodfill);
|
||||||
|
|
||||||
void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; };
|
void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; };
|
||||||
bool IsRequestComplete () const { return m_RequestComplete != nullptr; };
|
bool IsRequestComplete () const { return m_RequestComplete != nullptr; };
|
||||||
void Success (std::shared_ptr<RouterInfo> r);
|
void Success (std::shared_ptr<RouterInfo> r);
|
||||||
void Fail ();
|
void Fail ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
IdentHash m_Destination;
|
IdentHash m_Destination;
|
||||||
bool m_IsExploratory;
|
bool m_IsExploratory;
|
||||||
std::set<IdentHash> m_ExcludedPeers;
|
std::set<IdentHash> m_ExcludedPeers;
|
||||||
uint64_t m_CreationTime;
|
uint64_t m_CreationTime;
|
||||||
RequestComplete m_RequestComplete;
|
RequestComplete m_RequestComplete;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetDbRequests
|
class NetDbRequests
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete = nullptr);
|
std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete = nullptr);
|
||||||
void RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r);
|
void RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r);
|
||||||
std::shared_ptr<RequestedDestination> FindRequest (const IdentHash& ident) const;
|
std::shared_ptr<RequestedDestination> FindRequest (const IdentHash& ident) const;
|
||||||
void ManageRequests ();
|
void ManageRequests ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::mutex m_RequestedDestinationsMutex;
|
std::mutex m_RequestedDestinationsMutex;
|
||||||
std::map<IdentHash, std::shared_ptr<RequestedDestination> > m_RequestedDestinations;
|
std::map<IdentHash, std::shared_ptr<RequestedDestination> > m_RequestedDestinations;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
390
Profiling.cpp
390
Profiling.cpp
|
@ -9,205 +9,205 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
RouterProfile::RouterProfile (const IdentHash& identHash):
|
RouterProfile::RouterProfile (const IdentHash& identHash):
|
||||||
m_IdentHash (identHash), m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
|
m_IdentHash (identHash), m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
|
||||||
m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
|
m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
|
||||||
m_NumTimesTaken (0), m_NumTimesRejected (0)
|
m_NumTimesTaken (0), m_NumTimesRejected (0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::posix_time::ptime RouterProfile::GetTime () const
|
boost::posix_time::ptime RouterProfile::GetTime () const
|
||||||
{
|
{
|
||||||
return boost::posix_time::second_clock::local_time();
|
return boost::posix_time::second_clock::local_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterProfile::UpdateTime ()
|
void RouterProfile::UpdateTime ()
|
||||||
{
|
{
|
||||||
m_LastUpdateTime = GetTime ();
|
m_LastUpdateTime = GetTime ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterProfile::Save ()
|
void RouterProfile::Save ()
|
||||||
{
|
{
|
||||||
// fill sections
|
// fill sections
|
||||||
boost::property_tree::ptree participation;
|
boost::property_tree::ptree participation;
|
||||||
participation.put (PEER_PROFILE_PARTICIPATION_AGREED, m_NumTunnelsAgreed);
|
participation.put (PEER_PROFILE_PARTICIPATION_AGREED, m_NumTunnelsAgreed);
|
||||||
participation.put (PEER_PROFILE_PARTICIPATION_DECLINED, m_NumTunnelsDeclined);
|
participation.put (PEER_PROFILE_PARTICIPATION_DECLINED, m_NumTunnelsDeclined);
|
||||||
participation.put (PEER_PROFILE_PARTICIPATION_NON_REPLIED, m_NumTunnelsNonReplied);
|
participation.put (PEER_PROFILE_PARTICIPATION_NON_REPLIED, m_NumTunnelsNonReplied);
|
||||||
boost::property_tree::ptree usage;
|
boost::property_tree::ptree usage;
|
||||||
usage.put (PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken);
|
usage.put (PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken);
|
||||||
usage.put (PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected);
|
usage.put (PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected);
|
||||||
// fill property tree
|
// fill property tree
|
||||||
boost::property_tree::ptree pt;
|
boost::property_tree::ptree pt;
|
||||||
pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
|
pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
|
||||||
pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation);
|
pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation);
|
||||||
pt.put_child (PEER_PROFILE_SECTION_USAGE, usage);
|
pt.put_child (PEER_PROFILE_SECTION_USAGE, usage);
|
||||||
|
|
||||||
// save to file
|
// save to file
|
||||||
auto path = i2p::util::filesystem::GetDefaultDataDir() / PEER_PROFILES_DIRECTORY;
|
auto path = i2p::util::filesystem::GetDefaultDataDir() / PEER_PROFILES_DIRECTORY;
|
||||||
if (!boost::filesystem::exists (path))
|
if (!boost::filesystem::exists (path))
|
||||||
{
|
{
|
||||||
// Create directory is necessary
|
// Create directory is necessary
|
||||||
if (!boost::filesystem::create_directory (path))
|
if (!boost::filesystem::create_directory (path))
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Failed to create directory ", path);
|
LogPrint (eLogError, "Failed to create directory ", path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const char * chars = GetBase64SubstitutionTable (); // 64 bytes
|
const char * chars = GetBase64SubstitutionTable (); // 64 bytes
|
||||||
for (int i = 0; i < 64; i++)
|
for (int i = 0; i < 64; i++)
|
||||||
{
|
{
|
||||||
auto path1 = path / (std::string ("p") + chars[i]);
|
auto path1 = path / (std::string ("p") + chars[i]);
|
||||||
if (!boost::filesystem::create_directory (path1))
|
if (!boost::filesystem::create_directory (path1))
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Failed to create directory ", path1);
|
LogPrint (eLogError, "Failed to create directory ", path1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string base64 = m_IdentHash.ToBase64 ();
|
std::string base64 = m_IdentHash.ToBase64 ();
|
||||||
path = path / (std::string ("p") + base64[0]);
|
path = path / (std::string ("p") + base64[0]);
|
||||||
auto filename = path / (std::string (PEER_PROFILE_PREFIX) + base64 + ".txt");
|
auto filename = path / (std::string (PEER_PROFILE_PREFIX) + base64 + ".txt");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
boost::property_tree::write_ini (filename.string (), pt);
|
boost::property_tree::write_ini (filename.string (), pt);
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Can't write ", filename, ": ", ex.what ());
|
LogPrint (eLogError, "Can't write ", filename, ": ", ex.what ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterProfile::Load ()
|
void RouterProfile::Load ()
|
||||||
{
|
{
|
||||||
std::string base64 = m_IdentHash.ToBase64 ();
|
std::string base64 = m_IdentHash.ToBase64 ();
|
||||||
auto path = i2p::util::filesystem::GetDefaultDataDir() / PEER_PROFILES_DIRECTORY;
|
auto path = i2p::util::filesystem::GetDefaultDataDir() / PEER_PROFILES_DIRECTORY;
|
||||||
path /= std::string ("p") + base64[0];
|
path /= std::string ("p") + base64[0];
|
||||||
auto filename = path / (std::string (PEER_PROFILE_PREFIX) + base64 + ".txt");
|
auto filename = path / (std::string (PEER_PROFILE_PREFIX) + base64 + ".txt");
|
||||||
if (boost::filesystem::exists (filename))
|
if (boost::filesystem::exists (filename))
|
||||||
{
|
{
|
||||||
boost::property_tree::ptree pt;
|
boost::property_tree::ptree pt;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
boost::property_tree::read_ini (filename.string (), pt);
|
boost::property_tree::read_ini (filename.string (), pt);
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Can't read ", filename, ": ", ex.what ());
|
LogPrint (eLogError, "Can't read ", filename, ": ", ex.what ());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
|
auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
|
||||||
if (t.length () > 0)
|
if (t.length () > 0)
|
||||||
m_LastUpdateTime = boost::posix_time::time_from_string (t);
|
m_LastUpdateTime = boost::posix_time::time_from_string (t);
|
||||||
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
|
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// read participations
|
// read participations
|
||||||
auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION);
|
auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION);
|
||||||
m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0);
|
m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0);
|
||||||
m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0);
|
m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0);
|
||||||
m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0);
|
m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0);
|
||||||
}
|
}
|
||||||
catch (boost::property_tree::ptree_bad_path& ex)
|
catch (boost::property_tree::ptree_bad_path& ex)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_PARTICIPATION);
|
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_PARTICIPATION);
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// read usage
|
// read usage
|
||||||
auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
|
auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
|
||||||
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
|
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
|
||||||
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
|
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
|
||||||
}
|
}
|
||||||
catch (boost::property_tree::ptree_bad_path& ex)
|
catch (boost::property_tree::ptree_bad_path& ex)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE);
|
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*this = RouterProfile (m_IdentHash);
|
*this = RouterProfile (m_IdentHash);
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Can't read profile ", base64, " :", ex.what ());
|
LogPrint (eLogError, "Can't read profile ", base64, " :", ex.what ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterProfile::TunnelBuildResponse (uint8_t ret)
|
void RouterProfile::TunnelBuildResponse (uint8_t ret)
|
||||||
{
|
{
|
||||||
UpdateTime ();
|
UpdateTime ();
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
m_NumTunnelsDeclined++;
|
m_NumTunnelsDeclined++;
|
||||||
else
|
else
|
||||||
m_NumTunnelsAgreed++;
|
m_NumTunnelsAgreed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterProfile::TunnelNonReplied ()
|
void RouterProfile::TunnelNonReplied ()
|
||||||
{
|
{
|
||||||
m_NumTunnelsNonReplied++;
|
m_NumTunnelsNonReplied++;
|
||||||
UpdateTime ();
|
UpdateTime ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterProfile::IsLowPartcipationRate () const
|
bool RouterProfile::IsLowPartcipationRate () const
|
||||||
{
|
{
|
||||||
return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
|
return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterProfile::IsLowReplyRate () const
|
bool RouterProfile::IsLowReplyRate () const
|
||||||
{
|
{
|
||||||
auto total = m_NumTunnelsAgreed + m_NumTunnelsDeclined;
|
auto total = m_NumTunnelsAgreed + m_NumTunnelsDeclined;
|
||||||
return m_NumTunnelsNonReplied > 10*(total + 1);
|
return m_NumTunnelsNonReplied > 10*(total + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterProfile::IsBad ()
|
bool RouterProfile::IsBad ()
|
||||||
{
|
{
|
||||||
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
|
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
|
||||||
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
|
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
|
||||||
{
|
{
|
||||||
// reset profile
|
// reset profile
|
||||||
m_NumTunnelsAgreed = 0;
|
m_NumTunnelsAgreed = 0;
|
||||||
m_NumTunnelsDeclined = 0;
|
m_NumTunnelsDeclined = 0;
|
||||||
m_NumTunnelsNonReplied = 0;
|
m_NumTunnelsNonReplied = 0;
|
||||||
isBad = false;
|
isBad = false;
|
||||||
}
|
}
|
||||||
if (isBad) m_NumTimesRejected++; else m_NumTimesTaken++;
|
if (isBad) m_NumTimesRejected++; else m_NumTimesTaken++;
|
||||||
return isBad;
|
return isBad;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
|
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
|
||||||
{
|
{
|
||||||
auto profile = std::make_shared<RouterProfile> (identHash);
|
auto profile = std::make_shared<RouterProfile> (identHash);
|
||||||
profile->Load (); // if possible
|
profile->Load (); // if possible
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteObsoleteProfiles ()
|
void DeleteObsoleteProfiles ()
|
||||||
{
|
{
|
||||||
int num = 0;
|
int num = 0;
|
||||||
auto ts = boost::posix_time::second_clock::local_time();
|
auto ts = boost::posix_time::second_clock::local_time();
|
||||||
boost::filesystem::path p (i2p::util::filesystem::GetDataDir()/PEER_PROFILES_DIRECTORY);
|
boost::filesystem::path p (i2p::util::filesystem::GetDataDir()/PEER_PROFILES_DIRECTORY);
|
||||||
if (boost::filesystem::exists (p))
|
if (boost::filesystem::exists (p))
|
||||||
{
|
{
|
||||||
boost::filesystem::directory_iterator end;
|
boost::filesystem::directory_iterator end;
|
||||||
for (boost::filesystem::directory_iterator it (p); it != end; ++it)
|
for (boost::filesystem::directory_iterator it (p); it != end; ++it)
|
||||||
{
|
{
|
||||||
if (boost::filesystem::is_directory (it->status()))
|
if (boost::filesystem::is_directory (it->status()))
|
||||||
{
|
{
|
||||||
for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1)
|
for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1)
|
||||||
{
|
{
|
||||||
auto lastModified = boost::posix_time::from_time_t (boost::filesystem::last_write_time (it1->path ()));
|
auto lastModified = boost::posix_time::from_time_t (boost::filesystem::last_write_time (it1->path ()));
|
||||||
if ((ts - lastModified).hours () >= PEER_PROFILE_EXPIRATION_TIMEOUT)
|
if ((ts - lastModified).hours () >= PEER_PROFILE_EXPIRATION_TIMEOUT)
|
||||||
{
|
{
|
||||||
boost::filesystem::remove (it1->path ());
|
boost::filesystem::remove (it1->path ());
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogPrint (eLogInfo, num, " obsolete profiles deleted");
|
LogPrint (eLogInfo, num, " obsolete profiles deleted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
98
Profiling.h
98
Profiling.h
|
@ -8,62 +8,62 @@
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
const char PEER_PROFILES_DIRECTORY[] = "peerProfiles";
|
const char PEER_PROFILES_DIRECTORY[] = "peerProfiles";
|
||||||
const char PEER_PROFILE_PREFIX[] = "profile-";
|
const char PEER_PROFILE_PREFIX[] = "profile-";
|
||||||
// sections
|
// sections
|
||||||
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
|
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
|
||||||
const char PEER_PROFILE_SECTION_USAGE[] = "usage";
|
const char PEER_PROFILE_SECTION_USAGE[] = "usage";
|
||||||
// params
|
// params
|
||||||
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime";
|
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime";
|
||||||
const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
|
const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
|
||||||
const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined";
|
const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined";
|
||||||
const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied";
|
const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied";
|
||||||
const char PEER_PROFILE_USAGE_TAKEN[] = "taken";
|
const char PEER_PROFILE_USAGE_TAKEN[] = "taken";
|
||||||
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
|
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
|
||||||
|
|
||||||
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days)
|
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days)
|
||||||
|
|
||||||
class RouterProfile
|
class RouterProfile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RouterProfile (const IdentHash& identHash);
|
RouterProfile (const IdentHash& identHash);
|
||||||
RouterProfile& operator= (const RouterProfile& ) = default;
|
RouterProfile& operator= (const RouterProfile& ) = default;
|
||||||
|
|
||||||
void Save ();
|
void Save ();
|
||||||
void Load ();
|
void Load ();
|
||||||
|
|
||||||
bool IsBad ();
|
bool IsBad ();
|
||||||
|
|
||||||
void TunnelBuildResponse (uint8_t ret);
|
void TunnelBuildResponse (uint8_t ret);
|
||||||
void TunnelNonReplied ();
|
void TunnelNonReplied ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
boost::posix_time::ptime GetTime () const;
|
boost::posix_time::ptime GetTime () const;
|
||||||
void UpdateTime ();
|
void UpdateTime ();
|
||||||
|
|
||||||
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
|
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
|
||||||
bool IsLowPartcipationRate () const;
|
bool IsLowPartcipationRate () const;
|
||||||
bool IsLowReplyRate () const;
|
bool IsLowReplyRate () const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
IdentHash m_IdentHash;
|
IdentHash m_IdentHash;
|
||||||
boost::posix_time::ptime m_LastUpdateTime;
|
boost::posix_time::ptime m_LastUpdateTime;
|
||||||
// participation
|
// participation
|
||||||
uint32_t m_NumTunnelsAgreed;
|
uint32_t m_NumTunnelsAgreed;
|
||||||
uint32_t m_NumTunnelsDeclined;
|
uint32_t m_NumTunnelsDeclined;
|
||||||
uint32_t m_NumTunnelsNonReplied;
|
uint32_t m_NumTunnelsNonReplied;
|
||||||
// usage
|
// usage
|
||||||
uint32_t m_NumTimesTaken;
|
uint32_t m_NumTimesTaken;
|
||||||
uint32_t m_NumTimesRejected;
|
uint32_t m_NumTimesRejected;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
|
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
|
||||||
void DeleteObsoleteProfiles ();
|
void DeleteObsoleteProfiles ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
270
Queue.h
270
Queue.h
|
@ -12,158 +12,158 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
template<typename Element>
|
template<typename Element>
|
||||||
class Queue
|
class Queue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void Put (Element e)
|
void Put (Element e)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||||
m_Queue.push (e);
|
m_Queue.push (e);
|
||||||
m_NonEmpty.notify_one ();
|
m_NonEmpty.notify_one ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Put (const std::vector<Element>& vec)
|
void Put (const std::vector<Element>& vec)
|
||||||
{
|
{
|
||||||
if (!vec.empty ())
|
if (!vec.empty ())
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||||
for (auto it: vec)
|
for (auto it: vec)
|
||||||
m_Queue.push (it);
|
m_Queue.push (it);
|
||||||
m_NonEmpty.notify_one ();
|
m_NonEmpty.notify_one ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Element GetNext ()
|
Element GetNext ()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||||
auto el = GetNonThreadSafe ();
|
auto el = GetNonThreadSafe ();
|
||||||
if (!el)
|
if (!el)
|
||||||
{
|
{
|
||||||
m_NonEmpty.wait (l);
|
m_NonEmpty.wait (l);
|
||||||
el = GetNonThreadSafe ();
|
el = GetNonThreadSafe ();
|
||||||
}
|
}
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
Element GetNextWithTimeout (int usec)
|
Element GetNextWithTimeout (int usec)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||||
auto el = GetNonThreadSafe ();
|
auto el = GetNonThreadSafe ();
|
||||||
if (!el)
|
if (!el)
|
||||||
{
|
{
|
||||||
m_NonEmpty.wait_for (l, std::chrono::milliseconds (usec));
|
m_NonEmpty.wait_for (l, std::chrono::milliseconds (usec));
|
||||||
el = GetNonThreadSafe ();
|
el = GetNonThreadSafe ();
|
||||||
}
|
}
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wait ()
|
void Wait ()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||||
m_NonEmpty.wait (l);
|
m_NonEmpty.wait (l);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wait (int sec, int usec)
|
bool Wait (int sec, int usec)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||||
return m_NonEmpty.wait_for (l, std::chrono::seconds (sec) + std::chrono::milliseconds (usec)) != std::cv_status::timeout;
|
return m_NonEmpty.wait_for (l, std::chrono::seconds (sec) + std::chrono::milliseconds (usec)) != std::cv_status::timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsEmpty ()
|
bool IsEmpty ()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||||
return m_Queue.empty ();
|
return m_Queue.empty ();
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetSize ()
|
int GetSize ()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||||
return m_Queue.size ();
|
return m_Queue.size ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WakeUp () { m_NonEmpty.notify_all (); };
|
void WakeUp () { m_NonEmpty.notify_all (); };
|
||||||
|
|
||||||
Element Get ()
|
Element Get ()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||||
return GetNonThreadSafe ();
|
return GetNonThreadSafe ();
|
||||||
}
|
}
|
||||||
|
|
||||||
Element Peek ()
|
Element Peek ()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||||
return GetNonThreadSafe (true);
|
return GetNonThreadSafe (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Element GetNonThreadSafe (bool peek = false)
|
Element GetNonThreadSafe (bool peek = false)
|
||||||
{
|
{
|
||||||
if (!m_Queue.empty ())
|
if (!m_Queue.empty ())
|
||||||
{
|
{
|
||||||
auto el = m_Queue.front ();
|
auto el = m_Queue.front ();
|
||||||
if (!peek)
|
if (!peek)
|
||||||
m_Queue.pop ();
|
m_Queue.pop ();
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::queue<Element> m_Queue;
|
std::queue<Element> m_Queue;
|
||||||
std::mutex m_QueueMutex;
|
std::mutex m_QueueMutex;
|
||||||
std::condition_variable m_NonEmpty;
|
std::condition_variable m_NonEmpty;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Msg>
|
template<class Msg>
|
||||||
class MsgQueue: public Queue<Msg *>
|
class MsgQueue: public Queue<Msg *>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef std::function<void()> OnEmpty;
|
typedef std::function<void()> OnEmpty;
|
||||||
|
|
||||||
MsgQueue (): m_IsRunning (true), m_Thread (std::bind (&MsgQueue<Msg>::Run, this)) {};
|
MsgQueue (): m_IsRunning (true), m_Thread (std::bind (&MsgQueue<Msg>::Run, this)) {};
|
||||||
~MsgQueue () { Stop (); };
|
~MsgQueue () { Stop (); };
|
||||||
void Stop()
|
void Stop()
|
||||||
{
|
{
|
||||||
if (m_IsRunning)
|
if (m_IsRunning)
|
||||||
{
|
{
|
||||||
m_IsRunning = false;
|
m_IsRunning = false;
|
||||||
Queue<Msg *>::WakeUp ();
|
Queue<Msg *>::WakeUp ();
|
||||||
m_Thread.join();
|
m_Thread.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetOnEmpty (OnEmpty const & e) { m_OnEmpty = e; };
|
void SetOnEmpty (OnEmpty const & e) { m_OnEmpty = e; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ()
|
void Run ()
|
||||||
{
|
{
|
||||||
while (m_IsRunning)
|
while (m_IsRunning)
|
||||||
{
|
{
|
||||||
while (auto msg = Queue<Msg *>::Get ())
|
while (auto msg = Queue<Msg *>::Get ())
|
||||||
{
|
{
|
||||||
msg->Process ();
|
msg->Process ();
|
||||||
delete msg;
|
delete msg;
|
||||||
}
|
}
|
||||||
if (m_OnEmpty != nullptr)
|
if (m_OnEmpty != nullptr)
|
||||||
m_OnEmpty ();
|
m_OnEmpty ();
|
||||||
if (m_IsRunning)
|
if (m_IsRunning)
|
||||||
Queue<Msg *>::Wait ();
|
Queue<Msg *>::Wait ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
volatile bool m_IsRunning;
|
volatile bool m_IsRunning;
|
||||||
OnEmpty m_OnEmpty;
|
OnEmpty m_OnEmpty;
|
||||||
std::thread m_Thread;
|
std::thread m_Thread;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
1702
Reseed.cpp
1702
Reseed.cpp
File diff suppressed because it is too large
Load diff
114
Reseed.h
114
Reseed.h
|
@ -16,79 +16,79 @@ namespace i2p
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
|
|
||||||
class Reseeder
|
class Reseeder
|
||||||
{
|
{
|
||||||
typedef Tag<512> PublicKey;
|
typedef Tag<512> PublicKey;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Reseeder();
|
Reseeder();
|
||||||
~Reseeder();
|
~Reseeder();
|
||||||
bool reseedNow(); // depreacted
|
bool reseedNow(); // depreacted
|
||||||
int ReseedNowSU3 ();
|
int ReseedNowSU3 ();
|
||||||
|
|
||||||
void LoadCertificates ();
|
void LoadCertificates ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void LoadCertificate (const std::string& filename);
|
void LoadCertificate (const std::string& filename);
|
||||||
std::string LoadCertificate (CryptoPP::ByteQueue& queue); // returns issuer's name
|
std::string LoadCertificate (CryptoPP::ByteQueue& queue); // returns issuer's name
|
||||||
|
|
||||||
int ReseedFromSU3 (const std::string& host, bool https = false);
|
int ReseedFromSU3 (const std::string& host, bool https = false);
|
||||||
int ProcessSU3File (const char * filename);
|
int ProcessSU3File (const char * filename);
|
||||||
int ProcessSU3Stream (std::istream& s);
|
int ProcessSU3Stream (std::istream& s);
|
||||||
|
|
||||||
bool FindZipDataDescriptor (std::istream& s);
|
bool FindZipDataDescriptor (std::istream& s);
|
||||||
|
|
||||||
std::string HttpsRequest (const std::string& address);
|
std::string HttpsRequest (const std::string& address);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::map<std::string, PublicKey> m_SigningKeys;
|
std::map<std::string, PublicKey> m_SigningKeys;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TlsCipher
|
class TlsCipher
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~TlsCipher () {};
|
virtual ~TlsCipher () {};
|
||||||
|
|
||||||
virtual void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac) = 0;
|
virtual void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac) = 0;
|
||||||
virtual size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) = 0;
|
virtual size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) = 0;
|
||||||
virtual size_t Decrypt (uint8_t * buf, size_t len) = 0;
|
virtual size_t Decrypt (uint8_t * buf, size_t len) = 0;
|
||||||
virtual size_t GetIVSize () const { return 0; }; // override for AES
|
virtual size_t GetIVSize () const { return 0; }; // override for AES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TlsSession
|
class TlsSession
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TlsSession (const std::string& host, int port);
|
TlsSession (const std::string& host, int port);
|
||||||
~TlsSession ();
|
~TlsSession ();
|
||||||
void Send (const uint8_t * buf, size_t len);
|
void Send (const uint8_t * buf, size_t len);
|
||||||
bool Receive (std::ostream& rs);
|
bool Receive (std::ostream& rs);
|
||||||
bool IsEstablished () const { return m_IsEstablished; };
|
bool IsEstablished () const { return m_IsEstablished; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Handshake ();
|
void Handshake ();
|
||||||
void SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, size_t len);
|
void SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, size_t len);
|
||||||
void SendFinishedMsg ();
|
void SendFinishedMsg ();
|
||||||
CryptoPP::RSA::PublicKey ExtractPublicKey (const uint8_t * certificate, size_t len);
|
CryptoPP::RSA::PublicKey ExtractPublicKey (const uint8_t * certificate, size_t len);
|
||||||
|
|
||||||
void PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen,
|
void PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen,
|
||||||
size_t len, uint8_t * buf);
|
size_t len, uint8_t * buf);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_IsEstablished;
|
bool m_IsEstablished;
|
||||||
boost::asio::ip::tcp::iostream m_Site;
|
boost::asio::ip::tcp::iostream m_Site;
|
||||||
CryptoPP::SHA256 m_FinishedHash;
|
CryptoPP::SHA256 m_FinishedHash;
|
||||||
uint8_t m_MasterSecret[64]; // actual size is 48, but must be multiple of 32
|
uint8_t m_MasterSecret[64]; // actual size is 48, but must be multiple of 32
|
||||||
TlsCipher * m_Cipher;
|
TlsCipher * m_Cipher;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,307 +12,307 @@
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
RouterContext context;
|
RouterContext context;
|
||||||
|
|
||||||
RouterContext::RouterContext ():
|
RouterContext::RouterContext ():
|
||||||
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
|
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
|
||||||
m_StartupTime (0), m_Status (eRouterStatusOK )
|
m_StartupTime (0), m_Status (eRouterStatusOK )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::Init ()
|
void RouterContext::Init ()
|
||||||
{
|
{
|
||||||
m_StartupTime = i2p::util::GetSecondsSinceEpoch ();
|
m_StartupTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
if (!Load ())
|
if (!Load ())
|
||||||
CreateNewRouter ();
|
CreateNewRouter ();
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::CreateNewRouter ()
|
void RouterContext::CreateNewRouter ()
|
||||||
{
|
{
|
||||||
m_Keys = i2p::data::CreateRandomKeys ();
|
m_Keys = i2p::data::CreateRandomKeys ();
|
||||||
SaveKeys ();
|
SaveKeys ();
|
||||||
NewRouterInfo ();
|
NewRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::NewRouterInfo ()
|
void RouterContext::NewRouterInfo ()
|
||||||
{
|
{
|
||||||
i2p::data::RouterInfo routerInfo;
|
i2p::data::RouterInfo routerInfo;
|
||||||
routerInfo.SetRouterIdentity (GetIdentity ());
|
routerInfo.SetRouterIdentity (GetIdentity ());
|
||||||
int port = i2p::util::config::GetArg("-port", 0);
|
int port = i2p::util::config::GetArg("-port", 0);
|
||||||
if (!port)
|
if (!port)
|
||||||
port = m_Rnd.GenerateWord32 (9111, 30777); // I2P network ports range
|
port = m_Rnd.GenerateWord32 (9111, 30777); // I2P network ports range
|
||||||
routerInfo.AddSSUAddress (i2p::util::config::GetCharArg("-host", "127.0.0.1"), port, routerInfo.GetIdentHash ());
|
routerInfo.AddSSUAddress (i2p::util::config::GetCharArg("-host", "127.0.0.1"), port, routerInfo.GetIdentHash ());
|
||||||
routerInfo.AddNTCPAddress (i2p::util::config::GetCharArg("-host", "127.0.0.1"), port);
|
routerInfo.AddNTCPAddress (i2p::util::config::GetCharArg("-host", "127.0.0.1"), port);
|
||||||
routerInfo.SetCaps (i2p::data::RouterInfo::eReachable |
|
routerInfo.SetCaps (i2p::data::RouterInfo::eReachable |
|
||||||
i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC
|
i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC
|
||||||
routerInfo.SetProperty ("coreVersion", I2P_VERSION);
|
routerInfo.SetProperty ("coreVersion", I2P_VERSION);
|
||||||
routerInfo.SetProperty ("netId", "2");
|
routerInfo.SetProperty ("netId", "2");
|
||||||
routerInfo.SetProperty ("router.version", I2P_VERSION);
|
routerInfo.SetProperty ("router.version", I2P_VERSION);
|
||||||
routerInfo.SetProperty ("stat_uptime", "90m");
|
routerInfo.SetProperty ("stat_uptime", "90m");
|
||||||
routerInfo.CreateBuffer (m_Keys);
|
routerInfo.CreateBuffer (m_Keys);
|
||||||
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::UpdateRouterInfo ()
|
void RouterContext::UpdateRouterInfo ()
|
||||||
{
|
{
|
||||||
m_RouterInfo.CreateBuffer (m_Keys);
|
m_RouterInfo.CreateBuffer (m_Keys);
|
||||||
m_RouterInfo.SaveToFile (i2p::util::filesystem::GetFullPath (ROUTER_INFO));
|
m_RouterInfo.SaveToFile (i2p::util::filesystem::GetFullPath (ROUTER_INFO));
|
||||||
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
|
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::UpdatePort (int port)
|
void RouterContext::UpdatePort (int port)
|
||||||
{
|
{
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
for (auto& address : m_RouterInfo.GetAddresses ())
|
||||||
{
|
{
|
||||||
if (address.port != port)
|
if (address.port != port)
|
||||||
{
|
{
|
||||||
address.port = port;
|
address.port = port;
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (updated)
|
if (updated)
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::UpdateAddress (const boost::asio::ip::address& host)
|
void RouterContext::UpdateAddress (const boost::asio::ip::address& host)
|
||||||
{
|
{
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
for (auto& address : m_RouterInfo.GetAddresses ())
|
||||||
{
|
{
|
||||||
if (address.host != host && address.IsCompatible (host))
|
if (address.host != host && address.IsCompatible (host))
|
||||||
{
|
{
|
||||||
address.host = host;
|
address.host = host;
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
if (updated || ts > m_LastUpdateTime + ROUTER_INFO_UPDATE_INTERVAL)
|
if (updated || ts > m_LastUpdateTime + ROUTER_INFO_UPDATE_INTERVAL)
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterContext::AddIntroducer (const i2p::data::RouterInfo& routerInfo, uint32_t tag)
|
bool RouterContext::AddIntroducer (const i2p::data::RouterInfo& routerInfo, uint32_t tag)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
auto address = routerInfo.GetSSUAddress ();
|
auto address = routerInfo.GetSSUAddress ();
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
ret = m_RouterInfo.AddIntroducer (address, tag);
|
ret = m_RouterInfo.AddIntroducer (address, tag);
|
||||||
if (ret)
|
if (ret)
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
|
void RouterContext::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
|
||||||
{
|
{
|
||||||
if (m_RouterInfo.RemoveIntroducer (e))
|
if (m_RouterInfo.RemoveIntroducer (e))
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::SetFloodfill (bool floodfill)
|
void RouterContext::SetFloodfill (bool floodfill)
|
||||||
{
|
{
|
||||||
m_IsFloodfill = floodfill;
|
m_IsFloodfill = floodfill;
|
||||||
if (floodfill)
|
if (floodfill)
|
||||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eFloodfill);
|
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eFloodfill);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eFloodfill);
|
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eFloodfill);
|
||||||
// we don't publish number of routers and leaseset for non-floodfill
|
// we don't publish number of routers and leaseset for non-floodfill
|
||||||
m_RouterInfo.DeleteProperty (ROUTER_INFO_PROPERTY_LEASESETS);
|
m_RouterInfo.DeleteProperty (ROUTER_INFO_PROPERTY_LEASESETS);
|
||||||
m_RouterInfo.DeleteProperty (ROUTER_INFO_PROPERTY_ROUTERS);
|
m_RouterInfo.DeleteProperty (ROUTER_INFO_PROPERTY_ROUTERS);
|
||||||
}
|
}
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::SetHighBandwidth ()
|
void RouterContext::SetHighBandwidth ()
|
||||||
{
|
{
|
||||||
if (!m_RouterInfo.IsHighBandwidth ())
|
if (!m_RouterInfo.IsHighBandwidth ())
|
||||||
{
|
{
|
||||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eHighBandwidth);
|
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eHighBandwidth);
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::SetLowBandwidth ()
|
void RouterContext::SetLowBandwidth ()
|
||||||
{
|
{
|
||||||
if (m_RouterInfo.IsHighBandwidth ())
|
if (m_RouterInfo.IsHighBandwidth ())
|
||||||
{
|
{
|
||||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eHighBandwidth);
|
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eHighBandwidth);
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterContext::IsUnreachable () const
|
bool RouterContext::IsUnreachable () const
|
||||||
{
|
{
|
||||||
return m_RouterInfo.GetCaps () & i2p::data::RouterInfo::eUnreachable;
|
return m_RouterInfo.GetCaps () & i2p::data::RouterInfo::eUnreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::SetUnreachable ()
|
void RouterContext::SetUnreachable ()
|
||||||
{
|
{
|
||||||
// set caps
|
// set caps
|
||||||
m_RouterInfo.SetCaps (i2p::data::RouterInfo::eUnreachable | i2p::data::RouterInfo::eSSUTesting); // LU, B
|
m_RouterInfo.SetCaps (i2p::data::RouterInfo::eUnreachable | i2p::data::RouterInfo::eSSUTesting); // LU, B
|
||||||
// remove NTCP address
|
// remove NTCP address
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||||
for (size_t i = 0; i < addresses.size (); i++)
|
for (size_t i = 0; i < addresses.size (); i++)
|
||||||
{
|
{
|
||||||
if (addresses[i].transportStyle == i2p::data::RouterInfo::eTransportNTCP)
|
if (addresses[i].transportStyle == i2p::data::RouterInfo::eTransportNTCP)
|
||||||
{
|
{
|
||||||
addresses.erase (addresses.begin () + i);
|
addresses.erase (addresses.begin () + i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// delete previous introducers
|
// delete previous introducers
|
||||||
for (auto& addr : addresses)
|
for (auto& addr : addresses)
|
||||||
addr.introducers.clear ();
|
addr.introducers.clear ();
|
||||||
|
|
||||||
// update
|
// update
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::SetReachable ()
|
void RouterContext::SetReachable ()
|
||||||
{
|
{
|
||||||
// update caps
|
// update caps
|
||||||
uint8_t caps = m_RouterInfo.GetCaps ();
|
uint8_t caps = m_RouterInfo.GetCaps ();
|
||||||
caps &= ~i2p::data::RouterInfo::eUnreachable;
|
caps &= ~i2p::data::RouterInfo::eUnreachable;
|
||||||
caps |= i2p::data::RouterInfo::eReachable;
|
caps |= i2p::data::RouterInfo::eReachable;
|
||||||
caps |= i2p::data::RouterInfo::eSSUIntroducer;
|
caps |= i2p::data::RouterInfo::eSSUIntroducer;
|
||||||
if (m_IsFloodfill)
|
if (m_IsFloodfill)
|
||||||
caps |= i2p::data::RouterInfo::eFloodfill;
|
caps |= i2p::data::RouterInfo::eFloodfill;
|
||||||
m_RouterInfo.SetCaps (caps);
|
m_RouterInfo.SetCaps (caps);
|
||||||
|
|
||||||
// insert NTCP back
|
// insert NTCP back
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||||
for (size_t i = 0; i < addresses.size (); i++)
|
for (size_t i = 0; i < addresses.size (); i++)
|
||||||
{
|
{
|
||||||
if (addresses[i].transportStyle == i2p::data::RouterInfo::eTransportSSU)
|
if (addresses[i].transportStyle == i2p::data::RouterInfo::eTransportSSU)
|
||||||
{
|
{
|
||||||
// insert NTCP address with host/port form SSU
|
// insert NTCP address with host/port form SSU
|
||||||
m_RouterInfo.AddNTCPAddress (addresses[i].host.to_string ().c_str (), addresses[i].port);
|
m_RouterInfo.AddNTCPAddress (addresses[i].host.to_string ().c_str (), addresses[i].port);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// delete previous introducers
|
// delete previous introducers
|
||||||
for (auto& addr : addresses)
|
for (auto& addr : addresses)
|
||||||
addr.introducers.clear ();
|
addr.introducers.clear ();
|
||||||
|
|
||||||
// update
|
// update
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::SetSupportsV6 (bool supportsV6)
|
void RouterContext::SetSupportsV6 (bool supportsV6)
|
||||||
{
|
{
|
||||||
if (supportsV6)
|
if (supportsV6)
|
||||||
m_RouterInfo.EnableV6 ();
|
m_RouterInfo.EnableV6 ();
|
||||||
else
|
else
|
||||||
m_RouterInfo.DisableV6 ();
|
m_RouterInfo.DisableV6 ();
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::UpdateNTCPV6Address (const boost::asio::ip::address& host)
|
void RouterContext::UpdateNTCPV6Address (const boost::asio::ip::address& host)
|
||||||
{
|
{
|
||||||
bool updated = false, found = false;
|
bool updated = false, found = false;
|
||||||
int port = 0;
|
int port = 0;
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||||
for (auto& addr : addresses)
|
for (auto& addr : addresses)
|
||||||
{
|
{
|
||||||
if (addr.host.is_v6 () && addr.transportStyle == i2p::data::RouterInfo::eTransportNTCP)
|
if (addr.host.is_v6 () && addr.transportStyle == i2p::data::RouterInfo::eTransportNTCP)
|
||||||
{
|
{
|
||||||
if (addr.host != host)
|
if (addr.host != host)
|
||||||
{
|
{
|
||||||
addr.host = host;
|
addr.host = host;
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
port = addr.port;
|
port = addr.port;
|
||||||
}
|
}
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
// create new address
|
// create new address
|
||||||
m_RouterInfo.AddNTCPAddress (host.to_string ().c_str (), port);
|
m_RouterInfo.AddNTCPAddress (host.to_string ().c_str (), port);
|
||||||
auto mtu = i2p::util::net::GetMTU (host);
|
auto mtu = i2p::util::net::GetMTU (host);
|
||||||
if (mtu)
|
if (mtu)
|
||||||
{
|
{
|
||||||
LogPrint ("Our v6 MTU=", mtu);
|
LogPrint ("Our v6 MTU=", mtu);
|
||||||
if (mtu > 1472) mtu = 1472;
|
if (mtu > 1472) mtu = 1472;
|
||||||
}
|
}
|
||||||
m_RouterInfo.AddSSUAddress (host.to_string ().c_str (), port, GetIdentHash (), mtu ? mtu : 1472); // TODO
|
m_RouterInfo.AddSSUAddress (host.to_string ().c_str (), port, GetIdentHash (), mtu ? mtu : 1472); // TODO
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
if (updated)
|
if (updated)
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::UpdateStats ()
|
void RouterContext::UpdateStats ()
|
||||||
{
|
{
|
||||||
if (m_IsFloodfill)
|
if (m_IsFloodfill)
|
||||||
{
|
{
|
||||||
// update routers and leasesets
|
// update routers and leasesets
|
||||||
m_RouterInfo.SetProperty (ROUTER_INFO_PROPERTY_LEASESETS, boost::lexical_cast<std::string>(i2p::data::netdb.GetNumLeaseSets ()));
|
m_RouterInfo.SetProperty (ROUTER_INFO_PROPERTY_LEASESETS, boost::lexical_cast<std::string>(i2p::data::netdb.GetNumLeaseSets ()));
|
||||||
m_RouterInfo.SetProperty (ROUTER_INFO_PROPERTY_ROUTERS, boost::lexical_cast<std::string>(i2p::data::netdb.GetNumRouters ()));
|
m_RouterInfo.SetProperty (ROUTER_INFO_PROPERTY_ROUTERS, boost::lexical_cast<std::string>(i2p::data::netdb.GetNumRouters ()));
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterContext::Load ()
|
bool RouterContext::Load ()
|
||||||
{
|
{
|
||||||
std::ifstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ifstream::binary | std::ofstream::in);
|
std::ifstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ifstream::binary | std::ofstream::in);
|
||||||
if (!fk.is_open ()) return false;
|
if (!fk.is_open ()) return false;
|
||||||
|
|
||||||
i2p::data::Keys keys;
|
i2p::data::Keys keys;
|
||||||
fk.read ((char *)&keys, sizeof (keys));
|
fk.read ((char *)&keys, sizeof (keys));
|
||||||
m_Keys = keys;
|
m_Keys = keys;
|
||||||
|
|
||||||
i2p::data::RouterInfo routerInfo(i2p::util::filesystem::GetFullPath (ROUTER_INFO)); // TODO
|
i2p::data::RouterInfo routerInfo(i2p::util::filesystem::GetFullPath (ROUTER_INFO)); // TODO
|
||||||
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
||||||
m_RouterInfo.SetProperty ("coreVersion", I2P_VERSION);
|
m_RouterInfo.SetProperty ("coreVersion", I2P_VERSION);
|
||||||
m_RouterInfo.SetProperty ("router.version", I2P_VERSION);
|
m_RouterInfo.SetProperty ("router.version", I2P_VERSION);
|
||||||
|
|
||||||
if (IsUnreachable ())
|
if (IsUnreachable ())
|
||||||
SetReachable (); // we assume reachable until we discover firewall through peer tests
|
SetReachable (); // we assume reachable until we discover firewall through peer tests
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::SaveKeys ()
|
void RouterContext::SaveKeys ()
|
||||||
{
|
{
|
||||||
std::ofstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ofstream::binary | std::ofstream::out);
|
std::ofstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ofstream::binary | std::ofstream::out);
|
||||||
i2p::data::Keys keys;
|
i2p::data::Keys keys;
|
||||||
memcpy (keys.privateKey, m_Keys.GetPrivateKey (), sizeof (keys.privateKey));
|
memcpy (keys.privateKey, m_Keys.GetPrivateKey (), sizeof (keys.privateKey));
|
||||||
memcpy (keys.signingPrivateKey, m_Keys.GetSigningPrivateKey (), sizeof (keys.signingPrivateKey));
|
memcpy (keys.signingPrivateKey, m_Keys.GetSigningPrivateKey (), sizeof (keys.signingPrivateKey));
|
||||||
auto& ident = GetIdentity ().GetStandardIdentity ();
|
auto& ident = GetIdentity ().GetStandardIdentity ();
|
||||||
memcpy (keys.publicKey, ident.publicKey, sizeof (keys.publicKey));
|
memcpy (keys.publicKey, ident.publicKey, sizeof (keys.publicKey));
|
||||||
memcpy (keys.signingKey, ident.signingKey, sizeof (keys.signingKey));
|
memcpy (keys.signingKey, ident.signingKey, sizeof (keys.signingKey));
|
||||||
fk.write ((char *)&keys, sizeof (keys));
|
fk.write ((char *)&keys, sizeof (keys));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> RouterContext::GetTunnelPool () const
|
std::shared_ptr<i2p::tunnel::TunnelPool> RouterContext::GetTunnelPool () const
|
||||||
{
|
{
|
||||||
return i2p::tunnel::tunnels.GetExploratoryPool ();
|
return i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
|
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
|
||||||
{
|
{
|
||||||
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from));
|
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
||||||
i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg);
|
i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
||||||
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
|
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t RouterContext::GetUptime () const
|
uint32_t RouterContext::GetUptime () const
|
||||||
{
|
{
|
||||||
return i2p::util::GetSecondsSinceEpoch () - m_StartupTime;
|
return i2p::util::GetSecondsSinceEpoch () - m_StartupTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
156
RouterContext.h
156
RouterContext.h
|
@ -14,94 +14,94 @@
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
const char ROUTER_INFO[] = "router.info";
|
const char ROUTER_INFO[] = "router.info";
|
||||||
const char ROUTER_KEYS[] = "router.keys";
|
const char ROUTER_KEYS[] = "router.keys";
|
||||||
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
|
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
|
||||||
|
|
||||||
const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets";
|
const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets";
|
||||||
const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters";
|
const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters";
|
||||||
|
|
||||||
enum RouterStatus
|
enum RouterStatus
|
||||||
{
|
{
|
||||||
eRouterStatusOK = 0,
|
eRouterStatusOK = 0,
|
||||||
eRouterStatusTesting = 1,
|
eRouterStatusTesting = 1,
|
||||||
eRouterStatusFirewalled = 2
|
eRouterStatusFirewalled = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
class RouterContext: public i2p::garlic::GarlicDestination
|
class RouterContext: public i2p::garlic::GarlicDestination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RouterContext ();
|
RouterContext ();
|
||||||
void Init ();
|
void Init ();
|
||||||
|
|
||||||
i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; };
|
i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; };
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> GetSharedRouterInfo () const
|
std::shared_ptr<const i2p::data::RouterInfo> GetSharedRouterInfo () const
|
||||||
{
|
{
|
||||||
return std::shared_ptr<const i2p::data::RouterInfo> (&m_RouterInfo,
|
return std::shared_ptr<const i2p::data::RouterInfo> (&m_RouterInfo,
|
||||||
[](const i2p::data::RouterInfo *) {});
|
[](const i2p::data::RouterInfo *) {});
|
||||||
}
|
}
|
||||||
CryptoPP::RandomNumberGenerator& GetRandomNumberGenerator () { return m_Rnd; };
|
CryptoPP::RandomNumberGenerator& GetRandomNumberGenerator () { return m_Rnd; };
|
||||||
uint32_t GetUptime () const;
|
uint32_t GetUptime () const;
|
||||||
uint32_t GetStartupTime () const { return m_StartupTime; };
|
uint32_t GetStartupTime () const { return m_StartupTime; };
|
||||||
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||||
RouterStatus GetStatus () const { return m_Status; };
|
RouterStatus GetStatus () const { return m_Status; };
|
||||||
void SetStatus (RouterStatus status) { m_Status = status; };
|
void SetStatus (RouterStatus status) { m_Status = status; };
|
||||||
|
|
||||||
void UpdatePort (int port); // called from Daemon
|
void UpdatePort (int port); // called from Daemon
|
||||||
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
|
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
|
||||||
bool AddIntroducer (const i2p::data::RouterInfo& routerInfo, uint32_t tag);
|
bool AddIntroducer (const i2p::data::RouterInfo& routerInfo, uint32_t tag);
|
||||||
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
||||||
bool IsUnreachable () const;
|
bool IsUnreachable () const;
|
||||||
void SetUnreachable ();
|
void SetUnreachable ();
|
||||||
void SetReachable ();
|
void SetReachable ();
|
||||||
bool IsFloodfill () const { return m_IsFloodfill; };
|
bool IsFloodfill () const { return m_IsFloodfill; };
|
||||||
void SetFloodfill (bool floodfill);
|
void SetFloodfill (bool floodfill);
|
||||||
void SetHighBandwidth ();
|
void SetHighBandwidth ();
|
||||||
void SetLowBandwidth ();
|
void SetLowBandwidth ();
|
||||||
bool AcceptsTunnels () const { return m_AcceptsTunnels; };
|
bool AcceptsTunnels () const { return m_AcceptsTunnels; };
|
||||||
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
|
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
|
||||||
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
|
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
|
||||||
void SetSupportsV6 (bool supportsV6);
|
void SetSupportsV6 (bool supportsV6);
|
||||||
void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session
|
void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session
|
||||||
void UpdateStats ();
|
void UpdateStats ();
|
||||||
|
|
||||||
// implements LocalDestination
|
// implements LocalDestination
|
||||||
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
||||||
const uint8_t * GetEncryptionPrivateKey () const { return m_Keys.GetPrivateKey (); };
|
const uint8_t * GetEncryptionPrivateKey () const { return m_Keys.GetPrivateKey (); };
|
||||||
const uint8_t * GetEncryptionPublicKey () const { return GetIdentity ().GetStandardIdentity ().publicKey; };
|
const uint8_t * GetEncryptionPublicKey () const { return GetIdentity ().GetStandardIdentity ().publicKey; };
|
||||||
void SetLeaseSetUpdated () {};
|
void SetLeaseSetUpdated () {};
|
||||||
|
|
||||||
// implements GarlicDestination
|
// implements GarlicDestination
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> GetLeaseSet () { return nullptr; };
|
std::shared_ptr<const i2p::data::LeaseSet> GetLeaseSet () { return nullptr; };
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const;
|
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const;
|
||||||
void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||||
|
|
||||||
// override GarlicDestination
|
// override GarlicDestination
|
||||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateNewRouter ();
|
void CreateNewRouter ();
|
||||||
void NewRouterInfo ();
|
void NewRouterInfo ();
|
||||||
void UpdateRouterInfo ();
|
void UpdateRouterInfo ();
|
||||||
bool Load ();
|
bool Load ();
|
||||||
void SaveKeys ();
|
void SaveKeys ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
i2p::data::RouterInfo m_RouterInfo;
|
i2p::data::RouterInfo m_RouterInfo;
|
||||||
i2p::data::PrivateKeys m_Keys;
|
i2p::data::PrivateKeys m_Keys;
|
||||||
CryptoPP::AutoSeededRandomPool m_Rnd;
|
CryptoPP::AutoSeededRandomPool m_Rnd;
|
||||||
uint64_t m_LastUpdateTime;
|
uint64_t m_LastUpdateTime;
|
||||||
bool m_AcceptsTunnels, m_IsFloodfill;
|
bool m_AcceptsTunnels, m_IsFloodfill;
|
||||||
uint64_t m_StartupTime; // in seconds since epoch
|
uint64_t m_StartupTime; // in seconds since epoch
|
||||||
RouterStatus m_Status;
|
RouterStatus m_Status;
|
||||||
std::mutex m_GarlicMutex;
|
std::mutex m_GarlicMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern RouterContext context;
|
extern RouterContext context;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
1230
RouterInfo.cpp
1230
RouterInfo.cpp
File diff suppressed because it is too large
Load diff
295
RouterInfo.h
295
RouterInfo.h
|
@ -14,169 +14,170 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
const char CAPS_FLAG_FLOODFILL = 'f';
|
const char CAPS_FLAG_FLOODFILL = 'f';
|
||||||
const char CAPS_FLAG_HIDDEN = 'H';
|
const char CAPS_FLAG_HIDDEN = 'H';
|
||||||
const char CAPS_FLAG_REACHABLE = 'R';
|
const char CAPS_FLAG_REACHABLE = 'R';
|
||||||
const char CAPS_FLAG_UNREACHABLE = 'U';
|
const char CAPS_FLAG_UNREACHABLE = 'U';
|
||||||
const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K';
|
const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K';
|
||||||
const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L';
|
const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L';
|
||||||
const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M';
|
const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M';
|
||||||
const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N';
|
const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N';
|
||||||
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O';
|
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O';
|
||||||
|
|
||||||
const char CAPS_FLAG_SSU_TESTING = 'B';
|
const char CAPS_FLAG_SSU_TESTING = 'B';
|
||||||
const char CAPS_FLAG_SSU_INTRODUCER = 'C';
|
const char CAPS_FLAG_SSU_INTRODUCER = 'C';
|
||||||
|
|
||||||
const int MAX_RI_BUFFER_SIZE = 2048;
|
const int MAX_RI_BUFFER_SIZE = 2048;
|
||||||
class RouterInfo: public RoutingDestination
|
class RouterInfo: public RoutingDestination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum SupportedTranports
|
enum SupportedTranports
|
||||||
{
|
{
|
||||||
eNTCPV4 = 0x01,
|
eNTCPV4 = 0x01,
|
||||||
eNTCPV6 = 0x02,
|
eNTCPV6 = 0x02,
|
||||||
eSSUV4 = 0x04,
|
eSSUV4 = 0x04,
|
||||||
eSSUV6 = 0x08
|
eSSUV6 = 0x08
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Caps
|
enum Caps
|
||||||
{
|
{
|
||||||
eFloodfill = 0x01,
|
eFloodfill = 0x01,
|
||||||
eHighBandwidth = 0x02,
|
eHighBandwidth = 0x02,
|
||||||
eReachable = 0x04,
|
eReachable = 0x04,
|
||||||
eSSUTesting = 0x08,
|
eSSUTesting = 0x08,
|
||||||
eSSUIntroducer = 0x10,
|
eSSUIntroducer = 0x10,
|
||||||
eHidden = 0x20,
|
eHidden = 0x20,
|
||||||
eUnreachable = 0x40
|
eUnreachable = 0x40
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TransportStyle
|
enum TransportStyle
|
||||||
{
|
{
|
||||||
eTransportUnknown = 0,
|
eTransportUnknown = 0,
|
||||||
eTransportNTCP,
|
eTransportNTCP,
|
||||||
eTransportSSU
|
eTransportSSU
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Introducer
|
struct Introducer
|
||||||
{
|
{
|
||||||
boost::asio::ip::address iHost;
|
boost::asio::ip::address iHost;
|
||||||
int iPort;
|
int iPort;
|
||||||
Tag<32> iKey;
|
Tag<32> iKey;
|
||||||
uint32_t iTag;
|
uint32_t iTag;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Address
|
struct Address
|
||||||
{
|
{
|
||||||
TransportStyle transportStyle;
|
TransportStyle transportStyle;
|
||||||
boost::asio::ip::address host;
|
boost::asio::ip::address host;
|
||||||
std::string addressString;
|
std::string addressString;
|
||||||
int port, mtu;
|
int port, mtu;
|
||||||
uint64_t date;
|
uint64_t date;
|
||||||
uint8_t cost;
|
uint8_t cost;
|
||||||
// SSU only
|
// SSU only
|
||||||
Tag<32> key; // intro key for SSU
|
Tag<32> key; // intro key for SSU
|
||||||
std::vector<Introducer> introducers;
|
std::vector<Introducer> introducers;
|
||||||
|
|
||||||
bool IsCompatible (const boost::asio::ip::address& other) const
|
bool IsCompatible (const boost::asio::ip::address& other) const
|
||||||
{
|
{
|
||||||
return (host.is_v4 () && other.is_v4 ()) ||
|
return (host.is_v4 () && other.is_v4 ()) ||
|
||||||
(host.is_v6 () && other.is_v6 ());
|
(host.is_v6 () && other.is_v6 ());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
RouterInfo (const std::string& fullPath);
|
RouterInfo (const std::string& fullPath);
|
||||||
RouterInfo (): m_Buffer (nullptr) { };
|
RouterInfo (): m_Buffer (nullptr) { };
|
||||||
RouterInfo (const RouterInfo& ) = default;
|
|
||||||
RouterInfo& operator=(const RouterInfo& ) = default;
|
|
||||||
RouterInfo (const uint8_t * buf, int len);
|
|
||||||
~RouterInfo ();
|
|
||||||
|
|
||||||
const IdentityEx& GetRouterIdentity () const { return m_RouterIdentity; };
|
|
||||||
void SetRouterIdentity (const IdentityEx& identity);
|
|
||||||
std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); };
|
|
||||||
std::string GetIdentHashAbbreviation () const { return GetIdentHash ().ToBase64 ().substr (0, 4); };
|
|
||||||
uint64_t GetTimestamp () const { return m_Timestamp; };
|
|
||||||
std::vector<Address>& GetAddresses () { return m_Addresses; };
|
|
||||||
const Address * GetNTCPAddress (bool v4only = true) const;
|
|
||||||
const Address * GetSSUAddress (bool v4only = true) const;
|
|
||||||
const Address * GetSSUV6Address () const;
|
|
||||||
|
|
||||||
void AddNTCPAddress (const char * host, int port);
|
|
||||||
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
|
|
||||||
bool AddIntroducer (const Address * address, uint32_t tag);
|
|
||||||
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
|
||||||
void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only
|
|
||||||
void DeleteProperty (const std::string& key); // called from RouterContext only
|
|
||||||
void ClearProperties () { m_Properties.clear (); };
|
|
||||||
bool IsFloodfill () const;
|
|
||||||
bool IsNTCP (bool v4only = true) const;
|
|
||||||
bool IsSSU (bool v4only = true) const;
|
|
||||||
bool IsV6 () const;
|
|
||||||
void EnableV6 ();
|
|
||||||
void DisableV6 ();
|
|
||||||
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
|
|
||||||
bool UsesIntroducer () const;
|
|
||||||
bool IsIntroducer () const { return m_Caps & eSSUIntroducer; };
|
|
||||||
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
|
|
||||||
bool IsHidden () const { return m_Caps & eHidden; };
|
|
||||||
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
|
||||||
|
|
||||||
uint8_t GetCaps () const { return m_Caps; };
|
RouterInfo (const RouterInfo& ) = default;
|
||||||
void SetCaps (uint8_t caps);
|
RouterInfo& operator=(const RouterInfo& ) = default;
|
||||||
void SetCaps (const char * caps);
|
RouterInfo (const uint8_t * buf, int len);
|
||||||
|
~RouterInfo ();
|
||||||
|
|
||||||
|
const IdentityEx& GetRouterIdentity () const { return m_RouterIdentity; };
|
||||||
|
void SetRouterIdentity (const IdentityEx& identity);
|
||||||
|
std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); };
|
||||||
|
std::string GetIdentHashAbbreviation () const { return GetIdentHash ().ToBase64 ().substr (0, 4); };
|
||||||
|
uint64_t GetTimestamp () const { return m_Timestamp; };
|
||||||
|
std::vector<Address>& GetAddresses () { return m_Addresses; };
|
||||||
|
const Address * GetNTCPAddress (bool v4only = true) const;
|
||||||
|
const Address * GetSSUAddress (bool v4only = true) const;
|
||||||
|
const Address * GetSSUV6Address () const;
|
||||||
|
|
||||||
|
void AddNTCPAddress (const char * host, int port);
|
||||||
|
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
|
||||||
|
bool AddIntroducer (const Address * address, uint32_t tag);
|
||||||
|
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
||||||
|
void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only
|
||||||
|
void DeleteProperty (const std::string& key); // called from RouterContext only
|
||||||
|
void ClearProperties () { m_Properties.clear (); };
|
||||||
|
bool IsFloodfill () const;
|
||||||
|
bool IsNTCP (bool v4only = true) const;
|
||||||
|
bool IsSSU (bool v4only = true) const;
|
||||||
|
bool IsV6 () const;
|
||||||
|
void EnableV6 ();
|
||||||
|
void DisableV6 ();
|
||||||
|
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
|
||||||
|
bool UsesIntroducer () const;
|
||||||
|
bool IsIntroducer () const { return m_Caps & eSSUIntroducer; };
|
||||||
|
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
|
||||||
|
bool IsHidden () const { return m_Caps & eHidden; };
|
||||||
|
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||||
|
|
||||||
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
uint8_t GetCaps () const { return m_Caps; };
|
||||||
bool IsUnreachable () const { return m_IsUnreachable; };
|
void SetCaps (uint8_t caps);
|
||||||
|
void SetCaps (const char * caps);
|
||||||
|
|
||||||
const uint8_t * GetBuffer () const { return m_Buffer; };
|
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
||||||
const uint8_t * LoadBuffer (); // load if necessary
|
bool IsUnreachable () const { return m_IsUnreachable; };
|
||||||
int GetBufferLen () const { return m_BufferLen; };
|
|
||||||
void CreateBuffer (const PrivateKeys& privateKeys);
|
|
||||||
|
|
||||||
bool IsUpdated () const { return m_IsUpdated; };
|
const uint8_t * GetBuffer () const { return m_Buffer; };
|
||||||
void SetUpdated (bool updated) { m_IsUpdated = updated; };
|
const uint8_t * LoadBuffer (); // load if necessary
|
||||||
void SaveToFile (const std::string& fullPath);
|
int GetBufferLen () const { return m_BufferLen; };
|
||||||
|
void CreateBuffer (const PrivateKeys& privateKeys);
|
||||||
|
|
||||||
std::shared_ptr<RouterProfile> GetProfile () const;
|
bool IsUpdated () const { return m_IsUpdated; };
|
||||||
void SaveProfile () { if (m_Profile) m_Profile->Save (); };
|
void SetUpdated (bool updated) { m_IsUpdated = updated; };
|
||||||
|
void SaveToFile (const std::string& fullPath);
|
||||||
void Update (const uint8_t * buf, int len);
|
|
||||||
void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; };
|
|
||||||
|
|
||||||
// implements RoutingDestination
|
|
||||||
const IdentHash& GetIdentHash () const { return m_RouterIdentity.GetIdentHash (); };
|
|
||||||
const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity.GetStandardIdentity ().publicKey; };
|
|
||||||
bool IsDestination () const { return false; };
|
|
||||||
|
|
||||||
|
std::shared_ptr<RouterProfile> GetProfile () const;
|
||||||
private:
|
void SaveProfile () { if (m_Profile) m_Profile->Save (); };
|
||||||
|
|
||||||
|
void Update (const uint8_t * buf, int len);
|
||||||
|
void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; };
|
||||||
|
|
||||||
|
// implements RoutingDestination
|
||||||
|
const IdentHash& GetIdentHash () const { return m_RouterIdentity.GetIdentHash (); };
|
||||||
|
const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity.GetStandardIdentity ().publicKey; };
|
||||||
|
bool IsDestination () const { return false; };
|
||||||
|
|
||||||
bool LoadFile ();
|
|
||||||
void ReadFromFile ();
|
private:
|
||||||
void ReadFromStream (std::istream& s);
|
|
||||||
void ReadFromBuffer (bool verifySignature);
|
|
||||||
void WriteToStream (std::ostream& s);
|
|
||||||
size_t ReadString (char * str, std::istream& s);
|
|
||||||
void WriteString (const std::string& str, std::ostream& s);
|
|
||||||
void ExtractCaps (const char * value);
|
|
||||||
const Address * GetAddress (TransportStyle s, bool v4only, bool v6only = false) const;
|
|
||||||
void UpdateCapsProperty ();
|
|
||||||
|
|
||||||
private:
|
bool LoadFile ();
|
||||||
|
void ReadFromFile ();
|
||||||
|
void ReadFromStream (std::istream& s);
|
||||||
|
void ReadFromBuffer (bool verifySignature);
|
||||||
|
void WriteToStream (std::ostream& s);
|
||||||
|
size_t ReadString (char * str, std::istream& s);
|
||||||
|
void WriteString (const std::string& str, std::ostream& s);
|
||||||
|
void ExtractCaps (const char * value);
|
||||||
|
const Address * GetAddress (TransportStyle s, bool v4only, bool v6only = false) const;
|
||||||
|
void UpdateCapsProperty ();
|
||||||
|
|
||||||
std::string m_FullPath;
|
private:
|
||||||
IdentityEx m_RouterIdentity;
|
|
||||||
uint8_t * m_Buffer;
|
std::string m_FullPath;
|
||||||
int m_BufferLen;
|
IdentityEx m_RouterIdentity;
|
||||||
uint64_t m_Timestamp;
|
uint8_t * m_Buffer;
|
||||||
std::vector<Address> m_Addresses;
|
int m_BufferLen;
|
||||||
std::map<std::string, std::string> m_Properties;
|
uint64_t m_Timestamp;
|
||||||
bool m_IsUpdated, m_IsUnreachable;
|
std::vector<Address> m_Addresses;
|
||||||
uint8_t m_SupportedTransports, m_Caps;
|
std::map<std::string, std::string> m_Properties;
|
||||||
mutable std::shared_ptr<RouterProfile> m_Profile;
|
bool m_IsUpdated, m_IsUnreachable;
|
||||||
};
|
uint8_t m_SupportedTransports, m_Caps;
|
||||||
}
|
mutable std::shared_ptr<RouterProfile> m_Profile;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
286
SAM.h
286
SAM.h
|
@ -18,173 +18,173 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
const size_t SAM_SOCKET_BUFFER_SIZE = 8192;
|
const size_t SAM_SOCKET_BUFFER_SIZE = 8192;
|
||||||
const int SAM_SOCKET_CONNECTION_MAX_IDLE = 3600; // in seconds
|
const int SAM_SOCKET_CONNECTION_MAX_IDLE = 3600; // in seconds
|
||||||
const int SAM_SESSION_READINESS_CHECK_INTERVAL = 20; // in seconds
|
const int SAM_SESSION_READINESS_CHECK_INTERVAL = 20; // in seconds
|
||||||
const char SAM_HANDSHAKE[] = "HELLO VERSION";
|
const char SAM_HANDSHAKE[] = "HELLO VERSION";
|
||||||
const char SAM_HANDSHAKE_REPLY[] = "HELLO REPLY RESULT=OK VERSION=%s\n";
|
const char SAM_HANDSHAKE_REPLY[] = "HELLO REPLY RESULT=OK VERSION=%s\n";
|
||||||
const char SAM_HANDSHAKE_I2P_ERROR[] = "HELLO REPLY RESULT=I2P_ERROR\n";
|
const char SAM_HANDSHAKE_I2P_ERROR[] = "HELLO REPLY RESULT=I2P_ERROR\n";
|
||||||
const char SAM_SESSION_CREATE[] = "SESSION CREATE";
|
const char SAM_SESSION_CREATE[] = "SESSION CREATE";
|
||||||
const char SAM_SESSION_CREATE_REPLY_OK[] = "SESSION STATUS RESULT=OK DESTINATION=%s\n";
|
const char SAM_SESSION_CREATE_REPLY_OK[] = "SESSION STATUS RESULT=OK DESTINATION=%s\n";
|
||||||
const char SAM_SESSION_CREATE_DUPLICATED_ID[] = "SESSION STATUS RESULT=DUPLICATED_ID\n";
|
const char SAM_SESSION_CREATE_DUPLICATED_ID[] = "SESSION STATUS RESULT=DUPLICATED_ID\n";
|
||||||
const char SAM_SESSION_CREATE_DUPLICATED_DEST[] = "SESSION STATUS RESULT=DUPLICATED_DEST\n";
|
const char SAM_SESSION_CREATE_DUPLICATED_DEST[] = "SESSION STATUS RESULT=DUPLICATED_DEST\n";
|
||||||
const char SAM_SESSION_STATUS_INVALID_KEY[] = "SESSION STATUS RESULT=INVALID_KEY\n";
|
const char SAM_SESSION_STATUS_INVALID_KEY[] = "SESSION STATUS RESULT=INVALID_KEY\n";
|
||||||
const char SAM_STREAM_CONNECT[] = "STREAM CONNECT";
|
const char SAM_STREAM_CONNECT[] = "STREAM CONNECT";
|
||||||
const char SAM_STREAM_STATUS_OK[] = "STREAM STATUS RESULT=OK\n";
|
const char SAM_STREAM_STATUS_OK[] = "STREAM STATUS RESULT=OK\n";
|
||||||
const char SAM_STREAM_STATUS_INVALID_ID[] = "STREAM STATUS RESULT=INVALID_ID\n";
|
const char SAM_STREAM_STATUS_INVALID_ID[] = "STREAM STATUS RESULT=INVALID_ID\n";
|
||||||
const char SAM_STREAM_STATUS_CANT_REACH_PEER[] = "STREAM STATUS RESULT=CANT_REACH_PEER\n";
|
const char SAM_STREAM_STATUS_CANT_REACH_PEER[] = "STREAM STATUS RESULT=CANT_REACH_PEER\n";
|
||||||
const char SAM_STREAM_STATUS_I2P_ERROR[] = "STREAM STATUS RESULT=I2P_ERROR\n";
|
const char SAM_STREAM_STATUS_I2P_ERROR[] = "STREAM STATUS RESULT=I2P_ERROR\n";
|
||||||
const char SAM_STREAM_ACCEPT[] = "STREAM ACCEPT";
|
const char SAM_STREAM_ACCEPT[] = "STREAM ACCEPT";
|
||||||
const char SAM_DATAGRAM_SEND[] = "DATAGRAM SEND";
|
const char SAM_DATAGRAM_SEND[] = "DATAGRAM SEND";
|
||||||
const char SAM_DEST_GENERATE[] = "DEST GENERATE";
|
const char SAM_DEST_GENERATE[] = "DEST GENERATE";
|
||||||
const char SAM_DEST_REPLY[] = "DEST REPLY PUB=%s PRIV=%s\n";
|
const char SAM_DEST_REPLY[] = "DEST REPLY PUB=%s PRIV=%s\n";
|
||||||
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=%lu\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_MIN[] = "MIN";
|
const char SAM_PARAM_MIN[] = "MIN";
|
||||||
const char SAM_PARAM_MAX[] = "MAX";
|
const char SAM_PARAM_MAX[] = "MAX";
|
||||||
const char SAM_PARAM_STYLE[] = "STYLE";
|
const char SAM_PARAM_STYLE[] = "STYLE";
|
||||||
const char SAM_PARAM_ID[] = "ID";
|
const char SAM_PARAM_ID[] = "ID";
|
||||||
const char SAM_PARAM_SILENT[] = "SILENT";
|
const char SAM_PARAM_SILENT[] = "SILENT";
|
||||||
const char SAM_PARAM_DESTINATION[] = "DESTINATION";
|
const char SAM_PARAM_DESTINATION[] = "DESTINATION";
|
||||||
const char SAM_PARAM_NAME[] = "NAME";
|
const char SAM_PARAM_NAME[] = "NAME";
|
||||||
const char SAM_PARAM_SIGNATURE_TYPE[] = "SIGNATURE_TYPE";
|
const char SAM_PARAM_SIGNATURE_TYPE[] = "SIGNATURE_TYPE";
|
||||||
const char SAM_PARAM_SIZE[] = "SIZE";
|
const char SAM_PARAM_SIZE[] = "SIZE";
|
||||||
const char SAM_VALUE_TRANSIENT[] = "TRANSIENT";
|
const char SAM_VALUE_TRANSIENT[] = "TRANSIENT";
|
||||||
const char SAM_VALUE_STREAM[] = "STREAM";
|
const char SAM_VALUE_STREAM[] = "STREAM";
|
||||||
const char SAM_VALUE_DATAGRAM[] = "DATAGRAM";
|
const char SAM_VALUE_DATAGRAM[] = "DATAGRAM";
|
||||||
const char SAM_VALUE_RAW[] = "RAW";
|
const char SAM_VALUE_RAW[] = "RAW";
|
||||||
const char SAM_VALUE_TRUE[] = "true";
|
const char SAM_VALUE_TRUE[] = "true";
|
||||||
const char SAM_VALUE_FALSE[] = "false";
|
const char SAM_VALUE_FALSE[] = "false";
|
||||||
|
|
||||||
enum SAMSocketType
|
enum SAMSocketType
|
||||||
{
|
{
|
||||||
eSAMSocketTypeUnknown,
|
eSAMSocketTypeUnknown,
|
||||||
eSAMSocketTypeSession,
|
eSAMSocketTypeSession,
|
||||||
eSAMSocketTypeStream,
|
eSAMSocketTypeStream,
|
||||||
eSAMSocketTypeAcceptor,
|
eSAMSocketTypeAcceptor,
|
||||||
eSAMSocketTypeTerminated
|
eSAMSocketTypeTerminated
|
||||||
};
|
};
|
||||||
|
|
||||||
class SAMBridge;
|
class SAMBridge;
|
||||||
struct SAMSession;
|
struct SAMSession;
|
||||||
class SAMSocket: public std::enable_shared_from_this<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
|
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 ();
|
||||||
void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; };
|
void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; };
|
||||||
SAMSocketType GetSocketType () const { return m_SocketType; };
|
SAMSocketType GetSocketType () const { return m_SocketType; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void SendMessageReply (const char * msg, size_t len, bool close);
|
void SendMessageReply (const char * msg, size_t len, bool close);
|
||||||
void HandleMessageReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred, bool close);
|
void HandleMessageReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred, bool close);
|
||||||
void Receive ();
|
void Receive ();
|
||||||
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
|
|
||||||
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 (std::shared_ptr<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& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
void HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
void ProcessSessionCreate (char * buf, size_t len);
|
void ProcessSessionCreate (char * buf, size_t len);
|
||||||
void ProcessStreamConnect (char * buf, size_t len);
|
void ProcessStreamConnect (char * buf, size_t len);
|
||||||
void ProcessStreamAccept (char * buf, size_t len);
|
void ProcessStreamAccept (char * buf, size_t len);
|
||||||
void ProcessDestGenerate ();
|
void ProcessDestGenerate ();
|
||||||
void ProcessNamingLookup (char * buf, size_t len);
|
void ProcessNamingLookup (char * buf, size_t len);
|
||||||
size_t ProcessDatagramSend (char * buf, size_t len, const char * data); // from SAM 1.0
|
size_t ProcessDatagramSend (char * buf, size_t len, const char * data); // from SAM 1.0
|
||||||
void ExtractParams (char * buf, std::map<std::string, std::string>& params);
|
void ExtractParams (char * buf, std::map<std::string, std::string>& params);
|
||||||
|
|
||||||
void Connect (std::shared_ptr<const i2p::data::LeaseSet> remote);
|
void Connect (std::shared_ptr<const i2p::data::LeaseSet> remote);
|
||||||
void HandleConnectLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet);
|
void HandleConnectLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet);
|
||||||
void SendNamingLookupReply (const i2p::data::IdentityEx& identity);
|
void SendNamingLookupReply (const i2p::data::IdentityEx& identity);
|
||||||
void HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, i2p::data::IdentHash ident);
|
void HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, i2p::data::IdentHash ident);
|
||||||
void HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode);
|
void HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode);
|
||||||
void SendSessionCreateReplyOk ();
|
void SendSessionCreateReplyOk ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
SAMBridge& m_Owner;
|
SAMBridge& m_Owner;
|
||||||
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;
|
||||||
char m_Buffer[SAM_SOCKET_BUFFER_SIZE + 1];
|
char m_Buffer[SAM_SOCKET_BUFFER_SIZE + 1];
|
||||||
size_t m_BufferOffset;
|
size_t m_BufferOffset;
|
||||||
uint8_t m_StreamBuffer[SAM_SOCKET_BUFFER_SIZE];
|
uint8_t m_StreamBuffer[SAM_SOCKET_BUFFER_SIZE];
|
||||||
SAMSocketType m_SocketType;
|
SAMSocketType m_SocketType;
|
||||||
std::string m_ID; // nickname
|
std::string m_ID; // nickname
|
||||||
bool m_IsSilent;
|
bool m_IsSilent;
|
||||||
std::shared_ptr<i2p::stream::Stream> m_Stream;
|
std::shared_ptr<i2p::stream::Stream> m_Stream;
|
||||||
SAMSession * m_Session;
|
SAMSession * m_Session;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SAMSession
|
struct SAMSession
|
||||||
{
|
{
|
||||||
std::shared_ptr<ClientDestination> localDestination;
|
std::shared_ptr<ClientDestination> localDestination;
|
||||||
std::list<std::shared_ptr<SAMSocket> > sockets;
|
std::list<std::shared_ptr<SAMSocket> > sockets;
|
||||||
|
|
||||||
SAMSession (std::shared_ptr<ClientDestination> dest);
|
SAMSession (std::shared_ptr<ClientDestination> dest);
|
||||||
~SAMSession ();
|
~SAMSession ();
|
||||||
|
|
||||||
void CloseStreams ();
|
void CloseStreams ();
|
||||||
};
|
};
|
||||||
|
|
||||||
class SAMBridge
|
class SAMBridge
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SAMBridge (int port);
|
SAMBridge (int port);
|
||||||
~SAMBridge ();
|
~SAMBridge ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
boost::asio::io_service& GetService () { return m_Service; };
|
boost::asio::io_service& GetService () { return m_Service; };
|
||||||
SAMSession * CreateSession (const std::string& id, const std::string& destination, // empty string means transient
|
SAMSession * CreateSession (const std::string& id, const std::string& destination, // empty string means transient
|
||||||
const std::map<std::string, std::string> * params);
|
const std::map<std::string, std::string> * params);
|
||||||
void CloseSession (const std::string& id);
|
void CloseSession (const std::string& id);
|
||||||
SAMSession * FindSession (const std::string& id) const;
|
SAMSession * FindSession (const std::string& id) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
|
|
||||||
void Accept ();
|
void Accept ();
|
||||||
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<SAMSocket> socket);
|
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);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
boost::asio::io_service m_Service;
|
boost::asio::io_service m_Service;
|
||||||
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;
|
||||||
mutable std::mutex m_SessionsMutex;
|
mutable 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];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP
|
// for HTTP
|
||||||
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
|
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
22
SOCKS.h
22
SOCKS.h
|
@ -11,20 +11,20 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace proxy
|
namespace proxy
|
||||||
{
|
{
|
||||||
class SOCKSServer: public i2p::client::TCPIPAcceptor
|
class SOCKSServer: public i2p::client::TCPIPAcceptor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SOCKSServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
|
SOCKSServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
|
||||||
~SOCKSServer() {};
|
~SOCKSServer() {};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Implements TCPIPAcceptor
|
// Implements TCPIPAcceptor
|
||||||
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
||||||
const char* GetName() { return "SOCKS"; }
|
const char* GetName() { return "SOCKS"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef SOCKSServer SOCKSProxy;
|
typedef SOCKSServer SOCKSProxy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
152
SSU.h
152
SSU.h
|
@ -20,93 +20,93 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
|
const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
|
||||||
const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds
|
const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds
|
||||||
const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
|
const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
|
||||||
const size_t SSU_MAX_NUM_INTRODUCERS = 3;
|
const size_t SSU_MAX_NUM_INTRODUCERS = 3;
|
||||||
|
|
||||||
struct SSUPacket
|
struct SSUPacket
|
||||||
{
|
{
|
||||||
i2p::crypto::AESAlignedBuffer<1500> buf;
|
i2p::crypto::AESAlignedBuffer<1500> buf;
|
||||||
boost::asio::ip::udp::endpoint from;
|
boost::asio::ip::udp::endpoint from;
|
||||||
size_t len;
|
size_t len;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SSUServer
|
class SSUServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SSUServer (int port);
|
SSUServer (int port);
|
||||||
~SSUServer ();
|
~SSUServer ();
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
std::shared_ptr<SSUSession> GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
|
std::shared_ptr<SSUSession> GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
|
||||||
std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const;
|
std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const;
|
||||||
std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const;
|
std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const;
|
||||||
std::shared_ptr<SSUSession> GetRandomEstablishedSession (std::shared_ptr<const SSUSession> excluded);
|
std::shared_ptr<SSUSession> GetRandomEstablishedSession (std::shared_ptr<const SSUSession> excluded);
|
||||||
void DeleteSession (std::shared_ptr<SSUSession> session);
|
void DeleteSession (std::shared_ptr<SSUSession> session);
|
||||||
void DeleteAllSessions ();
|
void DeleteAllSessions ();
|
||||||
|
|
||||||
boost::asio::io_service& GetService () { return m_Service; };
|
boost::asio::io_service& GetService () { return m_Service; };
|
||||||
boost::asio::io_service& GetServiceV6 () { return m_ServiceV6; };
|
boost::asio::io_service& GetServiceV6 () { return m_ServiceV6; };
|
||||||
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);
|
||||||
std::shared_ptr<SSUSession> FindRelaySession (uint32_t tag);
|
std::shared_ptr<SSUSession> FindRelaySession (uint32_t tag);
|
||||||
|
|
||||||
void NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session = nullptr);
|
void NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session = nullptr);
|
||||||
PeerTestParticipant GetPeerTestParticipant (uint32_t nonce);
|
PeerTestParticipant GetPeerTestParticipant (uint32_t nonce);
|
||||||
std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce);
|
std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce);
|
||||||
void UpdatePeerTest (uint32_t nonce, PeerTestParticipant role);
|
void UpdatePeerTest (uint32_t nonce, PeerTestParticipant role);
|
||||||
void RemovePeerTest (uint32_t nonce);
|
void RemovePeerTest (uint32_t nonce);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void RunV6 ();
|
void RunV6 ();
|
||||||
void RunReceivers ();
|
void RunReceivers ();
|
||||||
void Receive ();
|
void Receive ();
|
||||||
void ReceiveV6 ();
|
void ReceiveV6 ();
|
||||||
void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
|
void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
|
||||||
void HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
|
void HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
|
||||||
void HandleReceivedPackets (std::vector<SSUPacket *> packets);
|
void HandleReceivedPackets (std::vector<SSUPacket *> packets);
|
||||||
|
|
||||||
template<typename Filter>
|
template<typename Filter>
|
||||||
std::shared_ptr<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 ();
|
||||||
void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode);
|
void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
void SchedulePeerTestsCleanupTimer ();
|
void SchedulePeerTestsCleanupTimer ();
|
||||||
void HandlePeerTestsCleanupTimer (const boost::system::error_code& ecode);
|
void HandlePeerTestsCleanupTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct PeerTest
|
struct PeerTest
|
||||||
{
|
{
|
||||||
uint64_t creationTime;
|
uint64_t creationTime;
|
||||||
PeerTestParticipant role;
|
PeerTestParticipant role;
|
||||||
std::shared_ptr<SSUSession> session; // for Bob to Alice
|
std::shared_ptr<SSUSession> session; // for Bob to Alice
|
||||||
};
|
};
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::thread * m_Thread, * m_ThreadV6, * m_ReceiversThread;
|
std::thread * m_Thread, * m_ThreadV6, * m_ReceiversThread;
|
||||||
boost::asio::io_service m_Service, m_ServiceV6, m_ReceiversService;
|
boost::asio::io_service m_Service, m_ServiceV6, m_ReceiversService;
|
||||||
boost::asio::io_service::work m_Work, m_WorkV6, m_ReceiversWork;
|
boost::asio::io_service::work m_Work, m_WorkV6, m_ReceiversWork;
|
||||||
boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6;
|
boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6;
|
||||||
boost::asio::ip::udp::socket m_Socket, m_SocketV6;
|
boost::asio::ip::udp::socket m_Socket, m_SocketV6;
|
||||||
boost::asio::deadline_timer m_IntroducersUpdateTimer, m_PeerTestsCleanupTimer;
|
boost::asio::deadline_timer m_IntroducersUpdateTimer, m_PeerTestsCleanupTimer;
|
||||||
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
|
||||||
mutable std::mutex m_SessionsMutex;
|
mutable std::mutex m_SessionsMutex;
|
||||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<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
|
||||||
std::map<uint32_t, PeerTest> m_PeerTests; // nonce -> creation time in milliseconds
|
std::map<uint32_t, PeerTest> m_PeerTests; // nonce -> creation time in milliseconds
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
|
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
938
SSUData.cpp
938
SSUData.cpp
|
@ -10,498 +10,498 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
void IncompleteMessage::AttachNextFragment (const uint8_t * fragment, size_t fragmentSize)
|
void IncompleteMessage::AttachNextFragment (const uint8_t * fragment, size_t fragmentSize)
|
||||||
{
|
{
|
||||||
if (msg->len + fragmentSize > msg->maxLen)
|
if (msg->len + fragmentSize > msg->maxLen)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "SSU I2NP message size ", msg->maxLen, " is not enough");
|
LogPrint (eLogInfo, "SSU I2NP message size ", msg->maxLen, " is not enough");
|
||||||
auto newMsg = ToSharedI2NPMessage(NewI2NPMessage ());
|
auto newMsg = ToSharedI2NPMessage(NewI2NPMessage ());
|
||||||
*newMsg = *msg;
|
*newMsg = *msg;
|
||||||
msg = newMsg;
|
msg = newMsg;
|
||||||
}
|
}
|
||||||
memcpy (msg->buf + msg->len, fragment, fragmentSize);
|
memcpy (msg->buf + msg->len, fragment, fragmentSize);
|
||||||
msg->len += fragmentSize;
|
msg->len += fragmentSize;
|
||||||
nextFragmentNum++;
|
nextFragmentNum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSUData::SSUData (SSUSession& session):
|
SSUData::SSUData (SSUSession& session):
|
||||||
m_Session (session), m_ResendTimer (session.GetService ()), m_DecayTimer (session.GetService ()),
|
m_Session (session), m_ResendTimer (session.GetService ()), m_DecayTimer (session.GetService ()),
|
||||||
m_IncompleteMessagesCleanupTimer (session.GetService ())
|
m_IncompleteMessagesCleanupTimer (session.GetService ())
|
||||||
{
|
{
|
||||||
m_MaxPacketSize = session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE;
|
m_MaxPacketSize = session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE;
|
||||||
m_PacketSize = m_MaxPacketSize;
|
m_PacketSize = m_MaxPacketSize;
|
||||||
auto remoteRouter = session.GetRemoteRouter ();
|
auto remoteRouter = session.GetRemoteRouter ();
|
||||||
if (remoteRouter)
|
if (remoteRouter)
|
||||||
AdjustPacketSize (*remoteRouter);
|
AdjustPacketSize (*remoteRouter);
|
||||||
}
|
}
|
||||||
|
|
||||||
SSUData::~SSUData ()
|
SSUData::~SSUData ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::Start ()
|
void SSUData::Start ()
|
||||||
{
|
{
|
||||||
ScheduleIncompleteMessagesCleanup ();
|
ScheduleIncompleteMessagesCleanup ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::Stop ()
|
void SSUData::Stop ()
|
||||||
{
|
{
|
||||||
m_ResendTimer.cancel ();
|
m_ResendTimer.cancel ();
|
||||||
m_DecayTimer.cancel ();
|
m_DecayTimer.cancel ();
|
||||||
m_IncompleteMessagesCleanupTimer.cancel ();
|
m_IncompleteMessagesCleanupTimer.cancel ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::AdjustPacketSize (const i2p::data::RouterInfo& remoteRouter)
|
void SSUData::AdjustPacketSize (const i2p::data::RouterInfo& remoteRouter)
|
||||||
{
|
{
|
||||||
auto ssuAddress = remoteRouter.GetSSUAddress ();
|
auto ssuAddress = remoteRouter.GetSSUAddress ();
|
||||||
if (ssuAddress && ssuAddress->mtu)
|
if (ssuAddress && ssuAddress->mtu)
|
||||||
{
|
{
|
||||||
if (m_Session.IsV6 ())
|
if (m_Session.IsV6 ())
|
||||||
m_PacketSize = ssuAddress->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE;
|
m_PacketSize = ssuAddress->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE;
|
||||||
else
|
else
|
||||||
m_PacketSize = ssuAddress->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE;
|
m_PacketSize = ssuAddress->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE;
|
||||||
if (m_PacketSize > 0)
|
if (m_PacketSize > 0)
|
||||||
{
|
{
|
||||||
// make sure packet size multiple of 16
|
// make sure packet size multiple of 16
|
||||||
m_PacketSize >>= 4;
|
m_PacketSize >>= 4;
|
||||||
m_PacketSize <<= 4;
|
m_PacketSize <<= 4;
|
||||||
if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize;
|
if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize;
|
||||||
LogPrint ("MTU=", ssuAddress->mtu, " packet size=", m_PacketSize);
|
LogPrint ("MTU=", ssuAddress->mtu, " packet size=", m_PacketSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Unexpected MTU ", ssuAddress->mtu);
|
LogPrint (eLogWarning, "Unexpected MTU ", ssuAddress->mtu);
|
||||||
m_PacketSize = m_MaxPacketSize;
|
m_PacketSize = m_MaxPacketSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::UpdatePacketSize (const i2p::data::IdentHash& remoteIdent)
|
void SSUData::UpdatePacketSize (const i2p::data::IdentHash& remoteIdent)
|
||||||
{
|
{
|
||||||
auto routerInfo = i2p::data::netdb.FindRouter (remoteIdent);
|
auto routerInfo = i2p::data::netdb.FindRouter (remoteIdent);
|
||||||
if (routerInfo)
|
if (routerInfo)
|
||||||
AdjustPacketSize (*routerInfo);
|
AdjustPacketSize (*routerInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::ProcessSentMessageAck (uint32_t msgID)
|
void SSUData::ProcessSentMessageAck (uint32_t msgID)
|
||||||
{
|
{
|
||||||
auto it = m_SentMessages.find (msgID);
|
auto it = m_SentMessages.find (msgID);
|
||||||
if (it != m_SentMessages.end ())
|
if (it != m_SentMessages.end ())
|
||||||
{
|
{
|
||||||
m_SentMessages.erase (it);
|
m_SentMessages.erase (it);
|
||||||
if (m_SentMessages.empty ())
|
if (m_SentMessages.empty ())
|
||||||
m_ResendTimer.cancel ();
|
m_ResendTimer.cancel ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag)
|
void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag)
|
||||||
{
|
{
|
||||||
if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED)
|
if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED)
|
||||||
{
|
{
|
||||||
// explicit ACKs
|
// explicit ACKs
|
||||||
uint8_t numAcks =*buf;
|
uint8_t numAcks =*buf;
|
||||||
buf++;
|
buf++;
|
||||||
for (int i = 0; i < numAcks; i++)
|
for (int i = 0; i < numAcks; i++)
|
||||||
ProcessSentMessageAck (bufbe32toh (buf+i*4));
|
ProcessSentMessageAck (bufbe32toh (buf+i*4));
|
||||||
buf += numAcks*4;
|
buf += numAcks*4;
|
||||||
}
|
}
|
||||||
if (flag & DATA_FLAG_ACK_BITFIELDS_INCLUDED)
|
if (flag & DATA_FLAG_ACK_BITFIELDS_INCLUDED)
|
||||||
{
|
{
|
||||||
// explicit ACK bitfields
|
// explicit ACK bitfields
|
||||||
uint8_t numBitfields =*buf;
|
uint8_t numBitfields =*buf;
|
||||||
buf++;
|
buf++;
|
||||||
for (int i = 0; i < numBitfields; i++)
|
for (int i = 0; i < numBitfields; i++)
|
||||||
{
|
{
|
||||||
uint32_t msgID = bufbe32toh (buf);
|
uint32_t msgID = bufbe32toh (buf);
|
||||||
buf += 4; // msgID
|
buf += 4; // msgID
|
||||||
auto it = m_SentMessages.find (msgID);
|
auto it = m_SentMessages.find (msgID);
|
||||||
// process individual Ack bitfields
|
// process individual Ack bitfields
|
||||||
bool isNonLast = false;
|
bool isNonLast = false;
|
||||||
int fragment = 0;
|
int fragment = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
uint8_t bitfield = *buf;
|
uint8_t bitfield = *buf;
|
||||||
isNonLast = bitfield & 0x80;
|
isNonLast = bitfield & 0x80;
|
||||||
bitfield &= 0x7F; // clear MSB
|
bitfield &= 0x7F; // clear MSB
|
||||||
if (bitfield && it != m_SentMessages.end ())
|
if (bitfield && it != m_SentMessages.end ())
|
||||||
{
|
{
|
||||||
int numSentFragments = it->second->fragments.size ();
|
int numSentFragments = it->second->fragments.size ();
|
||||||
// process bits
|
// process bits
|
||||||
uint8_t mask = 0x01;
|
uint8_t mask = 0x01;
|
||||||
for (int j = 0; j < 7; j++)
|
for (int j = 0; j < 7; j++)
|
||||||
{
|
{
|
||||||
if (bitfield & mask)
|
if (bitfield & mask)
|
||||||
{
|
{
|
||||||
if (fragment < numSentFragments)
|
if (fragment < numSentFragments)
|
||||||
it->second->fragments[fragment].reset (nullptr);
|
it->second->fragments[fragment].reset (nullptr);
|
||||||
}
|
}
|
||||||
fragment++;
|
fragment++;
|
||||||
mask <<= 1;
|
mask <<= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf++;
|
buf++;
|
||||||
}
|
}
|
||||||
while (isNonLast);
|
while (isNonLast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::ProcessFragments (uint8_t * buf)
|
void SSUData::ProcessFragments (uint8_t * buf)
|
||||||
{
|
{
|
||||||
uint8_t numFragments = *buf; // number of fragments
|
uint8_t numFragments = *buf; // number of fragments
|
||||||
buf++;
|
buf++;
|
||||||
for (int i = 0; i < numFragments; i++)
|
for (int i = 0; i < numFragments; i++)
|
||||||
{
|
{
|
||||||
uint32_t msgID = bufbe32toh (buf); // message ID
|
uint32_t msgID = bufbe32toh (buf); // message ID
|
||||||
buf += 4;
|
buf += 4;
|
||||||
uint8_t frag[4];
|
uint8_t frag[4];
|
||||||
frag[0] = 0;
|
frag[0] = 0;
|
||||||
memcpy (frag + 1, buf, 3);
|
memcpy (frag + 1, buf, 3);
|
||||||
buf += 3;
|
buf += 3;
|
||||||
uint32_t fragmentInfo = bufbe32toh (frag); // fragment info
|
uint32_t fragmentInfo = bufbe32toh (frag); // fragment info
|
||||||
uint16_t fragmentSize = fragmentInfo & 0x1FFF; // bits 0 - 13
|
uint16_t fragmentSize = fragmentInfo & 0x1FFF; // bits 0 - 13
|
||||||
bool isLast = fragmentInfo & 0x010000; // bit 16
|
bool isLast = fragmentInfo & 0x010000; // bit 16
|
||||||
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
|
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
|
||||||
if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE)
|
if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Fragment size ", fragmentSize, "exceeds max SSU packet size");
|
LogPrint (eLogError, "Fragment size ", fragmentSize, "exceeds max SSU packet size");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// find message with msgID
|
// find message with msgID
|
||||||
auto it = m_IncompleteMessages.find (msgID);
|
auto it = m_IncompleteMessages.find (msgID);
|
||||||
if (it == m_IncompleteMessages.end ())
|
if (it == m_IncompleteMessages.end ())
|
||||||
{
|
{
|
||||||
// create new message
|
// create new message
|
||||||
auto msg = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
auto msg = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
||||||
msg->len -= I2NP_SHORT_HEADER_SIZE;
|
msg->len -= I2NP_SHORT_HEADER_SIZE;
|
||||||
it = m_IncompleteMessages.insert (std::make_pair (msgID,
|
it = m_IncompleteMessages.insert (std::make_pair (msgID,
|
||||||
std::unique_ptr<IncompleteMessage>(new IncompleteMessage (msg)))).first;
|
std::unique_ptr<IncompleteMessage>(new IncompleteMessage (msg)))).first;
|
||||||
}
|
}
|
||||||
std::unique_ptr<IncompleteMessage>& incompleteMessage = it->second;
|
std::unique_ptr<IncompleteMessage>& incompleteMessage = it->second;
|
||||||
|
|
||||||
// handle current fragment
|
// handle current fragment
|
||||||
if (fragmentNum == incompleteMessage->nextFragmentNum)
|
if (fragmentNum == incompleteMessage->nextFragmentNum)
|
||||||
{
|
{
|
||||||
// expected fragment
|
// expected fragment
|
||||||
incompleteMessage->AttachNextFragment (buf, fragmentSize);
|
incompleteMessage->AttachNextFragment (buf, fragmentSize);
|
||||||
if (!isLast && !incompleteMessage->savedFragments.empty ())
|
if (!isLast && !incompleteMessage->savedFragments.empty ())
|
||||||
{
|
{
|
||||||
// try saved fragments
|
// try saved fragments
|
||||||
for (auto it1 = incompleteMessage->savedFragments.begin (); it1 != incompleteMessage->savedFragments.end ();)
|
for (auto it1 = incompleteMessage->savedFragments.begin (); it1 != incompleteMessage->savedFragments.end ();)
|
||||||
{
|
{
|
||||||
auto& savedFragment = *it1;
|
auto& savedFragment = *it1;
|
||||||
if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum)
|
if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum)
|
||||||
{
|
{
|
||||||
incompleteMessage->AttachNextFragment (savedFragment->buf, savedFragment->len);
|
incompleteMessage->AttachNextFragment (savedFragment->buf, savedFragment->len);
|
||||||
isLast = savedFragment->isLast;
|
isLast = savedFragment->isLast;
|
||||||
incompleteMessage->savedFragments.erase (it1++);
|
incompleteMessage->savedFragments.erase (it1++);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (isLast)
|
if (isLast)
|
||||||
LogPrint (eLogDebug, "Message ", msgID, " complete");
|
LogPrint (eLogDebug, "Message ", msgID, " complete");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (fragmentNum < incompleteMessage->nextFragmentNum)
|
if (fragmentNum < incompleteMessage->nextFragmentNum)
|
||||||
// duplicate fragment
|
// duplicate fragment
|
||||||
LogPrint (eLogWarning, "Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ". Ignored");
|
LogPrint (eLogWarning, "Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ". Ignored");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// missing fragment
|
// missing fragment
|
||||||
LogPrint (eLogWarning, "Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
|
LogPrint (eLogWarning, "Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
|
||||||
auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast);
|
auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast);
|
||||||
if (incompleteMessage->savedFragments.insert (std::unique_ptr<Fragment>(savedFragment)).second)
|
if (incompleteMessage->savedFragments.insert (std::unique_ptr<Fragment>(savedFragment)).second)
|
||||||
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
|
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
|
LogPrint (eLogWarning, "Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
|
||||||
}
|
}
|
||||||
isLast = false;
|
isLast = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLast)
|
if (isLast)
|
||||||
{
|
{
|
||||||
// delete incomplete message
|
// delete incomplete message
|
||||||
auto msg = incompleteMessage->msg;
|
auto msg = incompleteMessage->msg;
|
||||||
incompleteMessage->msg = nullptr;
|
incompleteMessage->msg = nullptr;
|
||||||
m_IncompleteMessages.erase (msgID);
|
m_IncompleteMessages.erase (msgID);
|
||||||
// process message
|
// process message
|
||||||
SendMsgAck (msgID);
|
SendMsgAck (msgID);
|
||||||
msg->FromSSU (msgID);
|
msg->FromSSU (msgID);
|
||||||
if (m_Session.GetState () == eSessionStateEstablished)
|
if (m_Session.GetState () == eSessionStateEstablished)
|
||||||
{
|
{
|
||||||
if (!m_ReceivedMessages.count (msgID))
|
if (!m_ReceivedMessages.count (msgID))
|
||||||
{
|
{
|
||||||
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES)
|
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES)
|
||||||
m_ReceivedMessages.clear ();
|
m_ReceivedMessages.clear ();
|
||||||
else
|
else
|
||||||
ScheduleDecay ();
|
ScheduleDecay ();
|
||||||
m_ReceivedMessages.insert (msgID);
|
m_ReceivedMessages.insert (msgID);
|
||||||
m_Handler.PutNextMessage (msg);
|
m_Handler.PutNextMessage (msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "SSU message ", msgID, " already received");
|
LogPrint (eLogWarning, "SSU message ", msgID, " already received");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we expect DeliveryStatus
|
// we expect DeliveryStatus
|
||||||
if (msg->GetTypeID () == eI2NPDeliveryStatus)
|
if (msg->GetTypeID () == eI2NPDeliveryStatus)
|
||||||
{
|
{
|
||||||
LogPrint ("SSU session established");
|
LogPrint ("SSU session established");
|
||||||
m_Session.Established ();
|
m_Session.Established ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "SSU unexpected message ", (int)msg->GetTypeID ());
|
LogPrint (eLogError, "SSU unexpected message ", (int)msg->GetTypeID ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SendFragmentAck (msgID, fragmentNum);
|
SendFragmentAck (msgID, fragmentNum);
|
||||||
buf += fragmentSize;
|
buf += fragmentSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::FlushReceivedMessage ()
|
void SSUData::FlushReceivedMessage ()
|
||||||
{
|
{
|
||||||
m_Handler.Flush ();
|
m_Handler.Flush ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::ProcessMessage (uint8_t * buf, size_t len)
|
void SSUData::ProcessMessage (uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
//uint8_t * start = buf;
|
//uint8_t * start = buf;
|
||||||
uint8_t flag = *buf;
|
uint8_t flag = *buf;
|
||||||
buf++;
|
buf++;
|
||||||
LogPrint (eLogDebug, "Process SSU data flags=", (int)flag, " len=", len);
|
LogPrint (eLogDebug, "Process SSU data flags=", (int)flag, " len=", len);
|
||||||
// process acks if presented
|
// process acks if presented
|
||||||
if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED))
|
if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED))
|
||||||
ProcessAcks (buf, flag);
|
ProcessAcks (buf, flag);
|
||||||
// extended data if presented
|
// extended data if presented
|
||||||
if (flag & DATA_FLAG_EXTENDED_DATA_INCLUDED)
|
if (flag & DATA_FLAG_EXTENDED_DATA_INCLUDED)
|
||||||
{
|
{
|
||||||
uint8_t extendedDataSize = *buf;
|
uint8_t extendedDataSize = *buf;
|
||||||
buf++; // size
|
buf++; // size
|
||||||
LogPrint (eLogDebug, "SSU extended data of ", extendedDataSize, " bytes presented");
|
LogPrint (eLogDebug, "SSU extended data of ", extendedDataSize, " bytes presented");
|
||||||
buf += extendedDataSize;
|
buf += extendedDataSize;
|
||||||
}
|
}
|
||||||
// process data
|
// process data
|
||||||
ProcessFragments (buf);
|
ProcessFragments (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::Send (std::shared_ptr<i2p::I2NPMessage> msg)
|
void SSUData::Send (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
uint32_t msgID = msg->ToSSU ();
|
uint32_t msgID = msg->ToSSU ();
|
||||||
if (m_SentMessages.count (msgID) > 0)
|
if (m_SentMessages.count (msgID) > 0)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "SSU message ", msgID, " already sent");
|
LogPrint (eLogWarning, "SSU message ", msgID, " already sent");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_SentMessages.empty ()) // schedule resend at first message only
|
if (m_SentMessages.empty ()) // schedule resend at first message only
|
||||||
ScheduleResend ();
|
ScheduleResend ();
|
||||||
|
|
||||||
auto ret = m_SentMessages.insert (std::make_pair (msgID, std::unique_ptr<SentMessage>(new SentMessage)));
|
auto ret = m_SentMessages.insert (std::make_pair (msgID, std::unique_ptr<SentMessage>(new SentMessage)));
|
||||||
std::unique_ptr<SentMessage>& sentMessage = ret.first->second;
|
std::unique_ptr<SentMessage>& sentMessage = ret.first->second;
|
||||||
if (ret.second)
|
if (ret.second)
|
||||||
{
|
{
|
||||||
sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL;
|
sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL;
|
||||||
sentMessage->numResends = 0;
|
sentMessage->numResends = 0;
|
||||||
}
|
}
|
||||||
auto& fragments = sentMessage->fragments;
|
auto& fragments = sentMessage->fragments;
|
||||||
size_t payloadSize = m_PacketSize - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
|
size_t payloadSize = m_PacketSize - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
|
||||||
size_t len = msg->GetLength ();
|
size_t len = msg->GetLength ();
|
||||||
uint8_t * msgBuf = msg->GetSSUHeader ();
|
uint8_t * msgBuf = msg->GetSSUHeader ();
|
||||||
|
|
||||||
uint32_t fragmentNum = 0;
|
uint32_t fragmentNum = 0;
|
||||||
while (len > 0)
|
while (len > 0)
|
||||||
{
|
{
|
||||||
Fragment * fragment = new Fragment;
|
Fragment * fragment = new Fragment;
|
||||||
fragment->fragmentNum = fragmentNum;
|
fragment->fragmentNum = fragmentNum;
|
||||||
uint8_t * buf = fragment->buf;
|
uint8_t * buf = fragment->buf;
|
||||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
|
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
|
||||||
payload++;
|
payload++;
|
||||||
*payload = 1; // always 1 message fragment per message
|
*payload = 1; // always 1 message fragment per message
|
||||||
payload++;
|
payload++;
|
||||||
htobe32buf (payload, msgID);
|
htobe32buf (payload, msgID);
|
||||||
payload += 4;
|
payload += 4;
|
||||||
bool isLast = (len <= payloadSize);
|
bool isLast = (len <= payloadSize);
|
||||||
size_t size = isLast ? len : payloadSize;
|
size_t size = isLast ? len : payloadSize;
|
||||||
uint32_t fragmentInfo = (fragmentNum << 17);
|
uint32_t fragmentInfo = (fragmentNum << 17);
|
||||||
if (isLast)
|
if (isLast)
|
||||||
fragmentInfo |= 0x010000;
|
fragmentInfo |= 0x010000;
|
||||||
|
|
||||||
fragmentInfo |= size;
|
fragmentInfo |= size;
|
||||||
fragmentInfo = htobe32 (fragmentInfo);
|
fragmentInfo = htobe32 (fragmentInfo);
|
||||||
memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3);
|
memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3);
|
||||||
payload += 3;
|
payload += 3;
|
||||||
memcpy (payload, msgBuf, size);
|
memcpy (payload, msgBuf, size);
|
||||||
|
|
||||||
size += payload - buf;
|
size += payload - buf;
|
||||||
if (size & 0x0F) // make sure 16 bytes boundary
|
if (size & 0x0F) // make sure 16 bytes boundary
|
||||||
size = ((size >> 4) + 1) << 4; // (/16 + 1)*16
|
size = ((size >> 4) + 1) << 4; // (/16 + 1)*16
|
||||||
fragment->len = size;
|
fragment->len = size;
|
||||||
fragments.push_back (std::unique_ptr<Fragment> (fragment));
|
fragments.push_back (std::unique_ptr<Fragment> (fragment));
|
||||||
|
|
||||||
// encrypt message with session key
|
// encrypt message with session key
|
||||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size);
|
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_Session.Send (buf, size);
|
m_Session.Send (buf, size);
|
||||||
}
|
}
|
||||||
catch (boost::system::system_error& ec)
|
catch (boost::system::system_error& ec)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Can't send SSU fragment ", ec.what ());
|
LogPrint (eLogError, "Can't send SSU fragment ", ec.what ());
|
||||||
}
|
}
|
||||||
if (!isLast)
|
if (!isLast)
|
||||||
{
|
{
|
||||||
len -= payloadSize;
|
len -= payloadSize;
|
||||||
msgBuf += payloadSize;
|
msgBuf += payloadSize;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
len = 0;
|
len = 0;
|
||||||
fragmentNum++;
|
fragmentNum++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::SendMsgAck (uint32_t msgID)
|
void SSUData::SendMsgAck (uint32_t msgID)
|
||||||
{
|
{
|
||||||
uint8_t buf[48 + 18]; // actual length is 44 = 37 + 7 but pad it to multiple of 16
|
uint8_t buf[48 + 18]; // actual length is 44 = 37 + 7 but pad it to multiple of 16
|
||||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
*payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag
|
*payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag
|
||||||
payload++;
|
payload++;
|
||||||
*payload = 1; // number of ACKs
|
*payload = 1; // number of ACKs
|
||||||
payload++;
|
payload++;
|
||||||
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
|
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
|
||||||
payload += 4;
|
payload += 4;
|
||||||
*payload = 0; // number of fragments
|
*payload = 0; // number of fragments
|
||||||
|
|
||||||
// encrypt message with session key
|
// encrypt message with session key
|
||||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
|
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
|
||||||
m_Session.Send (buf, 48);
|
m_Session.Send (buf, 48);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::SendFragmentAck (uint32_t msgID, int fragmentNum)
|
void SSUData::SendFragmentAck (uint32_t msgID, int fragmentNum)
|
||||||
{
|
{
|
||||||
if (fragmentNum > 64)
|
if (fragmentNum > 64)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Fragment number ", fragmentNum, " exceeds 64");
|
LogPrint (eLogWarning, "Fragment number ", fragmentNum, " exceeds 64");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint8_t buf[64 + 18];
|
uint8_t buf[64 + 18];
|
||||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
*payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag
|
*payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag
|
||||||
payload++;
|
payload++;
|
||||||
*payload = 1; // number of ACK bitfields
|
*payload = 1; // number of ACK bitfields
|
||||||
payload++;
|
payload++;
|
||||||
// one ack
|
// one ack
|
||||||
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
|
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
|
||||||
payload += 4;
|
payload += 4;
|
||||||
div_t d = div (fragmentNum, 7);
|
div_t d = div (fragmentNum, 7);
|
||||||
memset (payload, 0x80, d.quot); // 0x80 means non-last
|
memset (payload, 0x80, d.quot); // 0x80 means non-last
|
||||||
payload += d.quot;
|
payload += d.quot;
|
||||||
*payload = 0x01 << d.rem; // set corresponding bit
|
*payload = 0x01 << d.rem; // set corresponding bit
|
||||||
payload++;
|
payload++;
|
||||||
*payload = 0; // number of fragments
|
*payload = 0; // number of fragments
|
||||||
|
|
||||||
size_t len = d.quot < 4 ? 48 : 64; // 48 = 37 + 7 + 4 (3+1)
|
size_t len = d.quot < 4 ? 48 : 64; // 48 = 37 + 7 + 4 (3+1)
|
||||||
// encrypt message with session key
|
// encrypt message with session key
|
||||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len);
|
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len);
|
||||||
m_Session.Send (buf, len);
|
m_Session.Send (buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::ScheduleResend()
|
void SSUData::ScheduleResend()
|
||||||
{
|
{
|
||||||
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));
|
||||||
auto s = m_Session.shared_from_this();
|
auto s = m_Session.shared_from_this();
|
||||||
m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode)
|
m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode)
|
||||||
{ s->m_Data.HandleResendTimer (ecode); });
|
{ s->m_Data.HandleResendTimer (ecode); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::HandleResendTimer (const boost::system::error_code& ecode)
|
void SSUData::HandleResendTimer (const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
|
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
|
||||||
{
|
{
|
||||||
if (ts >= it->second->nextResendTime)
|
if (ts >= it->second->nextResendTime)
|
||||||
{
|
{
|
||||||
if (it->second->numResends < MAX_NUM_RESENDS)
|
if (it->second->numResends < MAX_NUM_RESENDS)
|
||||||
{
|
{
|
||||||
for (auto& f: it->second->fragments)
|
for (auto& f: it->second->fragments)
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_Session.Send (f->buf, f->len); // resend
|
m_Session.Send (f->buf, f->len); // resend
|
||||||
}
|
}
|
||||||
catch (boost::system::system_error& ec)
|
catch (boost::system::system_error& ec)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Can't resend SSU fragment ", ec.what ());
|
LogPrint (eLogError, "Can't resend SSU fragment ", ec.what ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
it->second->numResends++;
|
it->second->numResends++;
|
||||||
it->second->nextResendTime += it->second->numResends*RESEND_INTERVAL;
|
it->second->nextResendTime += it->second->numResends*RESEND_INTERVAL;
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "SSU message has not been ACKed after ", MAX_NUM_RESENDS, " attempts. Deleted");
|
LogPrint (eLogError, "SSU message has not been ACKed after ", MAX_NUM_RESENDS, " attempts. Deleted");
|
||||||
it = m_SentMessages.erase (it);
|
it = m_SentMessages.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
ScheduleResend ();
|
ScheduleResend ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::ScheduleDecay ()
|
void SSUData::ScheduleDecay ()
|
||||||
{
|
{
|
||||||
m_DecayTimer.cancel ();
|
m_DecayTimer.cancel ();
|
||||||
m_DecayTimer.expires_from_now (boost::posix_time::seconds(DECAY_INTERVAL));
|
m_DecayTimer.expires_from_now (boost::posix_time::seconds(DECAY_INTERVAL));
|
||||||
auto s = m_Session.shared_from_this();
|
auto s = m_Session.shared_from_this();
|
||||||
m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode)
|
m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode)
|
||||||
{ s->m_Data.HandleDecayTimer (ecode); });
|
{ s->m_Data.HandleDecayTimer (ecode); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::HandleDecayTimer (const boost::system::error_code& ecode)
|
void SSUData::HandleDecayTimer (const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
m_ReceivedMessages.clear ();
|
m_ReceivedMessages.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::ScheduleIncompleteMessagesCleanup ()
|
void SSUData::ScheduleIncompleteMessagesCleanup ()
|
||||||
{
|
{
|
||||||
m_IncompleteMessagesCleanupTimer.cancel ();
|
m_IncompleteMessagesCleanupTimer.cancel ();
|
||||||
m_IncompleteMessagesCleanupTimer.expires_from_now (boost::posix_time::seconds(INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT));
|
m_IncompleteMessagesCleanupTimer.expires_from_now (boost::posix_time::seconds(INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT));
|
||||||
auto s = m_Session.shared_from_this();
|
auto s = m_Session.shared_from_this();
|
||||||
m_IncompleteMessagesCleanupTimer.async_wait ([s](const boost::system::error_code& ecode)
|
m_IncompleteMessagesCleanupTimer.async_wait ([s](const boost::system::error_code& ecode)
|
||||||
{ s->m_Data.HandleIncompleteMessagesCleanupTimer (ecode); });
|
{ s->m_Data.HandleIncompleteMessagesCleanupTimer (ecode); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode)
|
void SSUData::HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();)
|
for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();)
|
||||||
{
|
{
|
||||||
if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT)
|
if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "SSU message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds. Deleted");
|
LogPrint (eLogError, "SSU message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds. Deleted");
|
||||||
it = m_IncompleteMessages.erase (it);
|
it = m_IncompleteMessages.erase (it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
ScheduleIncompleteMessagesCleanup ();
|
ScheduleIncompleteMessagesCleanup ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
182
SSUData.h
182
SSUData.h
|
@ -17,110 +17,110 @@ namespace i2p
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
|
|
||||||
const size_t SSU_MTU_V4 = 1484;
|
const size_t SSU_MTU_V4 = 1484;
|
||||||
const size_t SSU_MTU_V6 = 1472;
|
const size_t SSU_MTU_V6 = 1472;
|
||||||
const size_t IPV4_HEADER_SIZE = 20;
|
const size_t IPV4_HEADER_SIZE = 20;
|
||||||
const size_t IPV6_HEADER_SIZE = 40;
|
const size_t IPV6_HEADER_SIZE = 40;
|
||||||
const size_t UDP_HEADER_SIZE = 8;
|
const size_t UDP_HEADER_SIZE = 8;
|
||||||
const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456
|
const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456
|
||||||
const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1424
|
const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1424
|
||||||
const int RESEND_INTERVAL = 3; // in seconds
|
const int RESEND_INTERVAL = 3; // in seconds
|
||||||
const int MAX_NUM_RESENDS = 5;
|
const int MAX_NUM_RESENDS = 5;
|
||||||
const int DECAY_INTERVAL = 20; // in seconds
|
const int DECAY_INTERVAL = 20; // in seconds
|
||||||
const int MAX_NUM_RECEIVED_MESSAGES = 1000; // how many msgID we store for duplicates check
|
const int MAX_NUM_RECEIVED_MESSAGES = 1000; // how many msgID we store for duplicates check
|
||||||
const int INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
|
const int INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
|
||||||
// data flags
|
// data flags
|
||||||
const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
|
const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
|
||||||
const uint8_t DATA_FLAG_WANT_REPLY = 0x04;
|
const uint8_t DATA_FLAG_WANT_REPLY = 0x04;
|
||||||
const uint8_t DATA_FLAG_REQUEST_PREVIOUS_ACKS = 0x08;
|
const uint8_t DATA_FLAG_REQUEST_PREVIOUS_ACKS = 0x08;
|
||||||
const uint8_t DATA_FLAG_EXPLICIT_CONGESTION_NOTIFICATION = 0x10;
|
const uint8_t DATA_FLAG_EXPLICIT_CONGESTION_NOTIFICATION = 0x10;
|
||||||
const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
|
const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
|
||||||
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
|
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
|
||||||
|
|
||||||
struct Fragment
|
struct Fragment
|
||||||
{
|
{
|
||||||
int fragmentNum;
|
int fragmentNum;
|
||||||
size_t len;
|
size_t len;
|
||||||
bool isLast;
|
bool isLast;
|
||||||
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest
|
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest
|
||||||
|
|
||||||
Fragment () = default;
|
Fragment () = default;
|
||||||
Fragment (int n, const uint8_t * b, int l, bool last):
|
Fragment (int n, const uint8_t * b, int l, bool last):
|
||||||
fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); };
|
fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FragmentCmp
|
struct FragmentCmp
|
||||||
{
|
{
|
||||||
bool operator() (const std::unique_ptr<Fragment>& f1, const std::unique_ptr<Fragment>& f2) const
|
bool operator() (const std::unique_ptr<Fragment>& f1, const std::unique_ptr<Fragment>& f2) const
|
||||||
{
|
{
|
||||||
return f1->fragmentNum < f2->fragmentNum;
|
return f1->fragmentNum < f2->fragmentNum;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IncompleteMessage
|
struct IncompleteMessage
|
||||||
{
|
{
|
||||||
std::shared_ptr<I2NPMessage> msg;
|
std::shared_ptr<I2NPMessage> msg;
|
||||||
int nextFragmentNum;
|
int nextFragmentNum;
|
||||||
uint32_t lastFragmentInsertTime; // in seconds
|
uint32_t lastFragmentInsertTime; // in seconds
|
||||||
std::set<std::unique_ptr<Fragment>, FragmentCmp> savedFragments;
|
std::set<std::unique_ptr<Fragment>, FragmentCmp> savedFragments;
|
||||||
|
|
||||||
IncompleteMessage (std::shared_ptr<I2NPMessage> m): msg (m), nextFragmentNum (0), lastFragmentInsertTime (0) {};
|
IncompleteMessage (std::shared_ptr<I2NPMessage> m): msg (m), nextFragmentNum (0), lastFragmentInsertTime (0) {};
|
||||||
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
|
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SentMessage
|
struct SentMessage
|
||||||
{
|
{
|
||||||
std::vector<std::unique_ptr<Fragment> > fragments;
|
std::vector<std::unique_ptr<Fragment> > fragments;
|
||||||
uint32_t nextResendTime; // in seconds
|
uint32_t nextResendTime; // in seconds
|
||||||
int numResends;
|
int numResends;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SSUSession;
|
class SSUSession;
|
||||||
class SSUData
|
class SSUData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SSUData (SSUSession& session);
|
SSUData (SSUSession& session);
|
||||||
~SSUData ();
|
~SSUData ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
void ProcessMessage (uint8_t * buf, size_t len);
|
void ProcessMessage (uint8_t * buf, size_t len);
|
||||||
void FlushReceivedMessage ();
|
void FlushReceivedMessage ();
|
||||||
void Send (std::shared_ptr<i2p::I2NPMessage> msg);
|
void Send (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||||
|
|
||||||
void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent);
|
void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void SendMsgAck (uint32_t msgID);
|
void SendMsgAck (uint32_t msgID);
|
||||||
void SendFragmentAck (uint32_t msgID, int fragmentNum);
|
void SendFragmentAck (uint32_t msgID, int fragmentNum);
|
||||||
void ProcessAcks (uint8_t *& buf, uint8_t flag);
|
void ProcessAcks (uint8_t *& buf, uint8_t flag);
|
||||||
void ProcessFragments (uint8_t * buf);
|
void ProcessFragments (uint8_t * buf);
|
||||||
void ProcessSentMessageAck (uint32_t msgID);
|
void ProcessSentMessageAck (uint32_t msgID);
|
||||||
|
|
||||||
void ScheduleResend ();
|
void ScheduleResend ();
|
||||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
void ScheduleDecay ();
|
void ScheduleDecay ();
|
||||||
void HandleDecayTimer (const boost::system::error_code& ecode);
|
void HandleDecayTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
void ScheduleIncompleteMessagesCleanup ();
|
void ScheduleIncompleteMessagesCleanup ();
|
||||||
void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode);
|
void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
void AdjustPacketSize (const i2p::data::RouterInfo& remoteRouter);
|
void AdjustPacketSize (const i2p::data::RouterInfo& remoteRouter);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
SSUSession& m_Session;
|
SSUSession& m_Session;
|
||||||
std::map<uint32_t, std::unique_ptr<IncompleteMessage> > m_IncompleteMessages;
|
std::map<uint32_t, std::unique_ptr<IncompleteMessage> > m_IncompleteMessages;
|
||||||
std::map<uint32_t, std::unique_ptr<SentMessage> > m_SentMessages;
|
std::map<uint32_t, std::unique_ptr<SentMessage> > m_SentMessages;
|
||||||
std::set<uint32_t> m_ReceivedMessages;
|
std::set<uint32_t> m_ReceivedMessages;
|
||||||
boost::asio::deadline_timer m_ResendTimer, m_DecayTimer, m_IncompleteMessagesCleanupTimer;
|
boost::asio::deadline_timer m_ResendTimer, m_DecayTimer, m_IncompleteMessagesCleanupTimer;
|
||||||
int m_MaxPacketSize, m_PacketSize;
|
int m_MaxPacketSize, m_PacketSize;
|
||||||
i2p::I2NPMessagesHandler m_Handler;
|
i2p::I2NPMessagesHandler m_Handler;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2050
SSUSession.cpp
2050
SSUSession.cpp
File diff suppressed because it is too large
Load diff
242
SSUSession.h
242
SSUSession.h
|
@ -15,139 +15,141 @@ namespace i2p
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
struct SSUHeader
|
// Warning: do not change the order of these variables
|
||||||
{
|
// (or fix the unsafe casts in SSU.h)
|
||||||
uint8_t mac[16];
|
struct SSUHeader
|
||||||
uint8_t iv[16];
|
{
|
||||||
uint8_t flag;
|
uint8_t mac[16];
|
||||||
uint32_t time;
|
uint8_t iv[16];
|
||||||
|
uint8_t flag;
|
||||||
|
uint32_t time;
|
||||||
|
|
||||||
uint8_t GetPayloadType () const { return flag >> 4; };
|
uint8_t GetPayloadType () const { return flag >> 4; };
|
||||||
};
|
};
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
|
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||||
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
|
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
|
||||||
|
|
||||||
// payload types (4 bits)
|
// payload types (4 bits)
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
|
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1;
|
const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1;
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2;
|
const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2;
|
||||||
const uint8_t PAYLOAD_TYPE_RELAY_REQUEST = 3;
|
const uint8_t PAYLOAD_TYPE_RELAY_REQUEST = 3;
|
||||||
const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4;
|
const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4;
|
||||||
const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5;
|
const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5;
|
||||||
const uint8_t PAYLOAD_TYPE_DATA = 6;
|
const uint8_t PAYLOAD_TYPE_DATA = 6;
|
||||||
const uint8_t PAYLOAD_TYPE_PEER_TEST = 7;
|
const uint8_t PAYLOAD_TYPE_PEER_TEST = 7;
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8;
|
const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8;
|
||||||
|
|
||||||
enum SessionState
|
enum SessionState
|
||||||
{
|
{
|
||||||
eSessionStateUnknown,
|
eSessionStateUnknown,
|
||||||
eSessionStateIntroduced,
|
eSessionStateIntroduced,
|
||||||
eSessionStateEstablished,
|
eSessionStateEstablished,
|
||||||
eSessionStateClosed,
|
eSessionStateClosed,
|
||||||
eSessionStateFailed
|
eSessionStateFailed
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PeerTestParticipant
|
enum PeerTestParticipant
|
||||||
{
|
{
|
||||||
ePeerTestParticipantUnknown = 0,
|
ePeerTestParticipantUnknown = 0,
|
||||||
ePeerTestParticipantAlice1,
|
ePeerTestParticipantAlice1,
|
||||||
ePeerTestParticipantAlice2,
|
ePeerTestParticipantAlice2,
|
||||||
ePeerTestParticipantBob,
|
ePeerTestParticipantBob,
|
||||||
ePeerTestParticipantCharlie
|
ePeerTestParticipantCharlie
|
||||||
};
|
};
|
||||||
|
|
||||||
class SSUServer;
|
class SSUServer;
|
||||||
class SSUSession: public TransportSession, public std::enable_shared_from_this<SSUSession>
|
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,
|
||||||
std::shared_ptr<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 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 ();
|
||||||
void Done ();
|
void Done ();
|
||||||
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
|
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
|
||||||
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
|
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
||||||
void SendPeerTest (); // Alice
|
void SendPeerTest (); // Alice
|
||||||
|
|
||||||
SessionState GetState () const { return m_State; };
|
SessionState GetState () const { return m_State; };
|
||||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||||
|
|
||||||
void SendKeepAlive ();
|
void SendKeepAlive ();
|
||||||
uint32_t GetRelayTag () const { return m_RelayTag; };
|
uint32_t GetRelayTag () const { return m_RelayTag; };
|
||||||
uint32_t GetCreationTime () const { return m_CreationTime; };
|
uint32_t GetCreationTime () const { return m_CreationTime; };
|
||||||
|
|
||||||
void FlushData ();
|
void FlushData ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
boost::asio::io_service& GetService ();
|
boost::asio::io_service& GetService ();
|
||||||
void CreateAESandMacKey (const uint8_t * pubKey);
|
void CreateAESandMacKey (const uint8_t * pubKey);
|
||||||
|
|
||||||
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
||||||
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
|
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
|
||||||
void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
||||||
void SendSessionRequest ();
|
void SendSessionRequest ();
|
||||||
void SendRelayRequest (uint32_t iTag, const uint8_t * iKey);
|
void SendRelayRequest (uint32_t iTag, const uint8_t * iKey);
|
||||||
void ProcessSessionCreated (uint8_t * buf, size_t len);
|
void ProcessSessionCreated (uint8_t * buf, size_t len);
|
||||||
void SendSessionCreated (const uint8_t * x);
|
void SendSessionCreated (const uint8_t * x);
|
||||||
void ProcessSessionConfirmed (uint8_t * buf, size_t len);
|
void ProcessSessionConfirmed (uint8_t * buf, size_t len);
|
||||||
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, size_t ourAddressLen);
|
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, size_t ourAddressLen);
|
||||||
void ProcessRelayRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
|
void ProcessRelayRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
|
||||||
void SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from,
|
void SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from,
|
||||||
const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to);
|
const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to);
|
||||||
void SendRelayIntro (SSUSession * session, const boost::asio::ip::udp::endpoint& from);
|
void SendRelayIntro (SSUSession * session, const boost::asio::ip::udp::endpoint& from);
|
||||||
void ProcessRelayResponse (uint8_t * buf, size_t len);
|
void ProcessRelayResponse (uint8_t * buf, size_t len);
|
||||||
void ProcessRelayIntro (uint8_t * buf, size_t len);
|
void ProcessRelayIntro (uint8_t * buf, size_t len);
|
||||||
void Established ();
|
void Established ();
|
||||||
void Failed ();
|
void Failed ();
|
||||||
void ScheduleConnectTimer ();
|
void ScheduleConnectTimer ();
|
||||||
void HandleConnectTimer (const boost::system::error_code& ecode);
|
void HandleConnectTimer (const boost::system::error_code& ecode);
|
||||||
void ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
void ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
||||||
void SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, const uint8_t * introKey, bool toAddress = true, bool sendAddress = true);
|
void SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, const uint8_t * introKey, bool toAddress = true, bool sendAddress = true);
|
||||||
void ProcessData (uint8_t * buf, size_t len);
|
void ProcessData (uint8_t * buf, size_t len);
|
||||||
void SendSesionDestroyed ();
|
void SendSesionDestroyed ();
|
||||||
void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key
|
void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key
|
||||||
void Send (const uint8_t * buf, size_t size);
|
void Send (const uint8_t * buf, size_t size);
|
||||||
|
|
||||||
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey);
|
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey);
|
||||||
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
|
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
|
||||||
void Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey);
|
void Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey);
|
||||||
void DecryptSessionKey (uint8_t * buf, size_t len);
|
void DecryptSessionKey (uint8_t * buf, size_t len);
|
||||||
bool Validate (uint8_t * buf, size_t len, const uint8_t * macKey);
|
bool Validate (uint8_t * buf, size_t len, const uint8_t * macKey);
|
||||||
const uint8_t * GetIntroKey () const;
|
const uint8_t * GetIntroKey () const;
|
||||||
|
|
||||||
void ScheduleTermination ();
|
void ScheduleTermination ();
|
||||||
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class SSUData; // TODO: change in later
|
friend class SSUData; // TODO: change in later
|
||||||
SSUServer& m_Server;
|
SSUServer& m_Server;
|
||||||
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
|
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
|
||||||
boost::asio::deadline_timer m_Timer;
|
boost::asio::deadline_timer m_Timer;
|
||||||
bool m_PeerTest;
|
bool m_PeerTest;
|
||||||
SessionState m_State;
|
SessionState m_State;
|
||||||
bool m_IsSessionKey;
|
bool m_IsSessionKey;
|
||||||
uint32_t m_RelayTag;
|
uint32_t m_RelayTag;
|
||||||
i2p::crypto::CBCEncryption m_SessionKeyEncryption;
|
i2p::crypto::CBCEncryption m_SessionKeyEncryption;
|
||||||
i2p::crypto::CBCDecryption m_SessionKeyDecryption;
|
i2p::crypto::CBCDecryption m_SessionKeyDecryption;
|
||||||
i2p::crypto::AESKey m_SessionKey;
|
i2p::crypto::AESKey m_SessionKey;
|
||||||
i2p::crypto::MACKey m_MacKey;
|
i2p::crypto::MACKey m_MacKey;
|
||||||
uint32_t m_CreationTime; // seconds since epoch
|
uint32_t m_CreationTime; // seconds since epoch
|
||||||
SSUData m_Data;
|
SSUData m_Data;
|
||||||
bool m_IsDataReceived;
|
bool m_IsDataReceived;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
184
Signature.cpp
184
Signature.cpp
|
@ -8,113 +8,113 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace crypto
|
namespace crypto
|
||||||
{
|
{
|
||||||
class Ed25519
|
class Ed25519
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Ed25519 ()
|
Ed25519 ()
|
||||||
{
|
{
|
||||||
q = CryptoPP::Integer::Power2 (255) - CryptoPP::Integer (19); // 2^255-19
|
q = CryptoPP::Integer::Power2 (255) - CryptoPP::Integer (19); // 2^255-19
|
||||||
l = CryptoPP::Integer::Power2 (252) + CryptoPP::Integer ("27742317777372353535851937790883648493");
|
l = CryptoPP::Integer::Power2 (252) + CryptoPP::Integer ("27742317777372353535851937790883648493");
|
||||||
// 2^252 + 27742317777372353535851937790883648493
|
// 2^252 + 27742317777372353535851937790883648493
|
||||||
d = CryptoPP::Integer (-121665) * CryptoPP::Integer (121666).InverseMod (q); // -121665/121666
|
d = CryptoPP::Integer (-121665) * CryptoPP::Integer (121666).InverseMod (q); // -121665/121666
|
||||||
I = a_exp_b_mod_c (CryptoPP::Integer::Two (), (q - CryptoPP::Integer::One ()).DividedBy (4), q);
|
I = a_exp_b_mod_c (CryptoPP::Integer::Two (), (q - CryptoPP::Integer::One ()).DividedBy (4), q);
|
||||||
B = DecodePoint (CryptoPP::Integer (4)*CryptoPP::Integer (5).InverseMod (q));
|
B = DecodePoint (CryptoPP::Integer (4)*CryptoPP::Integer (5).InverseMod (q));
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoPP::ECP::Point DecodePublicKey (const uint8_t * key) const
|
CryptoPP::ECP::Point DecodePublicKey (const uint8_t * key) const
|
||||||
{
|
{
|
||||||
return DecodePoint (CryptoPP::Integer (key, 32));
|
return DecodePoint (CryptoPP::Integer (key, 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoPP::ECP::Point GeneratePublicKey (const uint8_t * privateKey) const
|
CryptoPP::ECP::Point GeneratePublicKey (const uint8_t * privateKey) const
|
||||||
{
|
{
|
||||||
return Mul (B, CryptoPP::Integer (privateKey, 32));
|
return Mul (B, CryptoPP::Integer (privateKey, 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CryptoPP::ECP::Point Sum (const CryptoPP::ECP::Point& p1, const CryptoPP::ECP::Point& p2) const
|
CryptoPP::ECP::Point Sum (const CryptoPP::ECP::Point& p1, const CryptoPP::ECP::Point& p2) const
|
||||||
{
|
{
|
||||||
CryptoPP::Integer m = d*p1.x*p2.x*p1.y*p2.y,
|
CryptoPP::Integer m = d*p1.x*p2.x*p1.y*p2.y,
|
||||||
x = a_times_b_mod_c (p1.x*p2.y + p2.x*p1.y, (CryptoPP::Integer::One() + m).InverseMod (q), q),
|
x = a_times_b_mod_c (p1.x*p2.y + p2.x*p1.y, (CryptoPP::Integer::One() + m).InverseMod (q), q),
|
||||||
y = a_times_b_mod_c (p1.y*p2.y + p1.x*p2.x, (CryptoPP::Integer::One() - m).InverseMod (q), q);
|
y = a_times_b_mod_c (p1.y*p2.y + p1.x*p2.x, (CryptoPP::Integer::One() - m).InverseMod (q), q);
|
||||||
return CryptoPP::ECP::Point {x, y};
|
return CryptoPP::ECP::Point {x, y};
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoPP::ECP::Point Mul (const CryptoPP::ECP::Point& p, const CryptoPP::Integer& e) const
|
CryptoPP::ECP::Point Mul (const CryptoPP::ECP::Point& p, const CryptoPP::Integer& e) const
|
||||||
{
|
{
|
||||||
CryptoPP::ECP::Point res {0, 1};
|
CryptoPP::ECP::Point res {0, 1};
|
||||||
if (!e.IsZero ())
|
if (!e.IsZero ())
|
||||||
{
|
{
|
||||||
auto bitCount = e.BitCount ();
|
auto bitCount = e.BitCount ();
|
||||||
for (int i = bitCount - 1; i >= 0; i--)
|
for (int i = bitCount - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
res = Sum (res, res);
|
res = Sum (res, res);
|
||||||
if (e.GetBit (i)) res = Sum (res, p);
|
if (e.GetBit (i)) res = Sum (res, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsOnCurve (const CryptoPP::ECP::Point& p) const
|
bool IsOnCurve (const CryptoPP::ECP::Point& p) const
|
||||||
{
|
{
|
||||||
auto x2 = p.x.Squared(), y2 = p.y.Squared ();
|
auto x2 = p.x.Squared(), y2 = p.y.Squared ();
|
||||||
return (y2 - x2 - CryptoPP::Integer::One() - d*x2*y2).Modulo (q).IsZero ();
|
return (y2 - x2 - CryptoPP::Integer::One() - d*x2*y2).Modulo (q).IsZero ();
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoPP::Integer RecoverX (const CryptoPP::Integer& y) const
|
CryptoPP::Integer RecoverX (const CryptoPP::Integer& y) const
|
||||||
{
|
{
|
||||||
auto y2 = y.Squared ();
|
auto y2 = y.Squared ();
|
||||||
auto xx = (y2 - CryptoPP::Integer::One())*(d*y2 + CryptoPP::Integer::One()).InverseMod (q);
|
auto xx = (y2 - CryptoPP::Integer::One())*(d*y2 + CryptoPP::Integer::One()).InverseMod (q);
|
||||||
auto x = a_exp_b_mod_c (xx, (q + CryptoPP::Integer (3)).DividedBy (8), q);
|
auto x = a_exp_b_mod_c (xx, (q + CryptoPP::Integer (3)).DividedBy (8), q);
|
||||||
if (!(x.Squared () - xx).Modulo (q).IsZero ())
|
if (!(x.Squared () - xx).Modulo (q).IsZero ())
|
||||||
x = a_times_b_mod_c (x, I, q);
|
x = a_times_b_mod_c (x, I, q);
|
||||||
if (x.IsOdd ()) x = q - x;
|
if (x.IsOdd ()) x = q - x;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoPP::ECP::Point DecodePoint (const CryptoPP::Integer& y) const
|
CryptoPP::ECP::Point DecodePoint (const CryptoPP::Integer& y) const
|
||||||
{
|
{
|
||||||
auto x = RecoverX (y);
|
auto x = RecoverX (y);
|
||||||
CryptoPP::ECP::Point p {x, y};
|
CryptoPP::ECP::Point p {x, y};
|
||||||
if (!IsOnCurve (p))
|
if (!IsOnCurve (p))
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Decoded point is not on 25519");
|
LogPrint (eLogError, "Decoded point is not on 25519");
|
||||||
return CryptoPP::ECP::Point {0, 1};
|
return CryptoPP::ECP::Point {0, 1};
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CryptoPP::Integer q, l, d, I;
|
CryptoPP::Integer q, l, d, I;
|
||||||
CryptoPP::ECP::Point B; // base point
|
CryptoPP::ECP::Point B; // base point
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::unique_ptr<Ed25519> g_Ed25519;
|
static std::unique_ptr<Ed25519> g_Ed25519;
|
||||||
std::unique_ptr<Ed25519>& GetEd25519 ()
|
std::unique_ptr<Ed25519>& GetEd25519 ()
|
||||||
{
|
{
|
||||||
if (!g_Ed25519)
|
if (!g_Ed25519)
|
||||||
g_Ed25519.reset (new Ed25519 ());
|
g_Ed25519.reset (new Ed25519 ());
|
||||||
return g_Ed25519;
|
return g_Ed25519;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey):
|
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey):
|
||||||
m_PublicKey (GetEd25519 ()->DecodePublicKey (signingKey))
|
m_PublicKey (GetEd25519 ()->DecodePublicKey (signingKey))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||||
{
|
{
|
||||||
return true; // TODO:
|
return true; // TODO:
|
||||||
}
|
}
|
||||||
|
|
||||||
void EDDSA25519Signer::Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const
|
void EDDSA25519Signer::Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
684
Signature.h
684
Signature.h
|
@ -14,430 +14,430 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace crypto
|
namespace crypto
|
||||||
{
|
{
|
||||||
class Verifier
|
class Verifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~Verifier () {};
|
virtual ~Verifier () {};
|
||||||
virtual bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const = 0;
|
virtual bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const = 0;
|
||||||
virtual size_t GetPublicKeyLen () const = 0;
|
virtual size_t GetPublicKeyLen () const = 0;
|
||||||
virtual size_t GetSignatureLen () const = 0;
|
virtual size_t GetSignatureLen () const = 0;
|
||||||
virtual size_t GetPrivateKeyLen () const { return GetSignatureLen ()/2; };
|
virtual size_t GetPrivateKeyLen () const { return GetSignatureLen ()/2; };
|
||||||
};
|
};
|
||||||
|
|
||||||
class Signer
|
class Signer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~Signer () {};
|
virtual ~Signer () {};
|
||||||
virtual void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const = 0;
|
virtual void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t DSA_PUBLIC_KEY_LENGTH = 128;
|
const size_t DSA_PUBLIC_KEY_LENGTH = 128;
|
||||||
const size_t DSA_SIGNATURE_LENGTH = 40;
|
const size_t DSA_SIGNATURE_LENGTH = 40;
|
||||||
const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH/2;
|
const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH/2;
|
||||||
class DSAVerifier: public Verifier
|
class DSAVerifier: public Verifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DSAVerifier (const uint8_t * signingKey)
|
DSAVerifier (const uint8_t * signingKey)
|
||||||
{
|
{
|
||||||
m_PublicKey.Initialize (dsap, dsaq, dsag, CryptoPP::Integer (signingKey, DSA_PUBLIC_KEY_LENGTH));
|
m_PublicKey.Initialize (dsap, dsaq, dsag, CryptoPP::Integer (signingKey, DSA_PUBLIC_KEY_LENGTH));
|
||||||
}
|
}
|
||||||
|
|
||||||
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::DSA::Verifier verifier (m_PublicKey);
|
CryptoPP::DSA::Verifier verifier (m_PublicKey);
|
||||||
return verifier.VerifyMessage (buf, len, signature, DSA_SIGNATURE_LENGTH);
|
return verifier.VerifyMessage (buf, len, signature, DSA_SIGNATURE_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetPublicKeyLen () const { return DSA_PUBLIC_KEY_LENGTH; };
|
size_t GetPublicKeyLen () const { return DSA_PUBLIC_KEY_LENGTH; };
|
||||||
size_t GetSignatureLen () const { return DSA_SIGNATURE_LENGTH; };
|
size_t GetSignatureLen () const { return DSA_SIGNATURE_LENGTH; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CryptoPP::DSA::PublicKey m_PublicKey;
|
CryptoPP::DSA::PublicKey m_PublicKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DSASigner: public Signer
|
class DSASigner: public Signer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DSASigner (const uint8_t * signingPrivateKey)
|
DSASigner (const uint8_t * signingPrivateKey)
|
||||||
{
|
{
|
||||||
m_PrivateKey.Initialize (dsap, dsaq, dsag, CryptoPP::Integer (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH));
|
m_PrivateKey.Initialize (dsap, dsaq, dsag, CryptoPP::Integer (signingPrivateKey, DSA_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::DSA::Signer signer (m_PrivateKey);
|
CryptoPP::DSA::Signer signer (m_PrivateKey);
|
||||||
signer.SignMessage (rnd, buf, len, signature);
|
signer.SignMessage (rnd, buf, len, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CryptoPP::DSA::PrivateKey m_PrivateKey;
|
CryptoPP::DSA::PrivateKey m_PrivateKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void CreateDSARandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
inline void CreateDSARandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||||
{
|
{
|
||||||
CryptoPP::DSA::PrivateKey privateKey;
|
CryptoPP::DSA::PrivateKey privateKey;
|
||||||
CryptoPP::DSA::PublicKey publicKey;
|
CryptoPP::DSA::PublicKey publicKey;
|
||||||
privateKey.Initialize (rnd, dsap, dsaq, dsag);
|
privateKey.Initialize (rnd, dsap, dsaq, dsag);
|
||||||
privateKey.MakePublicKey (publicKey);
|
privateKey.MakePublicKey (publicKey);
|
||||||
privateKey.GetPrivateExponent ().Encode (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
|
privateKey.GetPrivateExponent ().Encode (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
|
||||||
publicKey.GetPublicElement ().Encode (signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
|
publicKey.GetPublicElement ().Encode (signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Hash, size_t keyLen>
|
template<typename Hash, size_t keyLen>
|
||||||
class ECDSAVerifier: public Verifier
|
class ECDSAVerifier: public Verifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
template<typename Curve>
|
template<typename Curve>
|
||||||
ECDSAVerifier (Curve curve, const uint8_t * signingKey)
|
ECDSAVerifier (Curve curve, const uint8_t * signingKey)
|
||||||
{
|
{
|
||||||
m_PublicKey.Initialize (curve,
|
m_PublicKey.Initialize (curve,
|
||||||
CryptoPP::ECP::Point (CryptoPP::Integer (signingKey, keyLen/2),
|
CryptoPP::ECP::Point (CryptoPP::Integer (signingKey, keyLen/2),
|
||||||
CryptoPP::Integer (signingKey + keyLen/2, keyLen/2)));
|
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
|
||||||
{
|
{
|
||||||
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::Verifier verifier (m_PublicKey);
|
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::Verifier verifier (m_PublicKey);
|
||||||
return verifier.VerifyMessage (buf, len, signature, keyLen); // signature length
|
return verifier.VerifyMessage (buf, len, signature, keyLen); // signature length
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetPublicKeyLen () const { return keyLen; };
|
size_t GetPublicKeyLen () const { return keyLen; };
|
||||||
size_t GetSignatureLen () const { return keyLen; }; // signature length = key length
|
size_t GetSignatureLen () const { return keyLen; }; // signature length = key length
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PublicKey m_PublicKey;
|
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PublicKey m_PublicKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Hash>
|
template<typename Hash>
|
||||||
class ECDSASigner: public Signer
|
class ECDSASigner: public Signer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
template<typename Curve>
|
template<typename Curve>
|
||||||
ECDSASigner (Curve curve, const uint8_t * signingPrivateKey, size_t keyLen)
|
ECDSASigner (Curve curve, const uint8_t * signingPrivateKey, size_t keyLen)
|
||||||
{
|
{
|
||||||
m_PrivateKey.Initialize (curve, CryptoPP::Integer (signingPrivateKey, keyLen/2)); // 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
|
||||||
{
|
{
|
||||||
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::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:
|
||||||
|
|
||||||
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PrivateKey m_PrivateKey;
|
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PrivateKey m_PrivateKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Hash, typename Curve>
|
template<typename Hash, typename Curve>
|
||||||
inline void CreateECDSARandomKeys (CryptoPP::RandomNumberGenerator& rnd, Curve curve,
|
inline void CreateECDSARandomKeys (CryptoPP::RandomNumberGenerator& rnd, Curve curve,
|
||||||
size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||||
{
|
{
|
||||||
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PrivateKey privateKey;
|
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PrivateKey privateKey;
|
||||||
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PublicKey publicKey;
|
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PublicKey publicKey;
|
||||||
privateKey.Initialize (rnd, curve);
|
privateKey.Initialize (rnd, curve);
|
||||||
privateKey.MakePublicKey (publicKey);
|
privateKey.MakePublicKey (publicKey);
|
||||||
privateKey.GetPrivateExponent ().Encode (signingPrivateKey, keyLen/2);
|
privateKey.GetPrivateExponent ().Encode (signingPrivateKey, keyLen/2);
|
||||||
auto q = publicKey.GetPublicElement ();
|
auto q = publicKey.GetPublicElement ();
|
||||||
q.x.Encode (signingPublicKey, keyLen/2);
|
q.x.Encode (signingPublicKey, keyLen/2);
|
||||||
q.y.Encode (signingPublicKey + keyLen/2, keyLen/2);
|
q.y.Encode (signingPublicKey + keyLen/2, keyLen/2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ECDSA_SHA256_P256
|
// ECDSA_SHA256_P256
|
||||||
const size_t ECDSAP256_KEY_LENGTH = 64;
|
const size_t ECDSAP256_KEY_LENGTH = 64;
|
||||||
class ECDSAP256Verifier: public ECDSAVerifier<CryptoPP::SHA256, ECDSAP256_KEY_LENGTH>
|
class ECDSAP256Verifier: public ECDSAVerifier<CryptoPP::SHA256, ECDSAP256_KEY_LENGTH>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ECDSAP256Verifier (const uint8_t * signingKey):
|
ECDSAP256Verifier (const uint8_t * signingKey):
|
||||||
ECDSAVerifier (CryptoPP::ASN1::secp256r1(), signingKey)
|
ECDSAVerifier (CryptoPP::ASN1::secp256r1(), signingKey)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ECDSAP256Signer: public ECDSASigner<CryptoPP::SHA256>
|
class ECDSAP256Signer: public ECDSASigner<CryptoPP::SHA256>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ECDSAP256Signer (const uint8_t * signingPrivateKey):
|
ECDSAP256Signer (const uint8_t * signingPrivateKey):
|
||||||
ECDSASigner (CryptoPP::ASN1::secp256r1(), signingPrivateKey, ECDSAP256_KEY_LENGTH)
|
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)
|
||||||
{
|
{
|
||||||
CreateECDSARandomKeys<CryptoPP::SHA256> (rnd, CryptoPP::ASN1::secp256r1(), ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
CreateECDSARandomKeys<CryptoPP::SHA256> (rnd, CryptoPP::ASN1::secp256r1(), ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ECDSA_SHA384_P384
|
// ECDSA_SHA384_P384
|
||||||
const size_t ECDSAP384_KEY_LENGTH = 96;
|
const size_t ECDSAP384_KEY_LENGTH = 96;
|
||||||
class ECDSAP384Verifier: public ECDSAVerifier<CryptoPP::SHA384, ECDSAP384_KEY_LENGTH>
|
class ECDSAP384Verifier: public ECDSAVerifier<CryptoPP::SHA384, ECDSAP384_KEY_LENGTH>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ECDSAP384Verifier (const uint8_t * signingKey):
|
ECDSAP384Verifier (const uint8_t * signingKey):
|
||||||
ECDSAVerifier (CryptoPP::ASN1::secp384r1(), signingKey)
|
ECDSAVerifier (CryptoPP::ASN1::secp384r1(), signingKey)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ECDSAP384Signer: public ECDSASigner<CryptoPP::SHA384>
|
class ECDSAP384Signer: public ECDSASigner<CryptoPP::SHA384>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ECDSAP384Signer (const uint8_t * signingPrivateKey):
|
ECDSAP384Signer (const uint8_t * signingPrivateKey):
|
||||||
ECDSASigner (CryptoPP::ASN1::secp384r1(), signingPrivateKey, ECDSAP384_KEY_LENGTH)
|
ECDSASigner (CryptoPP::ASN1::secp384r1(), signingPrivateKey, ECDSAP384_KEY_LENGTH)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void CreateECDSAP384RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
inline void CreateECDSAP384RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||||
{
|
{
|
||||||
CreateECDSARandomKeys<CryptoPP::SHA384> (rnd, CryptoPP::ASN1::secp384r1(), ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
CreateECDSARandomKeys<CryptoPP::SHA384> (rnd, CryptoPP::ASN1::secp384r1(), ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ECDSA_SHA512_P521
|
// ECDSA_SHA512_P521
|
||||||
const size_t ECDSAP521_KEY_LENGTH = 132;
|
const size_t ECDSAP521_KEY_LENGTH = 132;
|
||||||
class ECDSAP521Verifier: public ECDSAVerifier<CryptoPP::SHA512, ECDSAP521_KEY_LENGTH>
|
class ECDSAP521Verifier: public ECDSAVerifier<CryptoPP::SHA512, ECDSAP521_KEY_LENGTH>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ECDSAP521Verifier (const uint8_t * signingKey):
|
ECDSAP521Verifier (const uint8_t * signingKey):
|
||||||
ECDSAVerifier (CryptoPP::ASN1::secp521r1(), signingKey)
|
ECDSAVerifier (CryptoPP::ASN1::secp521r1(), signingKey)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ECDSAP521Signer: public ECDSASigner<CryptoPP::SHA512>
|
class ECDSAP521Signer: public ECDSASigner<CryptoPP::SHA512>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ECDSAP521Signer (const uint8_t * signingPrivateKey):
|
ECDSAP521Signer (const uint8_t * signingPrivateKey):
|
||||||
ECDSASigner (CryptoPP::ASN1::secp521r1(), signingPrivateKey, ECDSAP521_KEY_LENGTH)
|
ECDSASigner (CryptoPP::ASN1::secp521r1(), signingPrivateKey, ECDSAP521_KEY_LENGTH)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void CreateECDSAP521RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
inline void CreateECDSAP521RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||||
{
|
{
|
||||||
CreateECDSARandomKeys<CryptoPP::SHA512> (rnd, CryptoPP::ASN1::secp521r1(), ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
CreateECDSARandomKeys<CryptoPP::SHA512> (rnd, CryptoPP::ASN1::secp521r1(), ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RSA
|
// RSA
|
||||||
template<typename Hash, size_t keyLen>
|
template<typename Hash, size_t keyLen>
|
||||||
class RSAVerifier: public Verifier
|
class RSAVerifier: public Verifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RSAVerifier (const uint8_t * signingKey)
|
RSAVerifier (const uint8_t * signingKey)
|
||||||
{
|
{
|
||||||
m_PublicKey.Initialize (CryptoPP::Integer (signingKey, keyLen), CryptoPP::Integer (rsae));
|
m_PublicKey.Initialize (CryptoPP::Integer (signingKey, keyLen), CryptoPP::Integer (rsae));
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
{
|
{
|
||||||
typename CryptoPP::RSASS<CryptoPP::PKCS1v15, Hash>::Verifier verifier (m_PublicKey);
|
typename CryptoPP::RSASS<CryptoPP::PKCS1v15, Hash>::Verifier verifier (m_PublicKey);
|
||||||
return verifier.VerifyMessage (buf, len, signature, keyLen); // signature length
|
return verifier.VerifyMessage (buf, len, signature, keyLen); // signature length
|
||||||
}
|
}
|
||||||
size_t GetPublicKeyLen () const { return keyLen; }
|
size_t GetPublicKeyLen () const { return keyLen; }
|
||||||
size_t GetSignatureLen () const { return keyLen; }
|
size_t GetSignatureLen () const { return keyLen; }
|
||||||
size_t GetPrivateKeyLen () const { return GetSignatureLen ()*2; };
|
size_t GetPrivateKeyLen () const { return GetSignatureLen ()*2; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CryptoPP::RSA::PublicKey m_PublicKey;
|
CryptoPP::RSA::PublicKey m_PublicKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename Hash>
|
template<typename Hash>
|
||||||
class RSASigner: public Signer
|
class RSASigner: public Signer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RSASigner (const uint8_t * signingPrivateKey, size_t keyLen)
|
RSASigner (const uint8_t * signingPrivateKey, size_t keyLen)
|
||||||
{
|
{
|
||||||
m_PrivateKey.Initialize (CryptoPP::Integer (signingPrivateKey, keyLen/2),
|
m_PrivateKey.Initialize (CryptoPP::Integer (signingPrivateKey, keyLen/2),
|
||||||
rsae,
|
rsae,
|
||||||
CryptoPP::Integer (signingPrivateKey + keyLen/2, keyLen/2));
|
CryptoPP::Integer (signingPrivateKey + keyLen/2, keyLen/2));
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
{
|
{
|
||||||
typename CryptoPP::RSASS<CryptoPP::PKCS1v15, Hash>::Signer signer (m_PrivateKey);
|
typename CryptoPP::RSASS<CryptoPP::PKCS1v15, Hash>::Signer signer (m_PrivateKey);
|
||||||
signer.SignMessage (rnd, buf, len, signature);
|
signer.SignMessage (rnd, buf, len, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CryptoPP::RSA::PrivateKey m_PrivateKey;
|
CryptoPP::RSA::PrivateKey m_PrivateKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void CreateRSARandomKeys (CryptoPP::RandomNumberGenerator& rnd,
|
inline void CreateRSARandomKeys (CryptoPP::RandomNumberGenerator& rnd,
|
||||||
size_t publicKeyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
size_t publicKeyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||||
{
|
{
|
||||||
CryptoPP::RSA::PrivateKey privateKey;
|
CryptoPP::RSA::PrivateKey privateKey;
|
||||||
privateKey.Initialize (rnd, publicKeyLen*8, rsae);
|
privateKey.Initialize (rnd, publicKeyLen*8, rsae);
|
||||||
privateKey.GetModulus ().Encode (signingPrivateKey, publicKeyLen);
|
privateKey.GetModulus ().Encode (signingPrivateKey, publicKeyLen);
|
||||||
privateKey.GetPrivateExponent ().Encode (signingPrivateKey + publicKeyLen, publicKeyLen);
|
privateKey.GetPrivateExponent ().Encode (signingPrivateKey + publicKeyLen, publicKeyLen);
|
||||||
privateKey.GetModulus ().Encode (signingPublicKey, publicKeyLen);
|
privateKey.GetModulus ().Encode (signingPublicKey, publicKeyLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// RSA_SHA256_2048
|
// RSA_SHA256_2048
|
||||||
const size_t RSASHA2562048_KEY_LENGTH = 256;
|
const size_t RSASHA2562048_KEY_LENGTH = 256;
|
||||||
class RSASHA2562048Verifier: public RSAVerifier<CryptoPP::SHA256, RSASHA2562048_KEY_LENGTH>
|
class RSASHA2562048Verifier: public RSAVerifier<CryptoPP::SHA256, RSASHA2562048_KEY_LENGTH>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RSASHA2562048Verifier (const uint8_t * signingKey): RSAVerifier (signingKey)
|
RSASHA2562048Verifier (const uint8_t * signingKey): RSAVerifier (signingKey)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class RSASHA2562048Signer: public RSASigner<CryptoPP::SHA256>
|
class RSASHA2562048Signer: public RSASigner<CryptoPP::SHA256>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RSASHA2562048Signer (const uint8_t * signingPrivateKey):
|
RSASHA2562048Signer (const uint8_t * signingPrivateKey):
|
||||||
RSASigner (signingPrivateKey, RSASHA2562048_KEY_LENGTH*2)
|
RSASigner (signingPrivateKey, RSASHA2562048_KEY_LENGTH*2)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// RSA_SHA384_3072
|
// RSA_SHA384_3072
|
||||||
const size_t RSASHA3843072_KEY_LENGTH = 384;
|
const size_t RSASHA3843072_KEY_LENGTH = 384;
|
||||||
class RSASHA3843072Verifier: public RSAVerifier<CryptoPP::SHA384, RSASHA3843072_KEY_LENGTH>
|
class RSASHA3843072Verifier: public RSAVerifier<CryptoPP::SHA384, RSASHA3843072_KEY_LENGTH>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RSASHA3843072Verifier (const uint8_t * signingKey): RSAVerifier (signingKey)
|
RSASHA3843072Verifier (const uint8_t * signingKey): RSAVerifier (signingKey)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class RSASHA3843072Signer: public RSASigner<CryptoPP::SHA384>
|
class RSASHA3843072Signer: public RSASigner<CryptoPP::SHA384>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RSASHA3843072Signer (const uint8_t * signingPrivateKey):
|
RSASHA3843072Signer (const uint8_t * signingPrivateKey):
|
||||||
RSASigner (signingPrivateKey, RSASHA3843072_KEY_LENGTH*2)
|
RSASigner (signingPrivateKey, RSASHA3843072_KEY_LENGTH*2)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// RSA_SHA512_4096
|
// RSA_SHA512_4096
|
||||||
const size_t RSASHA5124096_KEY_LENGTH = 512;
|
const size_t RSASHA5124096_KEY_LENGTH = 512;
|
||||||
class RSASHA5124096Verifier: public RSAVerifier<CryptoPP::SHA512, RSASHA5124096_KEY_LENGTH>
|
class RSASHA5124096Verifier: public RSAVerifier<CryptoPP::SHA512, RSASHA5124096_KEY_LENGTH>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RSASHA5124096Verifier (const uint8_t * signingKey): RSAVerifier (signingKey)
|
RSASHA5124096Verifier (const uint8_t * signingKey): RSAVerifier (signingKey)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class RSASHA5124096Signer: public RSASigner<CryptoPP::SHA512>
|
class RSASHA5124096Signer: public RSASigner<CryptoPP::SHA512>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RSASHA5124096Signer (const uint8_t * signingPrivateKey):
|
RSASHA5124096Signer (const uint8_t * signingPrivateKey):
|
||||||
RSASigner (signingPrivateKey, RSASHA5124096_KEY_LENGTH*2)
|
RSASigner (signingPrivateKey, RSASHA5124096_KEY_LENGTH*2)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Raw verifiers
|
// Raw verifiers
|
||||||
class RawVerifier
|
class RawVerifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~RawVerifier () {};
|
virtual ~RawVerifier () {};
|
||||||
virtual void Update (const uint8_t * buf, size_t len) = 0;
|
virtual void Update (const uint8_t * buf, size_t len) = 0;
|
||||||
virtual bool Verify (const uint8_t * signature) = 0;
|
virtual bool Verify (const uint8_t * signature) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Hash, size_t keyLen>
|
template<typename Hash, size_t keyLen>
|
||||||
class RSARawVerifier: public RawVerifier
|
class RSARawVerifier: public RawVerifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RSARawVerifier (const uint8_t * signingKey):
|
RSARawVerifier (const uint8_t * signingKey):
|
||||||
n (signingKey, keyLen)
|
n (signingKey, keyLen)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update (const uint8_t * buf, size_t len)
|
void Update (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
m_Hash.Update (buf, len);
|
m_Hash.Update (buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Verify (const uint8_t * signature)
|
bool Verify (const uint8_t * signature)
|
||||||
{
|
{
|
||||||
// RSA encryption first
|
// RSA encryption first
|
||||||
CryptoPP::Integer enSig (a_exp_b_mod_c (CryptoPP::Integer (signature, keyLen),
|
CryptoPP::Integer enSig (a_exp_b_mod_c (CryptoPP::Integer (signature, keyLen),
|
||||||
CryptoPP::Integer (i2p::crypto::rsae), n)); // s^e mod n
|
CryptoPP::Integer (i2p::crypto::rsae), n)); // s^e mod n
|
||||||
uint8_t enSigBuf[keyLen];
|
uint8_t enSigBuf[keyLen];
|
||||||
enSig.Encode (enSigBuf, keyLen);
|
enSig.Encode (enSigBuf, keyLen);
|
||||||
|
|
||||||
uint8_t digest[Hash::DIGESTSIZE];
|
uint8_t digest[Hash::DIGESTSIZE];
|
||||||
m_Hash.Final (digest);
|
m_Hash.Final (digest);
|
||||||
if ((int)keyLen < Hash::DIGESTSIZE) return false; // can't verify digest longer than key
|
if ((int)keyLen < Hash::DIGESTSIZE) return false; // can't verify digest longer than key
|
||||||
// we assume digest is right aligned, at least for PKCS#1 v1.5 padding
|
// we assume digest is right aligned, at least for PKCS#1 v1.5 padding
|
||||||
return !memcmp (enSigBuf + (keyLen - Hash::DIGESTSIZE), digest, Hash::DIGESTSIZE);
|
return !memcmp (enSigBuf + (keyLen - Hash::DIGESTSIZE), digest, Hash::DIGESTSIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CryptoPP::Integer n; // RSA modulus
|
CryptoPP::Integer n; // RSA modulus
|
||||||
Hash m_Hash;
|
Hash m_Hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RSASHA5124096RawVerifier: public RSARawVerifier<CryptoPP::SHA512, RSASHA5124096_KEY_LENGTH>
|
class RSASHA5124096RawVerifier: public RSARawVerifier<CryptoPP::SHA512, RSASHA5124096_KEY_LENGTH>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RSASHA5124096RawVerifier (const uint8_t * signingKey): RSARawVerifier (signingKey)
|
RSASHA5124096RawVerifier (const uint8_t * signingKey): RSARawVerifier (signingKey)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// EdDSA
|
// EdDSA
|
||||||
const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32;
|
const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32;
|
||||||
const size_t EDDSA25519_SIGNATURE_LENGTH = 64;
|
const size_t EDDSA25519_SIGNATURE_LENGTH = 64;
|
||||||
const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32;
|
const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32;
|
||||||
class EDDSA25519Verifier: public Verifier
|
class EDDSA25519Verifier: public Verifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EDDSA25519Verifier (const uint8_t * signingKey);
|
EDDSA25519Verifier (const uint8_t * signingKey);
|
||||||
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;
|
||||||
|
|
||||||
size_t GetPublicKeyLen () const { return EDDSA25519_PUBLIC_KEY_LENGTH; };
|
size_t GetPublicKeyLen () const { return EDDSA25519_PUBLIC_KEY_LENGTH; };
|
||||||
size_t GetSignatureLen () const { return EDDSA25519_SIGNATURE_LENGTH; };
|
size_t GetSignatureLen () const { return EDDSA25519_SIGNATURE_LENGTH; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CryptoPP::ECP::Point m_PublicKey;
|
CryptoPP::ECP::Point m_PublicKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EDDSA25519Signer: public Signer
|
class EDDSA25519Signer: public Signer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EDDSA25519Signer (const uint8_t * signingPrivateKey) {};
|
EDDSA25519Signer (const uint8_t * signingPrivateKey) {};
|
||||||
|
|
||||||
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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1702
Streaming.cpp
1702
Streaming.cpp
File diff suppressed because it is too large
Load diff
424
Streaming.h
424
Streaming.h
|
@ -22,250 +22,250 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
class ClientDestination;
|
class ClientDestination;
|
||||||
}
|
}
|
||||||
namespace stream
|
namespace stream
|
||||||
{
|
{
|
||||||
const uint16_t PACKET_FLAG_SYNCHRONIZE = 0x0001;
|
const uint16_t PACKET_FLAG_SYNCHRONIZE = 0x0001;
|
||||||
const uint16_t PACKET_FLAG_CLOSE = 0x0002;
|
const uint16_t PACKET_FLAG_CLOSE = 0x0002;
|
||||||
const uint16_t PACKET_FLAG_RESET = 0x0004;
|
const uint16_t PACKET_FLAG_RESET = 0x0004;
|
||||||
const uint16_t PACKET_FLAG_SIGNATURE_INCLUDED = 0x0008;
|
const uint16_t PACKET_FLAG_SIGNATURE_INCLUDED = 0x0008;
|
||||||
const uint16_t PACKET_FLAG_SIGNATURE_REQUESTED = 0x0010;
|
const uint16_t PACKET_FLAG_SIGNATURE_REQUESTED = 0x0010;
|
||||||
const uint16_t PACKET_FLAG_FROM_INCLUDED = 0x0020;
|
const uint16_t PACKET_FLAG_FROM_INCLUDED = 0x0020;
|
||||||
const uint16_t PACKET_FLAG_DELAY_REQUESTED = 0x0040;
|
const uint16_t PACKET_FLAG_DELAY_REQUESTED = 0x0040;
|
||||||
const uint16_t PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED = 0x0080;
|
const uint16_t PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED = 0x0080;
|
||||||
const uint16_t PACKET_FLAG_PROFILE_INTERACTIVE = 0x0100;
|
const uint16_t PACKET_FLAG_PROFILE_INTERACTIVE = 0x0100;
|
||||||
const uint16_t PACKET_FLAG_ECHO = 0x0200;
|
const uint16_t PACKET_FLAG_ECHO = 0x0200;
|
||||||
const uint16_t PACKET_FLAG_NO_ACK = 0x0400;
|
const uint16_t PACKET_FLAG_NO_ACK = 0x0400;
|
||||||
|
|
||||||
const size_t STREAMING_MTU = 1730;
|
const size_t STREAMING_MTU = 1730;
|
||||||
const size_t MAX_PACKET_SIZE = 4096;
|
const size_t MAX_PACKET_SIZE = 4096;
|
||||||
const size_t COMPRESSION_THRESHOLD_SIZE = 66;
|
const size_t COMPRESSION_THRESHOLD_SIZE = 66;
|
||||||
const int ACK_SEND_TIMEOUT = 200; // in milliseconds
|
const int ACK_SEND_TIMEOUT = 200; // in milliseconds
|
||||||
const int MAX_NUM_RESEND_ATTEMPTS = 6;
|
const int MAX_NUM_RESEND_ATTEMPTS = 6;
|
||||||
const int WINDOW_SIZE = 6; // in messages
|
const int WINDOW_SIZE = 6; // in messages
|
||||||
const int MIN_WINDOW_SIZE = 1;
|
const int MIN_WINDOW_SIZE = 1;
|
||||||
const int MAX_WINDOW_SIZE = 128;
|
const int MAX_WINDOW_SIZE = 128;
|
||||||
const int INITIAL_RTT = 8000; // in milliseconds
|
const int INITIAL_RTT = 8000; // in milliseconds
|
||||||
const int INITIAL_RTO = 9000; // in milliseconds
|
const int INITIAL_RTO = 9000; // in milliseconds
|
||||||
|
|
||||||
struct Packet
|
struct Packet
|
||||||
{
|
{
|
||||||
size_t len, offset;
|
size_t len, offset;
|
||||||
uint8_t buf[MAX_PACKET_SIZE];
|
uint8_t buf[MAX_PACKET_SIZE];
|
||||||
uint64_t sendTime;
|
uint64_t sendTime;
|
||||||
|
|
||||||
Packet (): len (0), offset (0), sendTime (0) {};
|
Packet (): len (0), offset (0), sendTime (0) {};
|
||||||
uint8_t * GetBuffer () { return buf + offset; };
|
uint8_t * GetBuffer () { return buf + offset; };
|
||||||
size_t GetLength () const { return len - offset; };
|
size_t GetLength () const { return len - offset; };
|
||||||
|
|
||||||
uint32_t GetSendStreamID () const { return bufbe32toh (buf); };
|
uint32_t GetSendStreamID () const { return bufbe32toh (buf); };
|
||||||
uint32_t GetReceiveStreamID () const { return bufbe32toh (buf + 4); };
|
uint32_t GetReceiveStreamID () const { return bufbe32toh (buf + 4); };
|
||||||
uint32_t GetSeqn () const { return bufbe32toh (buf + 8); };
|
uint32_t GetSeqn () const { return bufbe32toh (buf + 8); };
|
||||||
uint32_t GetAckThrough () const { return bufbe32toh (buf + 12); };
|
uint32_t GetAckThrough () const { return bufbe32toh (buf + 12); };
|
||||||
uint8_t GetNACKCount () const { return buf[16]; };
|
uint8_t GetNACKCount () const { return buf[16]; };
|
||||||
uint32_t GetNACK (int i) const { return bufbe32toh (buf + 17 + 4 * i); };
|
uint32_t GetNACK (int i) const { return bufbe32toh (buf + 17 + 4 * i); };
|
||||||
const uint8_t * GetOption () const { return buf + 17 + GetNACKCount ()*4 + 3; }; // 3 = resendDelay + flags
|
const uint8_t * GetOption () const { return buf + 17 + GetNACKCount ()*4 + 3; }; // 3 = resendDelay + flags
|
||||||
uint16_t GetFlags () const { return bufbe16toh (GetOption () - 2); };
|
uint16_t GetFlags () const { return bufbe16toh (GetOption () - 2); };
|
||||||
uint16_t GetOptionSize () const { return bufbe16toh (GetOption ()); };
|
uint16_t GetOptionSize () const { return bufbe16toh (GetOption ()); };
|
||||||
const uint8_t * GetOptionData () const { return GetOption () + 2; };
|
const uint8_t * GetOptionData () const { return GetOption () + 2; };
|
||||||
const uint8_t * GetPayload () const { return GetOptionData () + GetOptionSize (); };
|
const uint8_t * GetPayload () const { return GetOptionData () + GetOptionSize (); };
|
||||||
|
|
||||||
bool IsSYN () const { return GetFlags () & PACKET_FLAG_SYNCHRONIZE; };
|
bool IsSYN () const { return GetFlags () & PACKET_FLAG_SYNCHRONIZE; };
|
||||||
bool IsNoAck () const { return GetFlags () & PACKET_FLAG_NO_ACK; };
|
bool IsNoAck () const { return GetFlags () & PACKET_FLAG_NO_ACK; };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PacketCmp
|
struct PacketCmp
|
||||||
{
|
{
|
||||||
bool operator() (const Packet * p1, const Packet * p2) const
|
bool operator() (const Packet * p1, const Packet * p2) const
|
||||||
{
|
{
|
||||||
return p1->GetSeqn () < p2->GetSeqn ();
|
return p1->GetSeqn () < p2->GetSeqn ();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum StreamStatus
|
enum StreamStatus
|
||||||
{
|
{
|
||||||
eStreamStatusNew = 0,
|
eStreamStatusNew = 0,
|
||||||
eStreamStatusOpen,
|
eStreamStatusOpen,
|
||||||
eStreamStatusReset,
|
eStreamStatusReset,
|
||||||
eStreamStatusClosing,
|
eStreamStatusClosing,
|
||||||
eStreamStatusClosed
|
eStreamStatusClosed
|
||||||
};
|
};
|
||||||
|
|
||||||
class StreamingDestination;
|
class StreamingDestination;
|
||||||
class Stream: public std::enable_shared_from_this<Stream>
|
class Stream: public std::enable_shared_from_this<Stream>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef std::function<void (const boost::system::error_code& ecode)> SendHandler;
|
typedef std::function<void (const boost::system::error_code& ecode)> SendHandler;
|
||||||
|
|
||||||
Stream (boost::asio::io_service& service, StreamingDestination& local,
|
Stream (boost::asio::io_service& service, StreamingDestination& local,
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0); // outgoing
|
std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0); // outgoing
|
||||||
Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming
|
Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming
|
||||||
|
|
||||||
~Stream ();
|
~Stream ();
|
||||||
uint32_t GetSendStreamID () const { return m_SendStreamID; };
|
uint32_t GetSendStreamID () const { return m_SendStreamID; };
|
||||||
uint32_t GetRecvStreamID () const { return m_RecvStreamID; };
|
uint32_t GetRecvStreamID () const { return m_RecvStreamID; };
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> GetRemoteLeaseSet () const { return m_RemoteLeaseSet; };
|
std::shared_ptr<const i2p::data::LeaseSet> GetRemoteLeaseSet () const { return m_RemoteLeaseSet; };
|
||||||
const i2p::data::IdentityEx& GetRemoteIdentity () const { return m_RemoteIdentity; };
|
const i2p::data::IdentityEx& GetRemoteIdentity () const { return m_RemoteIdentity; };
|
||||||
bool IsOpen () const { return m_Status == eStreamStatusOpen; };
|
bool IsOpen () const { return m_Status == eStreamStatusOpen; };
|
||||||
bool IsEstablished () const { return m_SendStreamID; };
|
bool IsEstablished () const { return m_SendStreamID; };
|
||||||
StreamStatus GetStatus () const { return m_Status; };
|
StreamStatus GetStatus () const { return m_Status; };
|
||||||
StreamingDestination& GetLocalDestination () { return m_LocalDestination; };
|
StreamingDestination& GetLocalDestination () { return m_LocalDestination; };
|
||||||
|
|
||||||
void HandleNextPacket (Packet * packet);
|
void HandleNextPacket (Packet * packet);
|
||||||
size_t Send (const uint8_t * buf, size_t len);
|
size_t Send (const uint8_t * buf, size_t len);
|
||||||
void AsyncSend (const uint8_t * buf, size_t len, SendHandler handler);
|
void AsyncSend (const uint8_t * buf, size_t len, SendHandler handler);
|
||||||
|
|
||||||
template<typename Buffer, typename ReceiveHandler>
|
template<typename Buffer, typename ReceiveHandler>
|
||||||
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
|
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
|
||||||
size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); };
|
size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); };
|
||||||
|
|
||||||
void Close ();
|
void Close ();
|
||||||
void Cancel () { m_ReceiveTimer.cancel (); };
|
void Cancel () { m_ReceiveTimer.cancel (); };
|
||||||
|
|
||||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||||
size_t GetSendQueueSize () const { return m_SentPackets.size (); };
|
size_t GetSendQueueSize () const { return m_SentPackets.size (); };
|
||||||
size_t GetReceiveQueueSize () const { return m_ReceiveQueue.size (); };
|
size_t GetReceiveQueueSize () const { return m_ReceiveQueue.size (); };
|
||||||
size_t GetSendBufferSize () const { return m_SendBuffer.rdbuf ()->in_avail (); };
|
size_t GetSendBufferSize () const { return m_SendBuffer.rdbuf ()->in_avail (); };
|
||||||
int GetWindowSize () const { return m_WindowSize; };
|
int GetWindowSize () const { return m_WindowSize; };
|
||||||
int GetRTT () const { return m_RTT; };
|
int GetRTT () const { return m_RTT; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
|
|
||||||
void SendBuffer ();
|
void SendBuffer ();
|
||||||
void SendQuickAck ();
|
void SendQuickAck ();
|
||||||
void SendClose ();
|
void SendClose ();
|
||||||
bool SendPacket (Packet * packet);
|
bool SendPacket (Packet * packet);
|
||||||
void SendPackets (const std::vector<Packet *>& packets);
|
void SendPackets (const std::vector<Packet *>& packets);
|
||||||
|
|
||||||
void SavePacket (Packet * packet);
|
void SavePacket (Packet * packet);
|
||||||
void ProcessPacket (Packet * packet);
|
void ProcessPacket (Packet * packet);
|
||||||
void ProcessAck (Packet * packet);
|
void ProcessAck (Packet * packet);
|
||||||
size_t ConcatenatePackets (uint8_t * buf, size_t len);
|
size_t ConcatenatePackets (uint8_t * buf, size_t len);
|
||||||
|
|
||||||
void UpdateCurrentRemoteLease (bool expired = false);
|
void UpdateCurrentRemoteLease (bool expired = false);
|
||||||
|
|
||||||
template<typename Buffer, typename ReceiveHandler>
|
template<typename Buffer, typename ReceiveHandler>
|
||||||
void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler);
|
void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler);
|
||||||
|
|
||||||
void ScheduleResend ();
|
void ScheduleResend ();
|
||||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||||
void HandleAckSendTimer (const boost::system::error_code& ecode);
|
void HandleAckSendTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len);
|
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
boost::asio::io_service& m_Service;
|
boost::asio::io_service& m_Service;
|
||||||
uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber;
|
uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber;
|
||||||
int32_t m_LastReceivedSequenceNumber;
|
int32_t m_LastReceivedSequenceNumber;
|
||||||
StreamStatus m_Status;
|
StreamStatus m_Status;
|
||||||
bool m_IsAckSendScheduled;
|
bool m_IsAckSendScheduled;
|
||||||
StreamingDestination& m_LocalDestination;
|
StreamingDestination& m_LocalDestination;
|
||||||
i2p::data::IdentityEx m_RemoteIdentity;
|
i2p::data::IdentityEx m_RemoteIdentity;
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
||||||
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
||||||
i2p::data::Lease m_CurrentRemoteLease;
|
i2p::data::Lease m_CurrentRemoteLease;
|
||||||
std::shared_ptr<i2p::tunnel::OutboundTunnel> m_CurrentOutboundTunnel;
|
std::shared_ptr<i2p::tunnel::OutboundTunnel> m_CurrentOutboundTunnel;
|
||||||
std::queue<Packet *> m_ReceiveQueue;
|
std::queue<Packet *> m_ReceiveQueue;
|
||||||
std::set<Packet *, PacketCmp> m_SavedPackets;
|
std::set<Packet *, PacketCmp> m_SavedPackets;
|
||||||
std::set<Packet *, PacketCmp> m_SentPackets;
|
std::set<Packet *, PacketCmp> m_SentPackets;
|
||||||
boost::asio::deadline_timer m_ReceiveTimer, m_ResendTimer, m_AckSendTimer;
|
boost::asio::deadline_timer m_ReceiveTimer, m_ResendTimer, m_AckSendTimer;
|
||||||
size_t m_NumSentBytes, m_NumReceivedBytes;
|
size_t m_NumSentBytes, m_NumReceivedBytes;
|
||||||
uint16_t m_Port;
|
uint16_t m_Port;
|
||||||
|
|
||||||
std::mutex m_SendBufferMutex;
|
std::mutex m_SendBufferMutex;
|
||||||
std::stringstream m_SendBuffer;
|
std::stringstream m_SendBuffer;
|
||||||
int m_WindowSize, m_RTT, m_RTO;
|
int m_WindowSize, m_RTT, m_RTO;
|
||||||
uint64_t m_LastWindowSizeIncreaseTime;
|
uint64_t m_LastWindowSizeIncreaseTime;
|
||||||
int m_NumResendAttempts;
|
int m_NumResendAttempts;
|
||||||
SendHandler m_SendHandler;
|
SendHandler m_SendHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StreamingDestination
|
class StreamingDestination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef std::function<void (std::shared_ptr<Stream>)> Acceptor;
|
typedef std::function<void (std::shared_ptr<Stream>)> Acceptor;
|
||||||
|
|
||||||
StreamingDestination (i2p::client::ClientDestination& owner, uint16_t localPort = 0):
|
StreamingDestination (i2p::client::ClientDestination& owner, uint16_t localPort = 0):
|
||||||
m_Owner (owner), m_LocalPort (localPort) {};
|
m_Owner (owner), m_LocalPort (localPort) {};
|
||||||
~StreamingDestination () {};
|
~StreamingDestination () {};
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
std::shared_ptr<Stream> CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
std::shared_ptr<Stream> CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
||||||
void DeleteStream (std::shared_ptr<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 () { if (m_Acceptor) m_Acceptor (nullptr); m_Acceptor = nullptr; };
|
void ResetAcceptor () { if (m_Acceptor) m_Acceptor (nullptr); m_Acceptor = nullptr; };
|
||||||
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
|
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
|
||||||
i2p::client::ClientDestination& GetOwner () { return m_Owner; };
|
i2p::client::ClientDestination& GetOwner () { return m_Owner; };
|
||||||
uint16_t GetLocalPort () const { return m_LocalPort; };
|
uint16_t GetLocalPort () const { return m_LocalPort; };
|
||||||
|
|
||||||
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
|
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void HandleNextPacket (Packet * packet);
|
void HandleNextPacket (Packet * packet);
|
||||||
std::shared_ptr<Stream> CreateNewIncomingStream ();
|
std::shared_ptr<Stream> CreateNewIncomingStream ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
i2p::client::ClientDestination& m_Owner;
|
i2p::client::ClientDestination& m_Owner;
|
||||||
uint16_t m_LocalPort;
|
uint16_t m_LocalPort;
|
||||||
std::mutex m_StreamsMutex;
|
std::mutex m_StreamsMutex;
|
||||||
std::map<uint32_t, std::shared_ptr<Stream> > m_Streams;
|
std::map<uint32_t, std::shared_ptr<Stream> > m_Streams;
|
||||||
Acceptor m_Acceptor;
|
Acceptor m_Acceptor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
const decltype(m_Streams)& GetStreams () const { return m_Streams; };
|
const decltype(m_Streams)& GetStreams () const { return m_Streams; };
|
||||||
};
|
};
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
template<typename Buffer, typename ReceiveHandler>
|
template<typename Buffer, typename ReceiveHandler>
|
||||||
void Stream::AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout)
|
void Stream::AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout)
|
||||||
{
|
{
|
||||||
auto s = shared_from_this();
|
auto s = shared_from_this();
|
||||||
m_Service.post ([=](void)
|
m_Service.post ([=](void)
|
||||||
{
|
{
|
||||||
if (!m_ReceiveQueue.empty () || m_Status == eStreamStatusReset)
|
if (!m_ReceiveQueue.empty () || m_Status == eStreamStatusReset)
|
||||||
s->HandleReceiveTimer (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), buffer, handler);
|
s->HandleReceiveTimer (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), buffer, handler);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout));
|
s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout));
|
||||||
s->m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode)
|
s->m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode)
|
||||||
{ s->HandleReceiveTimer (ecode, buffer, handler); });
|
{ s->HandleReceiveTimer (ecode, buffer, handler); });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Buffer, typename ReceiveHandler>
|
template<typename Buffer, typename ReceiveHandler>
|
||||||
void Stream::HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler)
|
void Stream::HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler)
|
||||||
{
|
{
|
||||||
size_t received = ConcatenatePackets (boost::asio::buffer_cast<uint8_t *>(buffer), boost::asio::buffer_size(buffer));
|
size_t received = ConcatenatePackets (boost::asio::buffer_cast<uint8_t *>(buffer), boost::asio::buffer_size(buffer));
|
||||||
if (received > 0)
|
if (received > 0)
|
||||||
handler (boost::system::error_code (), received);
|
handler (boost::system::error_code (), received);
|
||||||
else if (ecode == boost::asio::error::operation_aborted)
|
else if (ecode == boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
// timeout not expired
|
// timeout not expired
|
||||||
if (m_Status == eStreamStatusReset)
|
if (m_Status == eStreamStatusReset)
|
||||||
handler (boost::asio::error::make_error_code (boost::asio::error::connection_reset), 0);
|
handler (boost::asio::error::make_error_code (boost::asio::error::connection_reset), 0);
|
||||||
else
|
else
|
||||||
handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), 0);
|
handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// timeout expired
|
// timeout expired
|
||||||
handler (boost::asio::error::make_error_code (boost::asio::error::timed_out), received);
|
handler (boost::asio::error::make_error_code (boost::asio::error::timed_out), received);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
13
TODO
Normal file
13
TODO
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Short-term refactoring:
|
||||||
|
- SSUSession:637, SSUSession:635 get rid of casting to SSUHeader
|
||||||
|
- Identity.cpp:156 check for self asignment
|
||||||
|
|
||||||
|
Long-term refactoring:
|
||||||
|
- Rely on a library for TLS and SSL.
|
||||||
|
- Move parsing code out of networking code, to allow better testing.
|
||||||
|
- Separate front-end code (SAM, BOB, ...) from the back-end.
|
||||||
|
|
||||||
|
|
||||||
|
Additions:
|
||||||
|
- Write tests.
|
||||||
|
- Add documentation.
|
30
Timestamp.h
30
Timestamp.h
|
@ -8,23 +8,23 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
inline uint64_t GetMillisecondsSinceEpoch ()
|
inline uint64_t GetMillisecondsSinceEpoch ()
|
||||||
{
|
{
|
||||||
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
std::chrono::system_clock::now().time_since_epoch()).count ();
|
std::chrono::system_clock::now().time_since_epoch()).count ();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t GetHoursSinceEpoch ()
|
inline uint32_t GetHoursSinceEpoch ()
|
||||||
{
|
{
|
||||||
return std::chrono::duration_cast<std::chrono::hours>(
|
return std::chrono::duration_cast<std::chrono::hours>(
|
||||||
std::chrono::system_clock::now().time_since_epoch()).count ();
|
std::chrono::system_clock::now().time_since_epoch()).count ();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t GetSecondsSinceEpoch ()
|
inline uint64_t GetSecondsSinceEpoch ()
|
||||||
{
|
{
|
||||||
return std::chrono::duration_cast<std::chrono::seconds>(
|
return std::chrono::duration_cast<std::chrono::seconds>(
|
||||||
std::chrono::system_clock::now().time_since_epoch()).count ();
|
std::chrono::system_clock::now().time_since_epoch()).count ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,102 +10,102 @@
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
TransitTunnel::TransitTunnel (uint32_t receiveTunnelID,
|
TransitTunnel::TransitTunnel (uint32_t receiveTunnelID,
|
||||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||||
const uint8_t * layerKey,const uint8_t * ivKey):
|
const uint8_t * layerKey,const uint8_t * ivKey):
|
||||||
m_TunnelID (receiveTunnelID), m_NextTunnelID (nextTunnelID),
|
m_TunnelID (receiveTunnelID), m_NextTunnelID (nextTunnelID),
|
||||||
m_NextIdent (nextIdent)
|
m_NextIdent (nextIdent)
|
||||||
{
|
{
|
||||||
m_Encryption.SetKeys (layerKey, ivKey);
|
m_Encryption.SetKeys (layerKey, ivKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransitTunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
|
void TransitTunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
|
||||||
{
|
{
|
||||||
m_Encryption.Encrypt (in->GetPayload () + 4, out->GetPayload () + 4);
|
m_Encryption.Encrypt (in->GetPayload () + 4, out->GetPayload () + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
TransitTunnelParticipant::~TransitTunnelParticipant ()
|
TransitTunnelParticipant::~TransitTunnelParticipant ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransitTunnelParticipant::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
|
void TransitTunnelParticipant::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
|
||||||
{
|
{
|
||||||
auto newMsg = CreateEmptyTunnelDataMsg ();
|
auto newMsg = CreateEmptyTunnelDataMsg ();
|
||||||
EncryptTunnelMsg (tunnelMsg, newMsg);
|
EncryptTunnelMsg (tunnelMsg, newMsg);
|
||||||
|
|
||||||
m_NumTransmittedBytes += tunnelMsg->GetLength ();
|
m_NumTransmittedBytes += tunnelMsg->GetLength ();
|
||||||
htobe32buf (newMsg->GetPayload (), GetNextTunnelID ());
|
htobe32buf (newMsg->GetPayload (), GetNextTunnelID ());
|
||||||
newMsg->FillI2NPMessageHeader (eI2NPTunnelData);
|
newMsg->FillI2NPMessageHeader (eI2NPTunnelData);
|
||||||
m_TunnelDataMsgs.push_back (newMsg);
|
m_TunnelDataMsgs.push_back (newMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransitTunnelParticipant::FlushTunnelDataMsgs ()
|
void TransitTunnelParticipant::FlushTunnelDataMsgs ()
|
||||||
{
|
{
|
||||||
if (!m_TunnelDataMsgs.empty ())
|
if (!m_TunnelDataMsgs.empty ())
|
||||||
{
|
{
|
||||||
auto num = m_TunnelDataMsgs.size ();
|
auto num = m_TunnelDataMsgs.size ();
|
||||||
if (num > 1)
|
if (num > 1)
|
||||||
LogPrint (eLogDebug, "TransitTunnel: ",GetTunnelID (),"->", GetNextTunnelID (), " ", num);
|
LogPrint (eLogDebug, "TransitTunnel: ",GetTunnelID (),"->", GetNextTunnelID (), " ", num);
|
||||||
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs);
|
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs);
|
||||||
m_TunnelDataMsgs.clear ();
|
m_TunnelDataMsgs.clear ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
|
void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "We are not a gateway for transit tunnel ", m_TunnelID);
|
LogPrint (eLogError, "We are not a gateway for transit tunnel ", m_TunnelID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
|
void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Incoming tunnel message is not supported ", m_TunnelID);
|
LogPrint (eLogError, "Incoming tunnel message is not supported ", m_TunnelID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
|
void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
TunnelMessageBlock block;
|
TunnelMessageBlock block;
|
||||||
block.deliveryType = eDeliveryTypeLocal;
|
block.deliveryType = eDeliveryTypeLocal;
|
||||||
block.data = msg;
|
block.data = msg;
|
||||||
std::unique_lock<std::mutex> l(m_SendMutex);
|
std::unique_lock<std::mutex> l(m_SendMutex);
|
||||||
m_Gateway.PutTunnelDataMsg (block);
|
m_Gateway.PutTunnelDataMsg (block);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransitTunnelGateway::FlushTunnelDataMsgs ()
|
void TransitTunnelGateway::FlushTunnelDataMsgs ()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_SendMutex);
|
std::unique_lock<std::mutex> l(m_SendMutex);
|
||||||
m_Gateway.SendBuffer ();
|
m_Gateway.SendBuffer ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
|
void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
|
||||||
{
|
{
|
||||||
auto newMsg = CreateEmptyTunnelDataMsg ();
|
auto newMsg = CreateEmptyTunnelDataMsg ();
|
||||||
EncryptTunnelMsg (tunnelMsg, newMsg);
|
EncryptTunnelMsg (tunnelMsg, newMsg);
|
||||||
|
|
||||||
LogPrint (eLogDebug, "TransitTunnel endpoint for ", GetTunnelID ());
|
LogPrint (eLogDebug, "TransitTunnel endpoint for ", GetTunnelID ());
|
||||||
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
|
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
TransitTunnel * CreateTransitTunnel (uint32_t receiveTunnelID,
|
TransitTunnel * CreateTransitTunnel (uint32_t receiveTunnelID,
|
||||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||||
const uint8_t * layerKey,const uint8_t * ivKey,
|
const uint8_t * layerKey,const uint8_t * ivKey,
|
||||||
bool isGateway, bool isEndpoint)
|
bool isGateway, bool isEndpoint)
|
||||||
{
|
{
|
||||||
if (isEndpoint)
|
if (isEndpoint)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "TransitTunnel endpoint: ", receiveTunnelID, " created");
|
LogPrint (eLogInfo, "TransitTunnel endpoint: ", receiveTunnelID, " created");
|
||||||
return new TransitTunnelEndpoint (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
return new TransitTunnelEndpoint (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||||
}
|
}
|
||||||
else if (isGateway)
|
else if (isGateway)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "TransitTunnel gateway: ", receiveTunnelID, " created");
|
LogPrint (eLogInfo, "TransitTunnel gateway: ", receiveTunnelID, " created");
|
||||||
return new TransitTunnelGateway (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
return new TransitTunnelGateway (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created");
|
LogPrint (eLogInfo, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created");
|
||||||
return new TransitTunnelParticipant (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
return new TransitTunnelParticipant (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
152
TransitTunnel.h
152
TransitTunnel.h
|
@ -14,97 +14,97 @@
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
class TransitTunnel: public TunnelBase
|
class TransitTunnel: public TunnelBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TransitTunnel (uint32_t receiveTunnelID,
|
TransitTunnel (uint32_t receiveTunnelID,
|
||||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||||
const uint8_t * layerKey,const uint8_t * ivKey);
|
const uint8_t * layerKey,const uint8_t * ivKey);
|
||||||
|
|
||||||
virtual size_t GetNumTransmittedBytes () const { return 0; };
|
virtual size_t GetNumTransmittedBytes () const { return 0; };
|
||||||
|
|
||||||
uint32_t GetTunnelID () const { return m_TunnelID; };
|
uint32_t GetTunnelID () const { return m_TunnelID; };
|
||||||
|
|
||||||
// implements TunnelBase
|
// implements TunnelBase
|
||||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||||
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
|
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
|
||||||
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
|
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
|
||||||
uint32_t GetNextTunnelID () const { return m_NextTunnelID; };
|
uint32_t GetNextTunnelID () const { return m_NextTunnelID; };
|
||||||
const i2p::data::IdentHash& GetNextIdentHash () const { return m_NextIdent; };
|
const i2p::data::IdentHash& GetNextIdentHash () const { return m_NextIdent; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint32_t m_TunnelID, m_NextTunnelID;
|
uint32_t m_TunnelID, m_NextTunnelID;
|
||||||
i2p::data::IdentHash m_NextIdent;
|
i2p::data::IdentHash m_NextIdent;
|
||||||
|
|
||||||
i2p::crypto::TunnelEncryption m_Encryption;
|
i2p::crypto::TunnelEncryption m_Encryption;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TransitTunnelParticipant: public TransitTunnel
|
class TransitTunnelParticipant: public TransitTunnel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TransitTunnelParticipant (uint32_t receiveTunnelID,
|
TransitTunnelParticipant (uint32_t receiveTunnelID,
|
||||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||||
const uint8_t * layerKey,const uint8_t * ivKey):
|
const uint8_t * layerKey,const uint8_t * ivKey):
|
||||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
|
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
|
||||||
layerKey, ivKey), m_NumTransmittedBytes (0) {};
|
layerKey, ivKey), m_NumTransmittedBytes (0) {};
|
||||||
~TransitTunnelParticipant ();
|
~TransitTunnelParticipant ();
|
||||||
|
|
||||||
size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; };
|
size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; };
|
||||||
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
|
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
|
||||||
void FlushTunnelDataMsgs ();
|
void FlushTunnelDataMsgs ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
size_t m_NumTransmittedBytes;
|
size_t m_NumTransmittedBytes;
|
||||||
std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
|
std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TransitTunnelGateway: public TransitTunnel
|
class TransitTunnelGateway: public TransitTunnel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TransitTunnelGateway (uint32_t receiveTunnelID,
|
TransitTunnelGateway (uint32_t receiveTunnelID,
|
||||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||||
const uint8_t * layerKey,const uint8_t * ivKey):
|
const uint8_t * layerKey,const uint8_t * ivKey):
|
||||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
|
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
|
||||||
layerKey, ivKey), m_Gateway(this) {};
|
layerKey, ivKey), m_Gateway(this) {};
|
||||||
|
|
||||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||||
void FlushTunnelDataMsgs ();
|
void FlushTunnelDataMsgs ();
|
||||||
size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); };
|
size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::mutex m_SendMutex;
|
std::mutex m_SendMutex;
|
||||||
TunnelGateway m_Gateway;
|
TunnelGateway m_Gateway;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TransitTunnelEndpoint: public TransitTunnel
|
class TransitTunnelEndpoint: public TransitTunnel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TransitTunnelEndpoint (uint32_t receiveTunnelID,
|
TransitTunnelEndpoint (uint32_t receiveTunnelID,
|
||||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||||
const uint8_t * layerKey,const uint8_t * ivKey):
|
const uint8_t * layerKey,const uint8_t * ivKey):
|
||||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey),
|
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey),
|
||||||
m_Endpoint (false) {}; // transit endpoint is always outbound
|
m_Endpoint (false) {}; // transit endpoint is always outbound
|
||||||
|
|
||||||
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
|
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
|
||||||
size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }
|
size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
TunnelEndpoint m_Endpoint;
|
TunnelEndpoint m_Endpoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
TransitTunnel * CreateTransitTunnel (uint32_t receiveTunnelID,
|
TransitTunnel * CreateTransitTunnel (uint32_t receiveTunnelID,
|
||||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||||
const uint8_t * layerKey,const uint8_t * ivKey,
|
const uint8_t * layerKey,const uint8_t * ivKey,
|
||||||
bool isGateway, bool isEndpoint);
|
bool isGateway, bool isEndpoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,73 +13,73 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
struct DHKeysPair // transient keys for transport sessions
|
struct DHKeysPair // transient keys for transport sessions
|
||||||
{
|
{
|
||||||
uint8_t publicKey[256];
|
uint8_t publicKey[256];
|
||||||
uint8_t privateKey[256];
|
uint8_t privateKey[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
class SignedData
|
class SignedData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SignedData () {};
|
SignedData () {};
|
||||||
void Insert (const uint8_t * buf, size_t len)
|
void Insert (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
m_Stream.write ((char *)buf, len);
|
m_Stream.write ((char *)buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void Insert (T t)
|
void Insert (T t)
|
||||||
{
|
{
|
||||||
m_Stream.write ((char *)&t, sizeof (T));
|
m_Stream.write ((char *)&t, sizeof (T));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Verify (const i2p::data::IdentityEx& ident, const uint8_t * signature) const
|
bool Verify (const i2p::data::IdentityEx& ident, const uint8_t * signature) const
|
||||||
{
|
{
|
||||||
return ident.Verify ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
|
return ident.Verify ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sign (const i2p::data::PrivateKeys& keys, uint8_t * signature) const
|
void Sign (const i2p::data::PrivateKeys& keys, uint8_t * signature) const
|
||||||
{
|
{
|
||||||
keys.Sign ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
|
keys.Sign ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::stringstream m_Stream;
|
std::stringstream m_Stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TransportSession
|
class TransportSession
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TransportSession (std::shared_ptr<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),
|
||||||
m_NumSentBytes (0), m_NumReceivedBytes (0)
|
m_NumSentBytes (0), m_NumReceivedBytes (0)
|
||||||
{
|
{
|
||||||
if (m_RemoteRouter)
|
if (m_RemoteRouter)
|
||||||
m_RemoteIdentity = m_RemoteRouter->GetRouterIdentity ();
|
m_RemoteIdentity = m_RemoteRouter->GetRouterIdentity ();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TransportSession () { delete m_DHKeysPair; };
|
virtual ~TransportSession () { delete m_DHKeysPair; };
|
||||||
virtual void Done () = 0;
|
virtual void Done () = 0;
|
||||||
|
|
||||||
std::shared_ptr<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; };
|
||||||
|
|
||||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||||
|
|
||||||
virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0;
|
virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
std::shared_ptr<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
|
||||||
size_t m_NumSentBytes, m_NumReceivedBytes;
|
size_t m_NumSentBytes, m_NumReceivedBytes;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
912
Transports.cpp
912
Transports.cpp
|
@ -12,490 +12,494 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
DHKeysPairSupplier::DHKeysPairSupplier (int size):
|
DHKeysPairSupplier::DHKeysPairSupplier (int size):
|
||||||
m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr)
|
m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
DHKeysPairSupplier::~DHKeysPairSupplier ()
|
DHKeysPairSupplier::~DHKeysPairSupplier ()
|
||||||
{
|
{
|
||||||
Stop ();
|
Stop ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHKeysPairSupplier::Start ()
|
void DHKeysPairSupplier::Start ()
|
||||||
{
|
{
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
m_Thread = new std::thread (std::bind (&DHKeysPairSupplier::Run, this));
|
m_Thread = new std::thread (std::bind (&DHKeysPairSupplier::Run, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHKeysPairSupplier::Stop ()
|
void DHKeysPairSupplier::Stop ()
|
||||||
{
|
{
|
||||||
m_IsRunning = false;
|
m_IsRunning = false;
|
||||||
m_Acquired.notify_one ();
|
m_Acquired.notify_one ();
|
||||||
if (m_Thread)
|
if (m_Thread)
|
||||||
{
|
{
|
||||||
m_Thread->join ();
|
m_Thread->join ();
|
||||||
delete m_Thread;
|
delete m_Thread;
|
||||||
m_Thread = 0;
|
m_Thread = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHKeysPairSupplier::Run ()
|
void DHKeysPairSupplier::Run ()
|
||||||
{
|
{
|
||||||
while (m_IsRunning)
|
while (m_IsRunning)
|
||||||
{
|
{
|
||||||
int num;
|
int num;
|
||||||
while ((num = m_QueueSize - m_Queue.size ()) > 0)
|
while ((num = m_QueueSize - m_Queue.size ()) > 0)
|
||||||
CreateDHKeysPairs (num);
|
CreateDHKeysPairs (num);
|
||||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||||
m_Acquired.wait (l); // wait for element gets aquired
|
m_Acquired.wait (l); // wait for element gets aquired
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHKeysPairSupplier::CreateDHKeysPairs (int num)
|
void DHKeysPairSupplier::CreateDHKeysPairs (int num)
|
||||||
{
|
{
|
||||||
if (num > 0)
|
if (num > 0)
|
||||||
{
|
{
|
||||||
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
||||||
for (int i = 0; i < num; i++)
|
for (int i = 0; i < num; i++)
|
||||||
{
|
{
|
||||||
i2p::transport::DHKeysPair * pair = new i2p::transport::DHKeysPair ();
|
i2p::transport::DHKeysPair * pair = new i2p::transport::DHKeysPair ();
|
||||||
dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey);
|
dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey);
|
||||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||||
m_Queue.push (pair);
|
m_Queue.push (pair);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DHKeysPair * DHKeysPairSupplier::Acquire ()
|
DHKeysPair * DHKeysPairSupplier::Acquire ()
|
||||||
{
|
{
|
||||||
if (!m_Queue.empty ())
|
if (!m_Queue.empty ())
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||||
auto pair = m_Queue.front ();
|
auto pair = m_Queue.front ();
|
||||||
m_Queue.pop ();
|
m_Queue.pop ();
|
||||||
m_Acquired.notify_one ();
|
m_Acquired.notify_one ();
|
||||||
return pair;
|
return pair;
|
||||||
}
|
}
|
||||||
else // queue is empty, create new
|
else // queue is empty, create new
|
||||||
{
|
{
|
||||||
DHKeysPair * pair = new DHKeysPair ();
|
DHKeysPair * pair = new DHKeysPair ();
|
||||||
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
||||||
dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey);
|
dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey);
|
||||||
return pair;
|
return pair;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHKeysPairSupplier::Return (DHKeysPair * pair)
|
void DHKeysPairSupplier::Return (DHKeysPair * pair)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||||
m_Queue.push (pair);
|
m_Queue.push (pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
Transports transports;
|
Transports transports;
|
||||||
|
|
||||||
Transports::Transports ():
|
Transports::Transports ():
|
||||||
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_PeerCleanupTimer (m_Service),
|
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_PeerCleanupTimer (m_Service),
|
||||||
m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys
|
m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys
|
||||||
m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_InBandwidth (0), m_OutBandwidth (0),
|
m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_InBandwidth (0), m_OutBandwidth (0),
|
||||||
m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), m_LastBandwidthUpdateTime (0)
|
m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), m_LastBandwidthUpdateTime (0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Transports::~Transports ()
|
Transports::~Transports ()
|
||||||
{
|
{
|
||||||
Stop ();
|
Stop ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::Start ()
|
void Transports::Start ()
|
||||||
{
|
{
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
m_UPnP.Start ();
|
m_UPnP.Start ();
|
||||||
LogPrint(eLogInfo, "UPnP started");
|
LogPrint(eLogInfo, "UPnP started");
|
||||||
#endif
|
#endif
|
||||||
m_DHKeysPairSupplier.Start ();
|
m_DHKeysPairSupplier.Start ();
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
m_Thread = new std::thread (std::bind (&Transports::Run, this));
|
m_Thread = new std::thread (std::bind (&Transports::Run, this));
|
||||||
// create acceptors
|
// create acceptors
|
||||||
auto addresses = context.GetRouterInfo ().GetAddresses ();
|
auto addresses = context.GetRouterInfo ().GetAddresses ();
|
||||||
for (auto& address : addresses)
|
for (auto& address : addresses)
|
||||||
{
|
{
|
||||||
if (!m_NTCPServer)
|
if (!m_NTCPServer)
|
||||||
{
|
{
|
||||||
m_NTCPServer = new NTCPServer (address.port);
|
m_NTCPServer = new NTCPServer (address.port);
|
||||||
m_NTCPServer->Start ();
|
m_NTCPServer->Start ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address.transportStyle == RouterInfo::eTransportSSU && address.host.is_v4 ())
|
if (address.transportStyle == RouterInfo::eTransportSSU && address.host.is_v4 ())
|
||||||
{
|
{
|
||||||
if (!m_SSUServer)
|
if (!m_SSUServer)
|
||||||
{
|
{
|
||||||
m_SSUServer = new SSUServer (address.port);
|
m_SSUServer = new SSUServer (address.port);
|
||||||
LogPrint ("Start listening UDP port ", address.port);
|
LogPrint ("Start listening UDP port ", address.port);
|
||||||
m_SSUServer->Start ();
|
m_SSUServer->Start ();
|
||||||
DetectExternalIP ();
|
DetectExternalIP ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint ("SSU server already exists");
|
LogPrint ("SSU server already exists");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_PeerCleanupTimer.expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
m_PeerCleanupTimer.expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
||||||
m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::Stop ()
|
void Transports::Stop ()
|
||||||
{
|
{
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
m_UPnP.Stop ();
|
m_UPnP.Stop ();
|
||||||
LogPrint(eLogInfo, "UPnP stopped");
|
LogPrint(eLogInfo, "UPnP stopped");
|
||||||
#endif
|
#endif
|
||||||
m_PeerCleanupTimer.cancel ();
|
m_PeerCleanupTimer.cancel ();
|
||||||
m_Peers.clear ();
|
m_Peers.clear ();
|
||||||
if (m_SSUServer)
|
if (m_SSUServer)
|
||||||
{
|
{
|
||||||
m_SSUServer->Stop ();
|
m_SSUServer->Stop ();
|
||||||
delete m_SSUServer;
|
delete m_SSUServer;
|
||||||
m_SSUServer = nullptr;
|
m_SSUServer = nullptr;
|
||||||
}
|
}
|
||||||
if (m_NTCPServer)
|
if (m_NTCPServer)
|
||||||
{
|
{
|
||||||
m_NTCPServer->Stop ();
|
m_NTCPServer->Stop ();
|
||||||
delete m_NTCPServer;
|
delete m_NTCPServer;
|
||||||
m_NTCPServer = nullptr;
|
m_NTCPServer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_DHKeysPairSupplier.Stop ();
|
m_DHKeysPairSupplier.Stop ();
|
||||||
m_IsRunning = false;
|
m_IsRunning = false;
|
||||||
m_Service.stop ();
|
m_Service.stop ();
|
||||||
if (m_Thread)
|
if (m_Thread)
|
||||||
{
|
{
|
||||||
m_Thread->join ();
|
m_Thread->join ();
|
||||||
delete m_Thread;
|
delete m_Thread;
|
||||||
m_Thread = nullptr;
|
m_Thread = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::Run ()
|
void Transports::Run ()
|
||||||
{
|
{
|
||||||
while (m_IsRunning)
|
while (m_IsRunning)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_Service.run ();
|
m_Service.run ();
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
LogPrint ("Transports: ", ex.what ());
|
LogPrint ("Transports: ", ex.what ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::UpdateBandwidth ()
|
void Transports::UpdateBandwidth ()
|
||||||
{
|
{
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
if (m_LastBandwidthUpdateTime > 0)
|
if (m_LastBandwidthUpdateTime > 0)
|
||||||
{
|
{
|
||||||
auto delta = ts - m_LastBandwidthUpdateTime;
|
auto delta = ts - m_LastBandwidthUpdateTime;
|
||||||
if (delta > 0)
|
if (delta > 0)
|
||||||
{
|
{
|
||||||
m_InBandwidth = (m_TotalReceivedBytes - m_LastInBandwidthUpdateBytes)*1000/delta; // per second
|
m_InBandwidth = (m_TotalReceivedBytes - m_LastInBandwidthUpdateBytes)*1000/delta; // per second
|
||||||
m_OutBandwidth = (m_TotalSentBytes - m_LastOutBandwidthUpdateBytes)*1000/delta; // per second
|
m_OutBandwidth = (m_TotalSentBytes - m_LastOutBandwidthUpdateBytes)*1000/delta; // per second
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_LastBandwidthUpdateTime = ts;
|
m_LastBandwidthUpdateTime = ts;
|
||||||
m_LastInBandwidthUpdateBytes = m_TotalReceivedBytes;
|
m_LastInBandwidthUpdateBytes = m_TotalReceivedBytes;
|
||||||
m_LastOutBandwidthUpdateBytes = m_TotalSentBytes;
|
m_LastOutBandwidthUpdateBytes = m_TotalSentBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Transports::IsBandwidthExceeded () const
|
bool Transports::IsBandwidthExceeded () const
|
||||||
{
|
{
|
||||||
if (i2p::context.GetRouterInfo ().IsHighBandwidth ()) return false;
|
if (i2p::context.GetRouterInfo ().IsHighBandwidth ()) return false;
|
||||||
return std::max (m_InBandwidth, m_OutBandwidth) > LOW_BANDWIDTH_LIMIT;
|
return std::max (m_InBandwidth, m_OutBandwidth) > LOW_BANDWIDTH_LIMIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
|
void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
SendMessages (ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > {msg });
|
SendMessages (ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > {msg });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs)
|
void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs)
|
||||||
{
|
{
|
||||||
m_Service.post (std::bind (&Transports::PostMessages, this, ident, msgs));
|
m_Service.post (std::bind (&Transports::PostMessages, this, ident, msgs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs)
|
void Transports::PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs)
|
||||||
{
|
{
|
||||||
if (ident == i2p::context.GetRouterInfo ().GetIdentHash ())
|
if (ident == i2p::context.GetRouterInfo ().GetIdentHash ())
|
||||||
{
|
{
|
||||||
// we send it to ourself
|
// we send it to ourself
|
||||||
for (auto it: msgs)
|
for (auto it: msgs)
|
||||||
i2p::HandleI2NPMessage (it);
|
i2p::HandleI2NPMessage (it);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it == m_Peers.end ())
|
if (it == m_Peers.end ())
|
||||||
{
|
{
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto r = netdb.FindRouter (ident);
|
auto r = netdb.FindRouter (ident);
|
||||||
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},
|
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},
|
||||||
i2p::util::GetSecondsSinceEpoch () })).first;
|
i2p::util::GetSecondsSinceEpoch () })).first;
|
||||||
connected = ConnectToPeer (ident, it->second);
|
connected = ConnectToPeer (ident, it->second);
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Transports::PostMessages ", ex.what ());
|
LogPrint (eLogError, "Transports::PostMessages ", ex.what ());
|
||||||
}
|
}
|
||||||
if (!connected) return;
|
if (!connected) return;
|
||||||
}
|
}
|
||||||
if (!it->second.sessions.empty ())
|
if (!it->second.sessions.empty ())
|
||||||
it->second.sessions.front ()->SendI2NPMessages (msgs);
|
it->second.sessions.front ()->SendI2NPMessages (msgs);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (auto it1: msgs)
|
for (auto it1: msgs)
|
||||||
it->second.delayedMessages.push_back (it1);
|
it->second.delayedMessages.push_back (it1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer)
|
bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer)
|
||||||
{
|
{
|
||||||
if (peer.router) // we have RI already
|
if (peer.router) // we have RI already
|
||||||
{
|
{
|
||||||
if (!peer.numAttempts) // NTCP
|
if (!peer.numAttempts) // NTCP
|
||||||
{
|
{
|
||||||
peer.numAttempts++;
|
peer.numAttempts++;
|
||||||
auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ());
|
auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ());
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
#if BOOST_VERSION >= 104900
|
#if BOOST_VERSION >= 104900
|
||||||
if (!address->host.is_unspecified ()) // we have address now
|
if (!address->host.is_unspecified ()) // we have address now
|
||||||
#else
|
#else
|
||||||
boost::system::error_code ecode;
|
boost::system::error_code ecode;
|
||||||
address->host.to_string (ecode);
|
address->host.to_string (ecode);
|
||||||
if (!ecode)
|
if (!ecode)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ())
|
if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ())
|
||||||
{
|
{
|
||||||
auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router);
|
auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router);
|
||||||
m_NTCPServer->Connect (address->host, address->port, s);
|
m_NTCPServer->Connect (address->host, address->port, s);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // we don't have address
|
else // we don't have address
|
||||||
{
|
{
|
||||||
if (address->addressString.length () > 0) // trying to resolve
|
if (address->addressString.length () > 0) // trying to resolve
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Resolving ", address->addressString);
|
LogPrint (eLogInfo, "Resolving ", address->addressString);
|
||||||
NTCPResolve (address->addressString, ident);
|
NTCPResolve (address->addressString, ident);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (peer.numAttempts == 1)// SSU
|
else if (peer.numAttempts == 1)// SSU
|
||||||
{
|
{
|
||||||
peer.numAttempts++;
|
peer.numAttempts++;
|
||||||
if (m_SSUServer)
|
if (m_SSUServer)
|
||||||
{
|
{
|
||||||
if (m_SSUServer->GetSession (peer.router))
|
if (m_SSUServer->GetSession (peer.router))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogPrint (eLogError, "No NTCP and SSU addresses available");
|
LogPrint (eLogError, "No NTCP and SSU addresses available");
|
||||||
peer.Done ();
|
peer.Done ();
|
||||||
m_Peers.erase (ident);
|
m_Peers.erase (ident);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else // otherwise request RI
|
else // otherwise request RI
|
||||||
{
|
{
|
||||||
LogPrint ("Router not found. Requested");
|
LogPrint ("Router not found. Requested");
|
||||||
i2p::data::netdb.RequestDestination (ident, std::bind (
|
i2p::data::netdb.RequestDestination (ident, std::bind (
|
||||||
&Transports::RequestComplete, this, std::placeholders::_1, ident));
|
&Transports::RequestComplete, this, std::placeholders::_1, ident));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
|
void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
|
||||||
{
|
{
|
||||||
m_Service.post (std::bind (&Transports::HandleRequestComplete, this, r, ident));
|
m_Service.post (std::bind (&Transports::HandleRequestComplete, this, r, ident));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
|
void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
|
||||||
{
|
{
|
||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it != m_Peers.end ())
|
if (it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
LogPrint ("Router found. Trying to connect");
|
LogPrint ("Router found. Trying to connect");
|
||||||
it->second.router = r;
|
it->second.router = r;
|
||||||
ConnectToPeer (ident, it->second);
|
ConnectToPeer (ident, it->second);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint ("Router not found. Failed to send messages");
|
LogPrint ("Router not found. Failed to send messages");
|
||||||
m_Peers.erase (it);
|
m_Peers.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident)
|
void Transports::NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident)
|
||||||
{
|
{
|
||||||
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(m_Service);
|
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(m_Service);
|
||||||
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (addr, ""),
|
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (addr, ""),
|
||||||
std::bind (&Transports::HandleNTCPResolve, this,
|
std::bind (&Transports::HandleNTCPResolve, this,
|
||||||
std::placeholders::_1, std::placeholders::_2, ident, resolver));
|
std::placeholders::_1, std::placeholders::_2, ident, resolver));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
void Transports::HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||||
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
|
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
|
||||||
{
|
{
|
||||||
auto it1 = m_Peers.find (ident);
|
auto it1 = m_Peers.find (ident);
|
||||||
if (it1 != m_Peers.end ())
|
if (it1 != m_Peers.end ())
|
||||||
{
|
{
|
||||||
auto& peer = it1->second;
|
auto& peer = it1->second;
|
||||||
if (!ecode && peer.router)
|
if (!ecode && peer.router)
|
||||||
{
|
{
|
||||||
auto address = (*it).endpoint ().address ();
|
auto address = (*it).endpoint ().address ();
|
||||||
LogPrint (eLogInfo, (*it).host_name (), " has been resolved to ", address);
|
LogPrint (eLogInfo, (*it).host_name (), " has been resolved to ", address);
|
||||||
auto addr = peer.router->GetNTCPAddress ();
|
auto addr = peer.router->GetNTCPAddress ();
|
||||||
if (addr)
|
if (addr)
|
||||||
{
|
{
|
||||||
auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router);
|
auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router);
|
||||||
m_NTCPServer->Connect (address, addr->port, s);
|
m_NTCPServer->Connect (address, addr->port, s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogPrint (eLogError, "Unable to resolve NTCP address: ", ecode.message ());
|
LogPrint (eLogError, "Unable to resolve NTCP address: ", ecode.message ());
|
||||||
m_Peers.erase (it1);
|
m_Peers.erase (it1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::CloseSession (std::shared_ptr<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 (std::bind (&Transports::PostCloseSession, this, router));
|
m_Service.post (std::bind (&Transports::PostCloseSession, this, router));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::PostCloseSession (std::shared_ptr<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
|
||||||
{
|
{
|
||||||
m_SSUServer->DeleteSession (ssuSession);
|
m_SSUServer->DeleteSession (ssuSession);
|
||||||
LogPrint ("SSU session closed");
|
LogPrint ("SSU session closed");
|
||||||
}
|
}
|
||||||
// TODO: delete NTCP
|
// TODO: delete NTCP
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::DetectExternalIP ()
|
void Transports::DetectExternalIP ()
|
||||||
{
|
{
|
||||||
if (m_SSUServer)
|
if (m_SSUServer)
|
||||||
{
|
{
|
||||||
i2p::context.SetStatus (eRouterStatusTesting);
|
i2p::context.SetStatus (eRouterStatusTesting);
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
auto router = i2p::data::netdb.GetRandomPeerTestRouter ();
|
auto router = i2p::data::netdb.GetRandomPeerTestRouter ();
|
||||||
if (router && router->IsSSU ())
|
if (router && router->IsSSU ())
|
||||||
m_SSUServer->GetSession (router, true); // peer test
|
m_SSUServer->GetSession (router, true); // peer test
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// if not peer test capable routers found pick any
|
// if not peer test capable routers found pick any
|
||||||
router = i2p::data::netdb.GetRandomRouter ();
|
router = i2p::data::netdb.GetRandomRouter ();
|
||||||
if (router && router->IsSSU ())
|
if (router && router->IsSSU ())
|
||||||
m_SSUServer->GetSession (router); // no peer test
|
m_SSUServer->GetSession (router); // no peer test
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "Can't detect external IP. SSU is not available");
|
LogPrint (eLogError, "Can't detect external IP. SSU is not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
DHKeysPair * Transports::GetNextDHKeysPair ()
|
DHKeysPair * Transports::GetNextDHKeysPair ()
|
||||||
{
|
{
|
||||||
return m_DHKeysPairSupplier.Acquire ();
|
return m_DHKeysPairSupplier.Acquire ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::ReuseDHKeysPair (DHKeysPair * pair)
|
void Transports::ReuseDHKeysPair (DHKeysPair * pair)
|
||||||
{
|
{
|
||||||
m_DHKeysPairSupplier.Return (pair);
|
m_DHKeysPairSupplier.Return (pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::PeerConnected (std::shared_ptr<TransportSession> session)
|
void Transports::PeerConnected (std::shared_ptr<TransportSession> session)
|
||||||
{
|
{
|
||||||
m_Service.post([session, this]()
|
m_Service.post([session, this]()
|
||||||
{
|
{
|
||||||
auto ident = session->GetRemoteIdentity ().GetIdentHash ();
|
auto ident = session->GetRemoteIdentity ().GetIdentHash ();
|
||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it != m_Peers.end ())
|
if (it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
it->second.sessions.push_back (session);
|
it->second.sessions.push_back (session);
|
||||||
session->SendI2NPMessages (it->second.delayedMessages);
|
session->SendI2NPMessages (it->second.delayedMessages);
|
||||||
it->second.delayedMessages.clear ();
|
it->second.delayedMessages.clear ();
|
||||||
}
|
}
|
||||||
else // incoming connection
|
else // incoming connection
|
||||||
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch () }));
|
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch () }));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::PeerDisconnected (std::shared_ptr<TransportSession> session)
|
void Transports::PeerDisconnected (std::shared_ptr<TransportSession> session)
|
||||||
{
|
{
|
||||||
m_Service.post([session, this]()
|
m_Service.post([session, this]()
|
||||||
{
|
{
|
||||||
auto ident = session->GetRemoteIdentity ().GetIdentHash ();
|
auto ident = session->GetRemoteIdentity ().GetIdentHash ();
|
||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it != m_Peers.end ())
|
if (it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
it->second.sessions.remove (session);
|
it->second.sessions.remove (session);
|
||||||
if (it->second.sessions.empty ()) // TODO: why?
|
if (it->second.sessions.empty ()) // TODO: why?
|
||||||
{
|
{
|
||||||
if (it->second.delayedMessages.size () > 0)
|
if (it->second.delayedMessages.size () > 0)
|
||||||
ConnectToPeer (ident, it->second);
|
ConnectToPeer (ident, it->second);
|
||||||
else
|
else
|
||||||
m_Peers.erase (it);
|
m_Peers.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Transports::IsConnected (const i2p::data::IdentHash& ident) const
|
bool Transports::IsConnected (const i2p::data::IdentHash& ident) const
|
||||||
{
|
{
|
||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
return it != m_Peers.end ();
|
return it != m_Peers.end ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::HandlePeerCleanupTimer (const boost::system::error_code& ecode)
|
void Transports::HandlePeerCleanupTimer (const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
for (auto it = m_Peers.begin (); it != m_Peers.end (); )
|
for (auto it = m_Peers.begin (); it != m_Peers.end (); )
|
||||||
{
|
{
|
||||||
if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT)
|
if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
|
LogPrint (eLogError, "Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
|
||||||
it = m_Peers.erase (it);
|
it = m_Peers.erase (it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
UpdateBandwidth (); // TODO: use separate timer(s) for it
|
UpdateBandwidth (); // TODO: use separate timer(s) for it
|
||||||
if (i2p::context.GetStatus () == eRouterStatusTesting) // if still testing, repeat peer test
|
if (i2p::context.GetStatus () == eRouterStatusTesting) // if still testing, repeat peer test
|
||||||
DetectExternalIP ();
|
DetectExternalIP ();
|
||||||
m_PeerCleanupTimer.expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
m_PeerCleanupTimer.expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
||||||
m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer () const
|
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer () const
|
||||||
{
|
{
|
||||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
if(m_Peers.empty()) // ensure m.Peers.size() >= 1
|
||||||
auto it = m_Peers.begin ();
|
return nullptr;
|
||||||
std::advance (it, rnd.GenerateWord32 (0, m_Peers.size () - 1));
|
|
||||||
return it != m_Peers.end () ? it->second.router : nullptr;
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator();
|
||||||
}
|
auto it = m_Peers.begin();
|
||||||
|
std::advance(it, rnd.GenerateWord32(0, m_Peers.size () - 1));
|
||||||
|
|
||||||
|
return it->second.router;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
204
Transports.h
204
Transports.h
|
@ -28,133 +28,133 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
class DHKeysPairSupplier
|
class DHKeysPairSupplier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DHKeysPairSupplier (int size);
|
DHKeysPairSupplier (int size);
|
||||||
~DHKeysPairSupplier ();
|
~DHKeysPairSupplier ();
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
DHKeysPair * Acquire ();
|
DHKeysPair * Acquire ();
|
||||||
void Return (DHKeysPair * pair);
|
void Return (DHKeysPair * pair);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void CreateDHKeysPairs (int num);
|
void CreateDHKeysPairs (int num);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const int m_QueueSize;
|
const int m_QueueSize;
|
||||||
std::queue<DHKeysPair *> m_Queue;
|
std::queue<DHKeysPair *> m_Queue;
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
std::condition_variable m_Acquired;
|
std::condition_variable m_Acquired;
|
||||||
std::mutex m_AcquiredMutex;
|
std::mutex m_AcquiredMutex;
|
||||||
CryptoPP::AutoSeededRandomPool m_Rnd;
|
CryptoPP::AutoSeededRandomPool m_Rnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Peer
|
struct Peer
|
||||||
{
|
{
|
||||||
int numAttempts;
|
int numAttempts;
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> router;
|
std::shared_ptr<const i2p::data::RouterInfo> router;
|
||||||
std::list<std::shared_ptr<TransportSession> > sessions;
|
std::list<std::shared_ptr<TransportSession> > sessions;
|
||||||
uint64_t creationTime;
|
uint64_t creationTime;
|
||||||
std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
|
std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
|
||||||
|
|
||||||
void Done ()
|
void Done ()
|
||||||
{
|
{
|
||||||
for (auto it: sessions)
|
for (auto it: sessions)
|
||||||
it->Done ();
|
it->Done ();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds
|
const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds
|
||||||
const uint32_t LOW_BANDWIDTH_LIMIT = 32*1024; // 32KBs
|
const uint32_t LOW_BANDWIDTH_LIMIT = 32*1024; // 32KBs
|
||||||
class Transports
|
class Transports
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Transports ();
|
Transports ();
|
||||||
~Transports ();
|
~Transports ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
boost::asio::io_service& GetService () { return m_Service; };
|
boost::asio::io_service& GetService () { return m_Service; };
|
||||||
i2p::transport::DHKeysPair * GetNextDHKeysPair ();
|
i2p::transport::DHKeysPair * GetNextDHKeysPair ();
|
||||||
void ReuseDHKeysPair (DHKeysPair * pair);
|
void ReuseDHKeysPair (DHKeysPair * pair);
|
||||||
|
|
||||||
void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg);
|
void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg);
|
||||||
void SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs);
|
void SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs);
|
||||||
void CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
|
void CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
|
||||||
|
|
||||||
void PeerConnected (std::shared_ptr<TransportSession> session);
|
void PeerConnected (std::shared_ptr<TransportSession> session);
|
||||||
void PeerDisconnected (std::shared_ptr<TransportSession> session);
|
void PeerDisconnected (std::shared_ptr<TransportSession> session);
|
||||||
bool IsConnected (const i2p::data::IdentHash& ident) const;
|
bool IsConnected (const i2p::data::IdentHash& ident) const;
|
||||||
|
|
||||||
void UpdateSentBytes (uint64_t numBytes) { m_TotalSentBytes += numBytes; };
|
void UpdateSentBytes (uint64_t numBytes) { m_TotalSentBytes += numBytes; };
|
||||||
void UpdateReceivedBytes (uint64_t numBytes) { m_TotalReceivedBytes += numBytes; };
|
void UpdateReceivedBytes (uint64_t numBytes) { m_TotalReceivedBytes += numBytes; };
|
||||||
uint64_t GetTotalSentBytes () const { return m_TotalSentBytes; };
|
uint64_t GetTotalSentBytes () const { return m_TotalSentBytes; };
|
||||||
uint64_t GetTotalReceivedBytes () const { return m_TotalReceivedBytes; };
|
uint64_t GetTotalReceivedBytes () const { return m_TotalReceivedBytes; };
|
||||||
uint32_t GetInBandwidth () const { return m_InBandwidth; }; // bytes per second
|
uint32_t GetInBandwidth () const { return m_InBandwidth; }; // bytes per second
|
||||||
uint32_t GetOutBandwidth () const { return m_OutBandwidth; }; // bytes per second
|
uint32_t GetOutBandwidth () const { return m_OutBandwidth; }; // bytes per second
|
||||||
bool IsBandwidthExceeded () const;
|
bool IsBandwidthExceeded () const;
|
||||||
size_t GetNumPeers () const { return m_Peers.size (); };
|
size_t GetNumPeers () const { return m_Peers.size (); };
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer () const;
|
std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer () const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
|
void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
|
||||||
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
|
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
|
||||||
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
|
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
|
||||||
void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
|
void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
|
||||||
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
|
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
|
||||||
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
|
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
void NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident);
|
void NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident);
|
||||||
void HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
void HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||||
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
|
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
|
||||||
|
|
||||||
void UpdateBandwidth ();
|
void UpdateBandwidth ();
|
||||||
void DetectExternalIP ();
|
void DetectExternalIP ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
boost::asio::io_service m_Service;
|
boost::asio::io_service m_Service;
|
||||||
boost::asio::io_service::work m_Work;
|
boost::asio::io_service::work m_Work;
|
||||||
boost::asio::deadline_timer m_PeerCleanupTimer;
|
boost::asio::deadline_timer m_PeerCleanupTimer;
|
||||||
|
|
||||||
NTCPServer * m_NTCPServer;
|
NTCPServer * m_NTCPServer;
|
||||||
SSUServer * m_SSUServer;
|
SSUServer * m_SSUServer;
|
||||||
std::map<i2p::data::IdentHash, Peer> m_Peers;
|
std::map<i2p::data::IdentHash, Peer> m_Peers;
|
||||||
|
|
||||||
DHKeysPairSupplier m_DHKeysPairSupplier;
|
DHKeysPairSupplier m_DHKeysPairSupplier;
|
||||||
|
|
||||||
std::atomic<uint64_t> m_TotalSentBytes, m_TotalReceivedBytes;
|
std::atomic<uint64_t> m_TotalSentBytes, m_TotalReceivedBytes;
|
||||||
uint32_t m_InBandwidth, m_OutBandwidth;
|
uint32_t m_InBandwidth, m_OutBandwidth;
|
||||||
uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes;
|
uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes;
|
||||||
uint64_t m_LastBandwidthUpdateTime;
|
uint64_t m_LastBandwidthUpdateTime;
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
UPnP m_UPnP;
|
UPnP m_UPnP;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
const NTCPServer * GetNTCPServer () const { return m_NTCPServer; };
|
const NTCPServer * GetNTCPServer () const { return m_NTCPServer; };
|
||||||
const SSUServer * GetSSUServer () const { return m_SSUServer; };
|
const SSUServer * GetSSUServer () const { return m_SSUServer; };
|
||||||
const decltype(m_Peers)& GetPeers () const { return m_Peers; };
|
const decltype(m_Peers)& GetPeers () const { return m_Peers; };
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Transports transports;
|
extern Transports transports;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
1360
Tunnel.cpp
1360
Tunnel.cpp
File diff suppressed because it is too large
Load diff
310
Tunnel.h
310
Tunnel.h
|
@ -21,183 +21,183 @@
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
|
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
|
||||||
const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute
|
const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute
|
||||||
const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes
|
const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes
|
||||||
const int TUNNEL_CREATION_TIMEOUT = 30; // 30 seconds
|
const int TUNNEL_CREATION_TIMEOUT = 30; // 30 seconds
|
||||||
const int STANDARD_NUM_RECORDS = 5; // in VariableTunnelBuild message
|
const int STANDARD_NUM_RECORDS = 5; // in VariableTunnelBuild message
|
||||||
|
|
||||||
enum TunnelState
|
enum TunnelState
|
||||||
{
|
{
|
||||||
eTunnelStatePending,
|
eTunnelStatePending,
|
||||||
eTunnelStateBuildReplyReceived,
|
eTunnelStateBuildReplyReceived,
|
||||||
eTunnelStateBuildFailed,
|
eTunnelStateBuildFailed,
|
||||||
eTunnelStateEstablished,
|
eTunnelStateEstablished,
|
||||||
eTunnelStateTestFailed,
|
eTunnelStateTestFailed,
|
||||||
eTunnelStateFailed,
|
eTunnelStateFailed,
|
||||||
eTunnelStateExpiring
|
eTunnelStateExpiring
|
||||||
};
|
};
|
||||||
|
|
||||||
class OutboundTunnel;
|
class OutboundTunnel;
|
||||||
class InboundTunnel;
|
class InboundTunnel;
|
||||||
class Tunnel: public TunnelBase
|
class Tunnel: public TunnelBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Tunnel (std::shared_ptr<const TunnelConfig> config);
|
Tunnel (std::shared_ptr<const TunnelConfig> config);
|
||||||
~Tunnel ();
|
~Tunnel ();
|
||||||
|
|
||||||
void Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
|
void Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
|
||||||
|
|
||||||
std::shared_ptr<const TunnelConfig> GetTunnelConfig () const { return m_Config; }
|
std::shared_ptr<const TunnelConfig> GetTunnelConfig () const { return m_Config; }
|
||||||
TunnelState GetState () const { return m_State; };
|
TunnelState GetState () const { return m_State; };
|
||||||
void SetState (TunnelState state) { m_State = state; };
|
void SetState (TunnelState state) { m_State = state; };
|
||||||
bool IsEstablished () const { return m_State == eTunnelStateEstablished; };
|
bool IsEstablished () const { return m_State == eTunnelStateEstablished; };
|
||||||
bool IsFailed () const { return m_State == eTunnelStateFailed; };
|
bool IsFailed () const { return m_State == eTunnelStateFailed; };
|
||||||
bool IsRecreated () const { return m_IsRecreated; };
|
bool IsRecreated () const { return m_IsRecreated; };
|
||||||
void SetIsRecreated () { m_IsRecreated = true; };
|
void SetIsRecreated () { m_IsRecreated = true; };
|
||||||
|
|
||||||
std::shared_ptr<TunnelPool> GetTunnelPool () const { return m_Pool; };
|
std::shared_ptr<TunnelPool> GetTunnelPool () const { return m_Pool; };
|
||||||
void SetTunnelPool (std::shared_ptr<TunnelPool> pool) { m_Pool = pool; };
|
void SetTunnelPool (std::shared_ptr<TunnelPool> pool) { m_Pool = pool; };
|
||||||
|
|
||||||
bool HandleTunnelBuildResponse (uint8_t * msg, size_t len);
|
bool HandleTunnelBuildResponse (uint8_t * msg, size_t len);
|
||||||
|
|
||||||
// implements TunnelBase
|
// implements TunnelBase
|
||||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||||
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
|
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
|
||||||
uint32_t GetNextTunnelID () const { return m_Config->GetFirstHop ()->tunnelID; };
|
uint32_t GetNextTunnelID () const { return m_Config->GetFirstHop ()->tunnelID; };
|
||||||
const i2p::data::IdentHash& GetNextIdentHash () const { return m_Config->GetFirstHop ()->router->GetIdentHash (); };
|
const i2p::data::IdentHash& GetNextIdentHash () const { return m_Config->GetFirstHop ()->router->GetIdentHash (); };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::shared_ptr<const TunnelConfig> m_Config;
|
std::shared_ptr<const TunnelConfig> m_Config;
|
||||||
std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null
|
std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null
|
||||||
TunnelState m_State;
|
TunnelState m_State;
|
||||||
bool m_IsRecreated;
|
bool m_IsRecreated;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OutboundTunnel: public Tunnel
|
class OutboundTunnel: public Tunnel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
OutboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Gateway (this) {};
|
OutboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Gateway (this) {};
|
||||||
|
|
||||||
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg);
|
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg);
|
||||||
void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
|
void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
|
||||||
std::shared_ptr<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 (); };
|
||||||
|
|
||||||
// implements TunnelBase
|
// implements TunnelBase
|
||||||
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
|
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
|
||||||
uint32_t GetTunnelID () const { return GetNextTunnelID (); };
|
uint32_t GetTunnelID () const { return GetNextTunnelID (); };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::mutex m_SendMutex;
|
std::mutex m_SendMutex;
|
||||||
TunnelGateway m_Gateway;
|
TunnelGateway m_Gateway;
|
||||||
};
|
};
|
||||||
|
|
||||||
class InboundTunnel: public Tunnel, public std::enable_shared_from_this<InboundTunnel>
|
class InboundTunnel: public Tunnel, public std::enable_shared_from_this<InboundTunnel>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
InboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Endpoint (true) {};
|
InboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Endpoint (true) {};
|
||||||
void HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg);
|
void HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
|
size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
|
||||||
|
|
||||||
// implements TunnelBase
|
// implements TunnelBase
|
||||||
uint32_t GetTunnelID () const { return GetTunnelConfig ()->GetLastHop ()->nextTunnelID; };
|
uint32_t GetTunnelID () const { return GetTunnelConfig ()->GetLastHop ()->nextTunnelID; };
|
||||||
private:
|
private:
|
||||||
|
|
||||||
TunnelEndpoint m_Endpoint;
|
TunnelEndpoint m_Endpoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Tunnels
|
class Tunnels
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Tunnels ();
|
Tunnels ();
|
||||||
~Tunnels ();
|
~Tunnels ();
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
std::shared_ptr<InboundTunnel> GetInboundTunnel (uint32_t tunnelID);
|
std::shared_ptr<InboundTunnel> GetInboundTunnel (uint32_t tunnelID);
|
||||||
std::shared_ptr<InboundTunnel> GetPendingInboundTunnel (uint32_t replyMsgID);
|
std::shared_ptr<InboundTunnel> GetPendingInboundTunnel (uint32_t replyMsgID);
|
||||||
std::shared_ptr<OutboundTunnel> GetPendingOutboundTunnel (uint32_t replyMsgID);
|
std::shared_ptr<OutboundTunnel> GetPendingOutboundTunnel (uint32_t replyMsgID);
|
||||||
std::shared_ptr<InboundTunnel> GetNextInboundTunnel ();
|
std::shared_ptr<InboundTunnel> GetNextInboundTunnel ();
|
||||||
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel ();
|
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel ();
|
||||||
std::shared_ptr<TunnelPool> GetExploratoryPool () const { return m_ExploratoryPool; };
|
std::shared_ptr<TunnelPool> GetExploratoryPool () const { return m_ExploratoryPool; };
|
||||||
TransitTunnel * GetTransitTunnel (uint32_t tunnelID);
|
TransitTunnel * GetTransitTunnel (uint32_t tunnelID);
|
||||||
int GetTransitTunnelsExpirationTimeout ();
|
int GetTransitTunnelsExpirationTimeout ();
|
||||||
void AddTransitTunnel (TransitTunnel * tunnel);
|
void AddTransitTunnel (TransitTunnel * tunnel);
|
||||||
void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel);
|
void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel);
|
||||||
void AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel);
|
void AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel);
|
||||||
void PostTunnelData (std::shared_ptr<I2NPMessage> msg);
|
void PostTunnelData (std::shared_ptr<I2NPMessage> msg);
|
||||||
void PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
void PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
||||||
template<class TTunnel>
|
template<class TTunnel>
|
||||||
std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
|
std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
|
||||||
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel);
|
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel);
|
||||||
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel);
|
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel);
|
||||||
std::shared_ptr<TunnelPool> CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOuboundHops, int numInboundTunnels, int numOutboundTunnels);
|
std::shared_ptr<TunnelPool> CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOuboundHops, int numInboundTunnels, int numOutboundTunnels);
|
||||||
void DeleteTunnelPool (std::shared_ptr<TunnelPool> pool);
|
void DeleteTunnelPool (std::shared_ptr<TunnelPool> pool);
|
||||||
void StopTunnelPool (std::shared_ptr<TunnelPool> pool);
|
void StopTunnelPool (std::shared_ptr<TunnelPool> pool);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
template<class TTunnel>
|
template<class TTunnel>
|
||||||
std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels);
|
std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels);
|
||||||
|
|
||||||
void HandleTunnelGatewayMsg (TunnelBase * tunnel, std::shared_ptr<I2NPMessage> msg);
|
void HandleTunnelGatewayMsg (TunnelBase * tunnel, std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void ManageTunnels ();
|
void ManageTunnels ();
|
||||||
void ManageOutboundTunnels ();
|
void ManageOutboundTunnels ();
|
||||||
void ManageInboundTunnels ();
|
void ManageInboundTunnels ();
|
||||||
void ManageTransitTunnels ();
|
void ManageTransitTunnels ();
|
||||||
void ManagePendingTunnels ();
|
void ManagePendingTunnels ();
|
||||||
template<class PendingTunnels>
|
template<class PendingTunnels>
|
||||||
void ManagePendingTunnels (PendingTunnels& pendingTunnels);
|
void ManagePendingTunnels (PendingTunnels& pendingTunnels);
|
||||||
void ManageTunnelPools ();
|
void ManageTunnelPools ();
|
||||||
|
|
||||||
void CreateZeroHopsInboundTunnel ();
|
void CreateZeroHopsInboundTunnel ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_PendingInboundTunnels; // by replyMsgID
|
std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_PendingInboundTunnels; // by replyMsgID
|
||||||
std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID
|
std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID
|
||||||
std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_InboundTunnels;
|
std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_InboundTunnels;
|
||||||
std::list<std::shared_ptr<OutboundTunnel> > m_OutboundTunnels;
|
std::list<std::shared_ptr<OutboundTunnel> > m_OutboundTunnels;
|
||||||
std::mutex m_TransitTunnelsMutex;
|
std::mutex m_TransitTunnelsMutex;
|
||||||
std::map<uint32_t, TransitTunnel *> m_TransitTunnels;
|
std::map<uint32_t, TransitTunnel *> m_TransitTunnels;
|
||||||
std::mutex m_PoolsMutex;
|
std::mutex m_PoolsMutex;
|
||||||
std::list<std::shared_ptr<TunnelPool>> m_Pools;
|
std::list<std::shared_ptr<TunnelPool>> m_Pools;
|
||||||
std::shared_ptr<TunnelPool> m_ExploratoryPool;
|
std::shared_ptr<TunnelPool> m_ExploratoryPool;
|
||||||
i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
|
i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
|
||||||
|
|
||||||
// some stats
|
// some stats
|
||||||
int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations;
|
int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; };
|
const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; };
|
||||||
const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; };
|
const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; };
|
||||||
const decltype(m_TransitTunnels)& GetTransitTunnels () const { return m_TransitTunnels; };
|
const decltype(m_TransitTunnels)& GetTransitTunnels () const { return m_TransitTunnels; };
|
||||||
int GetQueueSize () { return m_Queue.GetSize (); };
|
int GetQueueSize () { return m_Queue.GetSize (); };
|
||||||
int GetTunnelCreationSuccessRate () const // in percents
|
int GetTunnelCreationSuccessRate () const // in percents
|
||||||
{
|
{
|
||||||
int totalNum = m_NumSuccesiveTunnelCreations + m_NumFailedTunnelCreations;
|
int totalNum = m_NumSuccesiveTunnelCreations + m_NumFailedTunnelCreations;
|
||||||
return totalNum ? m_NumSuccesiveTunnelCreations*100/totalNum : 0;
|
return totalNum ? m_NumSuccesiveTunnelCreations*100/totalNum : 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Tunnels tunnels;
|
extern Tunnels tunnels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
94
TunnelBase.h
94
TunnelBase.h
|
@ -11,58 +11,58 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
const size_t TUNNEL_DATA_MSG_SIZE = 1028;
|
const size_t TUNNEL_DATA_MSG_SIZE = 1028;
|
||||||
const size_t TUNNEL_DATA_ENCRYPTED_SIZE = 1008;
|
const size_t TUNNEL_DATA_ENCRYPTED_SIZE = 1008;
|
||||||
const size_t TUNNEL_DATA_MAX_PAYLOAD_SIZE = 1003;
|
const size_t TUNNEL_DATA_MAX_PAYLOAD_SIZE = 1003;
|
||||||
|
|
||||||
enum TunnelDeliveryType
|
enum TunnelDeliveryType
|
||||||
{
|
{
|
||||||
eDeliveryTypeLocal = 0,
|
eDeliveryTypeLocal = 0,
|
||||||
eDeliveryTypeTunnel = 1,
|
eDeliveryTypeTunnel = 1,
|
||||||
eDeliveryTypeRouter = 2
|
eDeliveryTypeRouter = 2
|
||||||
};
|
};
|
||||||
struct TunnelMessageBlock
|
struct TunnelMessageBlock
|
||||||
{
|
{
|
||||||
TunnelDeliveryType deliveryType;
|
TunnelDeliveryType deliveryType;
|
||||||
i2p::data::IdentHash hash;
|
i2p::data::IdentHash hash;
|
||||||
uint32_t tunnelID;
|
uint32_t tunnelID;
|
||||||
std::shared_ptr<I2NPMessage> data;
|
std::shared_ptr<I2NPMessage> data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TunnelBase
|
class TunnelBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//WARNING!!! GetSecondsSinceEpoch() return uint64_t
|
//WARNING!!! GetSecondsSinceEpoch() return uint64_t
|
||||||
TunnelBase (): m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {};
|
TunnelBase (): m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {};
|
||||||
virtual ~TunnelBase () {};
|
virtual ~TunnelBase () {};
|
||||||
|
|
||||||
virtual void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) = 0;
|
virtual void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) = 0;
|
||||||
virtual void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) = 0;
|
virtual void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) = 0;
|
||||||
virtual void FlushTunnelDataMsgs () {};
|
virtual void FlushTunnelDataMsgs () {};
|
||||||
virtual void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) = 0;
|
virtual void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) = 0;
|
||||||
virtual uint32_t GetNextTunnelID () const = 0;
|
virtual uint32_t GetNextTunnelID () const = 0;
|
||||||
virtual const i2p::data::IdentHash& GetNextIdentHash () const = 0;
|
virtual const i2p::data::IdentHash& GetNextIdentHash () const = 0;
|
||||||
virtual uint32_t GetTunnelID () const = 0; // as known at our side
|
virtual uint32_t GetTunnelID () const = 0; // as known at our side
|
||||||
|
|
||||||
uint32_t GetCreationTime () const { return m_CreationTime; };
|
uint32_t GetCreationTime () const { return m_CreationTime; };
|
||||||
void SetCreationTime (uint32_t t) { m_CreationTime = t; };
|
void SetCreationTime (uint32_t t) { m_CreationTime = t; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint32_t m_CreationTime; // seconds since epoch
|
uint32_t m_CreationTime; // seconds since epoch
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TunnelCreationTimeCmp
|
struct TunnelCreationTimeCmp
|
||||||
{
|
{
|
||||||
bool operator() (std::shared_ptr<const TunnelBase> t1, std::shared_ptr<const TunnelBase> t2) const
|
bool operator() (std::shared_ptr<const TunnelBase> t1, std::shared_ptr<const TunnelBase> t2) const
|
||||||
{
|
{
|
||||||
if (t1->GetCreationTime () != t2->GetCreationTime ())
|
if (t1->GetCreationTime () != t2->GetCreationTime ())
|
||||||
return t1->GetCreationTime () > t2->GetCreationTime ();
|
return t1->GetCreationTime () > t2->GetCreationTime ();
|
||||||
else
|
else
|
||||||
return t1 < t2;
|
return t1 < t2;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
398
TunnelConfig.h
398
TunnelConfig.h
|
@ -14,220 +14,220 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
struct TunnelHopConfig
|
struct TunnelHopConfig
|
||||||
{
|
{
|
||||||
std::shared_ptr<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];
|
||||||
uint8_t replyKey[32];
|
uint8_t replyKey[32];
|
||||||
uint8_t replyIV[16];
|
uint8_t replyIV[16];
|
||||||
bool isGateway, isEndpoint;
|
bool isGateway, isEndpoint;
|
||||||
|
|
||||||
TunnelHopConfig * next, * prev;
|
TunnelHopConfig * next, * prev;
|
||||||
i2p::crypto::TunnelDecryption decryption;
|
i2p::crypto::TunnelDecryption decryption;
|
||||||
int recordIndex; // record # in tunnel build message
|
int recordIndex; // record # in tunnel build message
|
||||||
|
|
||||||
TunnelHopConfig (std::shared_ptr<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);
|
||||||
rnd.GenerateBlock (ivKey, 32);
|
rnd.GenerateBlock (ivKey, 32);
|
||||||
rnd.GenerateBlock (replyIV, 16);
|
rnd.GenerateBlock (replyIV, 16);
|
||||||
tunnelID = rnd.GenerateWord32 ();
|
tunnelID = rnd.GenerateWord32 ();
|
||||||
isGateway = true;
|
isGateway = true;
|
||||||
isEndpoint = true;
|
isEndpoint = true;
|
||||||
router = r;
|
router = r;
|
||||||
//nextRouter = nullptr;
|
//nextRouter = nullptr;
|
||||||
nextTunnelID = 0;
|
nextTunnelID = 0;
|
||||||
|
|
||||||
next = nullptr;
|
next = nullptr;
|
||||||
prev = nullptr;
|
prev = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetNextRouter (std::shared_ptr<const i2p::data::RouterInfo> r)
|
void SetNextRouter (std::shared_ptr<const i2p::data::RouterInfo> r)
|
||||||
{
|
{
|
||||||
nextRouter = r;
|
nextRouter = r;
|
||||||
isEndpoint = false;
|
isEndpoint = false;
|
||||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
nextTunnelID = rnd.GenerateWord32 ();
|
nextTunnelID = rnd.GenerateWord32 ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetReplyHop (const TunnelHopConfig * replyFirstHop)
|
void SetReplyHop (const TunnelHopConfig * replyFirstHop)
|
||||||
{
|
{
|
||||||
nextRouter = replyFirstHop->router;
|
nextRouter = replyFirstHop->router;
|
||||||
nextTunnelID = replyFirstHop->tunnelID;
|
nextTunnelID = replyFirstHop->tunnelID;
|
||||||
isEndpoint = true;
|
isEndpoint = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetNext (TunnelHopConfig * n)
|
void SetNext (TunnelHopConfig * n)
|
||||||
{
|
{
|
||||||
next = n;
|
next = n;
|
||||||
if (next)
|
if (next)
|
||||||
{
|
{
|
||||||
next->prev = this;
|
next->prev = this;
|
||||||
next->isGateway = false;
|
next->isGateway = false;
|
||||||
isEndpoint = false;
|
isEndpoint = false;
|
||||||
nextRouter = next->router;
|
nextRouter = next->router;
|
||||||
nextTunnelID = next->tunnelID;
|
nextTunnelID = next->tunnelID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetPrev (TunnelHopConfig * p)
|
void SetPrev (TunnelHopConfig * p)
|
||||||
{
|
{
|
||||||
prev = p;
|
prev = p;
|
||||||
if (prev)
|
if (prev)
|
||||||
{
|
{
|
||||||
prev->next = this;
|
prev->next = this;
|
||||||
prev->isEndpoint = false;
|
prev->isEndpoint = false;
|
||||||
isGateway = false;
|
isGateway = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID) const
|
void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID) const
|
||||||
{
|
{
|
||||||
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE] = {};
|
||||||
htobe32buf (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID);
|
htobe32buf (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID);
|
||||||
memcpy (clearText + BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET, router->GetIdentHash (), 32);
|
memcpy (clearText + BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET, router->GetIdentHash (), 32);
|
||||||
htobe32buf (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID);
|
htobe32buf (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID);
|
||||||
memcpy (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, nextRouter->GetIdentHash (), 32);
|
memcpy (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, nextRouter->GetIdentHash (), 32);
|
||||||
memcpy (clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, layerKey, 32);
|
memcpy (clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, layerKey, 32);
|
||||||
memcpy (clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET, ivKey, 32);
|
memcpy (clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET, ivKey, 32);
|
||||||
memcpy (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET, replyKey, 32);
|
memcpy (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET, replyKey, 32);
|
||||||
memcpy (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET, replyIV, 16);
|
memcpy (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET, replyIV, 16);
|
||||||
uint8_t flag = 0;
|
uint8_t flag = 0;
|
||||||
if (isGateway) flag |= 0x80;
|
if (isGateway) flag |= 0x80;
|
||||||
if (isEndpoint) flag |= 0x40;
|
if (isEndpoint) flag |= 0x40;
|
||||||
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] = flag;
|
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] = flag;
|
||||||
htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ());
|
htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ());
|
||||||
htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID);
|
htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID);
|
||||||
// TODO: fill padding
|
// TODO: fill padding
|
||||||
router->GetElGamalEncryption ()->Encrypt (clearText, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET);
|
router->GetElGamalEncryption ()->Encrypt (clearText, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET);
|
||||||
memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)router->GetIdentHash (), 16);
|
memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)router->GetIdentHash (), 16);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TunnelConfig: public std::enable_shared_from_this<TunnelConfig>
|
class TunnelConfig: public std::enable_shared_from_this<TunnelConfig>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
||||||
TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> > peers,
|
TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> > peers,
|
||||||
std::shared_ptr<const TunnelConfig> replyTunnelConfig = nullptr) // replyTunnelConfig=nullptr means inbound
|
std::shared_ptr<const TunnelConfig> replyTunnelConfig = nullptr) // replyTunnelConfig=nullptr means inbound
|
||||||
{
|
{
|
||||||
TunnelHopConfig * prev = nullptr;
|
TunnelHopConfig * prev = nullptr;
|
||||||
for (auto it: peers)
|
for (auto it: peers)
|
||||||
{
|
{
|
||||||
auto hop = new TunnelHopConfig (it);
|
auto hop = new TunnelHopConfig (it);
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->SetNext (hop);
|
prev->SetNext (hop);
|
||||||
else
|
else
|
||||||
m_FirstHop = hop;
|
m_FirstHop = hop;
|
||||||
prev = hop;
|
prev = hop;
|
||||||
}
|
}
|
||||||
m_LastHop = prev;
|
m_LastHop = prev;
|
||||||
|
|
||||||
if (replyTunnelConfig) // outbound
|
if (replyTunnelConfig) // outbound
|
||||||
{
|
{
|
||||||
m_FirstHop->isGateway = false;
|
m_FirstHop->isGateway = false;
|
||||||
m_LastHop->SetReplyHop (replyTunnelConfig->GetFirstHop ());
|
m_LastHop->SetReplyHop (replyTunnelConfig->GetFirstHop ());
|
||||||
}
|
}
|
||||||
else // inbound
|
else // inbound
|
||||||
m_LastHop->SetNextRouter (i2p::context.GetSharedRouterInfo ());
|
m_LastHop->SetNextRouter (i2p::context.GetSharedRouterInfo ());
|
||||||
}
|
}
|
||||||
|
|
||||||
~TunnelConfig ()
|
~TunnelConfig ()
|
||||||
{
|
{
|
||||||
TunnelHopConfig * hop = m_FirstHop;
|
TunnelHopConfig * hop = m_FirstHop;
|
||||||
|
|
||||||
while (hop)
|
while (hop)
|
||||||
{
|
{
|
||||||
auto tmp = hop;
|
auto tmp = hop;
|
||||||
hop = hop->next;
|
hop = hop->next;
|
||||||
delete tmp;
|
delete tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TunnelHopConfig * GetFirstHop () const
|
TunnelHopConfig * GetFirstHop () const
|
||||||
{
|
{
|
||||||
return m_FirstHop;
|
return m_FirstHop;
|
||||||
}
|
}
|
||||||
|
|
||||||
TunnelHopConfig * GetLastHop () const
|
TunnelHopConfig * GetLastHop () const
|
||||||
{
|
{
|
||||||
return m_LastHop;
|
return m_LastHop;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetNumHops () const
|
int GetNumHops () const
|
||||||
{
|
{
|
||||||
int num = 0;
|
int num = 0;
|
||||||
TunnelHopConfig * hop = m_FirstHop;
|
TunnelHopConfig * hop = m_FirstHop;
|
||||||
while (hop)
|
while (hop)
|
||||||
{
|
{
|
||||||
num++;
|
num++;
|
||||||
hop = hop->next;
|
hop = hop->next;
|
||||||
}
|
}
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInbound () const { return m_FirstHop->isGateway; }
|
bool IsInbound () const { return m_FirstHop->isGateway; }
|
||||||
|
|
||||||
std::vector<std::shared_ptr<const i2p::data::RouterInfo> > GetPeers () const
|
std::vector<std::shared_ptr<const i2p::data::RouterInfo> > GetPeers () const
|
||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<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)
|
||||||
{
|
{
|
||||||
peers.push_back (hop->router);
|
peers.push_back (hop->router);
|
||||||
hop = hop->next;
|
hop = hop->next;
|
||||||
}
|
}
|
||||||
return peers;
|
return peers;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Print (std::stringstream& s) const
|
void Print (std::stringstream& s) const
|
||||||
{
|
{
|
||||||
TunnelHopConfig * hop = m_FirstHop;
|
TunnelHopConfig * hop = m_FirstHop;
|
||||||
if (!IsInbound ()) // outbound
|
if (!IsInbound ()) // outbound
|
||||||
s << "me";
|
s << "me";
|
||||||
s << "-->" << m_FirstHop->tunnelID;
|
s << "-->" << m_FirstHop->tunnelID;
|
||||||
while (hop)
|
while (hop)
|
||||||
{
|
{
|
||||||
s << ":" << hop->router->GetIdentHashAbbreviation () << "-->";
|
s << ":" << hop->router->GetIdentHashAbbreviation () << "-->";
|
||||||
if (!hop->isEndpoint)
|
if (!hop->isEndpoint)
|
||||||
s << hop->nextTunnelID;
|
s << hop->nextTunnelID;
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
hop = hop->next;
|
hop = hop->next;
|
||||||
}
|
}
|
||||||
// we didn't reach enpoint that mean we are last hop
|
// we didn't reach enpoint that mean we are last hop
|
||||||
s << ":me";
|
s << ":me";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<TunnelConfig> Invert () const
|
std::shared_ptr<TunnelConfig> Invert () const
|
||||||
{
|
{
|
||||||
auto peers = GetPeers ();
|
auto peers = GetPeers ();
|
||||||
std::reverse (peers.begin (), peers.end ());
|
std::reverse (peers.begin (), peers.end ());
|
||||||
// we use ourself as reply tunnel for outbound tunnel
|
// we use ourself as reply tunnel for outbound tunnel
|
||||||
return IsInbound () ? std::make_shared<TunnelConfig>(peers, shared_from_this ()) : std::make_shared<TunnelConfig>(peers);
|
return IsInbound () ? std::make_shared<TunnelConfig>(peers, shared_from_this ()) : std::make_shared<TunnelConfig>(peers);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<TunnelConfig> Clone (std::shared_ptr<const TunnelConfig> replyTunnelConfig = nullptr) const
|
std::shared_ptr<TunnelConfig> Clone (std::shared_ptr<const TunnelConfig> replyTunnelConfig = nullptr) const
|
||||||
{
|
{
|
||||||
return std::make_shared<TunnelConfig> (GetPeers (), replyTunnelConfig);
|
return std::make_shared<TunnelConfig> (GetPeers (), replyTunnelConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// this constructor can't be called from outside
|
// this constructor can't be called from outside
|
||||||
TunnelConfig (): m_FirstHop (nullptr), m_LastHop (nullptr)
|
TunnelConfig (): m_FirstHop (nullptr), m_LastHop (nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
TunnelHopConfig * m_FirstHop, * m_LastHop;
|
TunnelHopConfig * m_FirstHop, * m_LastHop;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,249 +11,249 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
TunnelEndpoint::~TunnelEndpoint ()
|
TunnelEndpoint::~TunnelEndpoint ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelEndpoint::HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg)
|
void TunnelEndpoint::HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE;
|
m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE;
|
||||||
|
|
||||||
uint8_t * decrypted = msg->GetPayload () + 20; // 4 + 16
|
uint8_t * decrypted = msg->GetPayload () + 20; // 4 + 16
|
||||||
uint8_t * zero = (uint8_t *)memchr (decrypted + 4, 0, TUNNEL_DATA_ENCRYPTED_SIZE - 4); // witout 4-byte checksum
|
uint8_t * zero = (uint8_t *)memchr (decrypted + 4, 0, TUNNEL_DATA_ENCRYPTED_SIZE - 4); // witout 4-byte checksum
|
||||||
if (zero)
|
if (zero)
|
||||||
{
|
{
|
||||||
uint8_t * fragment = zero + 1;
|
uint8_t * fragment = zero + 1;
|
||||||
// verify checksum
|
// verify checksum
|
||||||
memcpy (msg->GetPayload () + TUNNEL_DATA_MSG_SIZE, msg->GetPayload () + 4, 16); // copy iv to the end
|
memcpy (msg->GetPayload () + TUNNEL_DATA_MSG_SIZE, msg->GetPayload () + 4, 16); // copy iv to the end
|
||||||
uint8_t hash[32];
|
uint8_t hash[32];
|
||||||
CryptoPP::SHA256().CalculateDigest (hash, fragment, TUNNEL_DATA_MSG_SIZE -(fragment - msg->GetPayload ()) + 16); // payload + iv
|
CryptoPP::SHA256().CalculateDigest (hash, fragment, TUNNEL_DATA_MSG_SIZE -(fragment - msg->GetPayload ()) + 16); // payload + iv
|
||||||
if (memcmp (hash, decrypted, 4))
|
if (memcmp (hash, decrypted, 4))
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "TunnelMessage: checksum verification failed");
|
LogPrint (eLogError, "TunnelMessage: checksum verification failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// process fragments
|
// process fragments
|
||||||
while (fragment < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
|
while (fragment < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
|
||||||
{
|
{
|
||||||
uint8_t flag = fragment[0];
|
uint8_t flag = fragment[0];
|
||||||
fragment++;
|
fragment++;
|
||||||
|
|
||||||
bool isFollowOnFragment = flag & 0x80, isLastFragment = true;
|
bool isFollowOnFragment = flag & 0x80, isLastFragment = true;
|
||||||
uint32_t msgID = 0;
|
uint32_t msgID = 0;
|
||||||
int fragmentNum = 0;
|
int fragmentNum = 0;
|
||||||
TunnelMessageBlockEx m;
|
TunnelMessageBlockEx m;
|
||||||
if (!isFollowOnFragment)
|
if (!isFollowOnFragment)
|
||||||
{
|
{
|
||||||
// first fragment
|
// first fragment
|
||||||
|
|
||||||
m.deliveryType = (TunnelDeliveryType)((flag >> 5) & 0x03);
|
m.deliveryType = (TunnelDeliveryType)((flag >> 5) & 0x03);
|
||||||
switch (m.deliveryType)
|
switch (m.deliveryType)
|
||||||
{
|
{
|
||||||
case eDeliveryTypeLocal: // 0
|
case eDeliveryTypeLocal: // 0
|
||||||
break;
|
break;
|
||||||
case eDeliveryTypeTunnel: // 1
|
case eDeliveryTypeTunnel: // 1
|
||||||
m.tunnelID = bufbe32toh (fragment);
|
m.tunnelID = bufbe32toh (fragment);
|
||||||
fragment += 4; // tunnelID
|
fragment += 4; // tunnelID
|
||||||
m.hash = i2p::data::IdentHash (fragment);
|
m.hash = i2p::data::IdentHash (fragment);
|
||||||
fragment += 32; // hash
|
fragment += 32; // hash
|
||||||
break;
|
break;
|
||||||
case eDeliveryTypeRouter: // 2
|
case eDeliveryTypeRouter: // 2
|
||||||
m.hash = i2p::data::IdentHash (fragment);
|
m.hash = i2p::data::IdentHash (fragment);
|
||||||
fragment += 32; // to hash
|
fragment += 32; // to hash
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFragmented = flag & 0x08;
|
bool isFragmented = flag & 0x08;
|
||||||
if (isFragmented)
|
if (isFragmented)
|
||||||
{
|
{
|
||||||
// Message ID
|
// Message ID
|
||||||
msgID = bufbe32toh (fragment);
|
msgID = bufbe32toh (fragment);
|
||||||
fragment += 4;
|
fragment += 4;
|
||||||
isLastFragment = false;
|
isLastFragment = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// follow on
|
// follow on
|
||||||
msgID = bufbe32toh (fragment); // MessageID
|
msgID = bufbe32toh (fragment); // MessageID
|
||||||
fragment += 4;
|
fragment += 4;
|
||||||
fragmentNum = (flag >> 1) & 0x3F; // 6 bits
|
fragmentNum = (flag >> 1) & 0x3F; // 6 bits
|
||||||
isLastFragment = flag & 0x01;
|
isLastFragment = flag & 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t size = bufbe16toh (fragment);
|
uint16_t size = bufbe16toh (fragment);
|
||||||
fragment += 2;
|
fragment += 2;
|
||||||
|
|
||||||
msg->offset = fragment - msg->buf;
|
msg->offset = fragment - msg->buf;
|
||||||
msg->len = msg->offset + size;
|
msg->len = msg->offset + size;
|
||||||
if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
|
if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
|
||||||
{
|
{
|
||||||
// this is not last message. we have to copy it
|
// this is not last message. we have to copy it
|
||||||
m.data = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
m.data = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
||||||
m.data->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header
|
m.data->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header
|
||||||
m.data->len += TUNNEL_GATEWAY_HEADER_SIZE;
|
m.data->len += TUNNEL_GATEWAY_HEADER_SIZE;
|
||||||
*(m.data) = *msg;
|
*(m.data) = *msg;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m.data = msg;
|
m.data = msg;
|
||||||
|
|
||||||
if (!isFollowOnFragment && isLastFragment)
|
if (!isFollowOnFragment && isLastFragment)
|
||||||
HandleNextMessage (m);
|
HandleNextMessage (m);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (msgID) // msgID is presented, assume message is fragmented
|
if (msgID) // msgID is presented, assume message is fragmented
|
||||||
{
|
{
|
||||||
if (!isFollowOnFragment) // create new incomlete message
|
if (!isFollowOnFragment) // create new incomlete message
|
||||||
{
|
{
|
||||||
m.nextFragmentNum = 1;
|
m.nextFragmentNum = 1;
|
||||||
auto ret = m_IncompleteMessages.insert (std::pair<uint32_t, TunnelMessageBlockEx>(msgID, m));
|
auto ret = m_IncompleteMessages.insert (std::pair<uint32_t, TunnelMessageBlockEx>(msgID, m));
|
||||||
if (ret.second)
|
if (ret.second)
|
||||||
HandleOutOfSequenceFragment (msgID, ret.first->second);
|
HandleOutOfSequenceFragment (msgID, ret.first->second);
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "Incomplete message ", msgID, "already exists");
|
LogPrint (eLogError, "Incomplete message ", msgID, "already exists");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m.nextFragmentNum = fragmentNum;
|
m.nextFragmentNum = fragmentNum;
|
||||||
HandleFollowOnFragment (msgID, isLastFragment, m);
|
HandleFollowOnFragment (msgID, isLastFragment, m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "Message is fragmented, but msgID is not presented");
|
LogPrint (eLogError, "Message is fragmented, but msgID is not presented");
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment += size;
|
fragment += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "TunnelMessage: zero not found");
|
LogPrint (eLogError, "TunnelMessage: zero not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m)
|
void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m)
|
||||||
{
|
{
|
||||||
auto fragment = m.data->GetBuffer ();
|
auto fragment = m.data->GetBuffer ();
|
||||||
auto size = m.data->GetLength ();
|
auto size = m.data->GetLength ();
|
||||||
auto it = m_IncompleteMessages.find (msgID);
|
auto it = m_IncompleteMessages.find (msgID);
|
||||||
if (it != m_IncompleteMessages.end())
|
if (it != m_IncompleteMessages.end())
|
||||||
{
|
{
|
||||||
auto& msg = it->second;
|
auto& msg = it->second;
|
||||||
if (m.nextFragmentNum == msg.nextFragmentNum)
|
if (m.nextFragmentNum == msg.nextFragmentNum)
|
||||||
{
|
{
|
||||||
if (msg.data->len + size < I2NP_MAX_MESSAGE_SIZE) // check if message is not too long
|
if (msg.data->len + size < I2NP_MAX_MESSAGE_SIZE) // check if message is not too long
|
||||||
{
|
{
|
||||||
if (msg.data->len + size > msg.data->maxLen)
|
if (msg.data->len + size > msg.data->maxLen)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
|
LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
|
||||||
auto newMsg = ToSharedI2NPMessage (NewI2NPMessage ());
|
auto newMsg = ToSharedI2NPMessage (NewI2NPMessage ());
|
||||||
*newMsg = *(msg.data);
|
*newMsg = *(msg.data);
|
||||||
msg.data = newMsg;
|
msg.data = newMsg;
|
||||||
}
|
}
|
||||||
memcpy (msg.data->buf + msg.data->len, fragment, size); // concatenate fragment
|
memcpy (msg.data->buf + msg.data->len, fragment, size); // concatenate fragment
|
||||||
msg.data->len += size;
|
msg.data->len += size;
|
||||||
if (isLastFragment)
|
if (isLastFragment)
|
||||||
{
|
{
|
||||||
// message complete
|
// message complete
|
||||||
HandleNextMessage (msg);
|
HandleNextMessage (msg);
|
||||||
m_IncompleteMessages.erase (it);
|
m_IncompleteMessages.erase (it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
msg.nextFragmentNum++;
|
msg.nextFragmentNum++;
|
||||||
HandleOutOfSequenceFragment (msgID, msg);
|
HandleOutOfSequenceFragment (msgID, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Fragment ", m.nextFragmentNum, " of message ", msgID, "exceeds max I2NP message size. Message dropped");
|
LogPrint (eLogError, "Fragment ", m.nextFragmentNum, " of message ", msgID, "exceeds max I2NP message size. Message dropped");
|
||||||
m_IncompleteMessages.erase (it);
|
m_IncompleteMessages.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Unexpected fragment ", (int)m.nextFragmentNum, " instead ", (int)msg.nextFragmentNum, " of message ", msgID, ". Saved");
|
LogPrint (eLogInfo, "Unexpected fragment ", (int)m.nextFragmentNum, " instead ", (int)msg.nextFragmentNum, " of message ", msgID, ". Saved");
|
||||||
AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data);
|
AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "First fragment of message ", msgID, " not found. Saved");
|
LogPrint (eLogInfo, "First fragment of message ", msgID, " not found. Saved");
|
||||||
AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data);
|
AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data)
|
void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data)
|
||||||
{
|
{
|
||||||
auto it = m_OutOfSequenceFragments.find (msgID);
|
auto it = m_OutOfSequenceFragments.find (msgID);
|
||||||
if (it == m_OutOfSequenceFragments.end ())
|
if (it == m_OutOfSequenceFragments.end ())
|
||||||
m_OutOfSequenceFragments.insert (std::pair<uint32_t, Fragment> (msgID, {fragmentNum, isLastFragment, data}));
|
m_OutOfSequenceFragments.insert (std::pair<uint32_t, Fragment> (msgID, {fragmentNum, isLastFragment, data}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelEndpoint::HandleOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg)
|
void TunnelEndpoint::HandleOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg)
|
||||||
{
|
{
|
||||||
auto it = m_OutOfSequenceFragments.find (msgID);
|
auto it = m_OutOfSequenceFragments.find (msgID);
|
||||||
if (it != m_OutOfSequenceFragments.end ())
|
if (it != m_OutOfSequenceFragments.end ())
|
||||||
{
|
{
|
||||||
if (it->second.fragmentNum == msg.nextFragmentNum)
|
if (it->second.fragmentNum == msg.nextFragmentNum)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Out-of-sequence fragment ", (int)it->second.fragmentNum, " of message ", msgID, " found");
|
LogPrint (eLogInfo, "Out-of-sequence fragment ", (int)it->second.fragmentNum, " of message ", msgID, " found");
|
||||||
auto size = it->second.data->GetLength ();
|
auto size = it->second.data->GetLength ();
|
||||||
if (msg.data->len + size > msg.data->maxLen)
|
if (msg.data->len + size > msg.data->maxLen)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
|
LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
|
||||||
auto newMsg = ToSharedI2NPMessage (NewI2NPMessage ());
|
auto newMsg = ToSharedI2NPMessage (NewI2NPMessage ());
|
||||||
*newMsg = *(msg.data);
|
*newMsg = *(msg.data);
|
||||||
msg.data = newMsg;
|
msg.data = newMsg;
|
||||||
}
|
}
|
||||||
memcpy (msg.data->buf + msg.data->len, it->second.data->GetBuffer (), size); // concatenate out-of-sync fragment
|
memcpy (msg.data->buf + msg.data->len, it->second.data->GetBuffer (), size); // concatenate out-of-sync fragment
|
||||||
msg.data->len += size;
|
msg.data->len += size;
|
||||||
if (it->second.isLastFragment)
|
if (it->second.isLastFragment)
|
||||||
{
|
{
|
||||||
// message complete
|
// message complete
|
||||||
HandleNextMessage (msg);
|
HandleNextMessage (msg);
|
||||||
m_IncompleteMessages.erase (msgID);
|
m_IncompleteMessages.erase (msgID);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
msg.nextFragmentNum++;
|
msg.nextFragmentNum++;
|
||||||
m_OutOfSequenceFragments.erase (it);
|
m_OutOfSequenceFragments.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelEndpoint::HandleNextMessage (const TunnelMessageBlock& msg)
|
void TunnelEndpoint::HandleNextMessage (const TunnelMessageBlock& msg)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "TunnelMessage: handle fragment of ", msg.data->GetLength ()," bytes. Msg type ", (int)msg.data->GetTypeID ());
|
LogPrint (eLogInfo, "TunnelMessage: handle fragment of ", msg.data->GetLength ()," bytes. Msg type ", (int)msg.data->GetTypeID ());
|
||||||
switch (msg.deliveryType)
|
switch (msg.deliveryType)
|
||||||
{
|
{
|
||||||
case eDeliveryTypeLocal:
|
case eDeliveryTypeLocal:
|
||||||
i2p::HandleI2NPMessage (msg.data);
|
i2p::HandleI2NPMessage (msg.data);
|
||||||
break;
|
break;
|
||||||
case eDeliveryTypeTunnel:
|
case eDeliveryTypeTunnel:
|
||||||
i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
|
i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
|
||||||
break;
|
break;
|
||||||
case eDeliveryTypeRouter:
|
case eDeliveryTypeRouter:
|
||||||
if (msg.hash == i2p::context.GetRouterInfo ().GetIdentHash ()) // check if message is sent to us
|
if (msg.hash == i2p::context.GetRouterInfo ().GetIdentHash ()) // check if message is sent to us
|
||||||
i2p::HandleI2NPMessage (msg.data);
|
i2p::HandleI2NPMessage (msg.data);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// to somebody else
|
// to somebody else
|
||||||
if (!m_IsInbound) // outbound transit tunnel
|
if (!m_IsInbound) // outbound transit tunnel
|
||||||
{
|
{
|
||||||
/* auto typeID = msg.data->GetTypeID ();
|
/* auto typeID = msg.data->GetTypeID ();
|
||||||
if (typeID == eI2NPDatabaseStore || typeID == eI2NPDatabaseSearchReply )
|
if (typeID == eI2NPDatabaseStore || typeID == eI2NPDatabaseSearchReply )
|
||||||
// catch RI or reply with new list of routers
|
// catch RI or reply with new list of routers
|
||||||
i2p::data::netdb.PostI2NPMsg (msg.data);*/
|
i2p::data::netdb.PostI2NPMsg (msg.data);*/
|
||||||
i2p::transport::transports.SendMessage (msg.hash, msg.data);
|
i2p::transport::transports.SendMessage (msg.hash, msg.data);
|
||||||
}
|
}
|
||||||
else // we shouldn't send this message. possible leakage
|
else // we shouldn't send this message. possible leakage
|
||||||
LogPrint (eLogError, "Message to another router arrived from an inbound tunnel. Dropped");
|
LogPrint (eLogError, "Message to another router arrived from an inbound tunnel. Dropped");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType);
|
LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,44 +11,44 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
class TunnelEndpoint
|
class TunnelEndpoint
|
||||||
{
|
{
|
||||||
struct TunnelMessageBlockEx: public TunnelMessageBlock
|
struct TunnelMessageBlockEx: public TunnelMessageBlock
|
||||||
{
|
{
|
||||||
uint8_t nextFragmentNum;
|
uint8_t nextFragmentNum;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Fragment
|
struct Fragment
|
||||||
{
|
{
|
||||||
uint8_t fragmentNum;
|
uint8_t fragmentNum;
|
||||||
bool isLastFragment;
|
bool isLastFragment;
|
||||||
std::shared_ptr<I2NPMessage> data;
|
std::shared_ptr<I2NPMessage> data;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0) {};
|
TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0) {};
|
||||||
~TunnelEndpoint ();
|
~TunnelEndpoint ();
|
||||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||||
|
|
||||||
void HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg);
|
void HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m);
|
void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m);
|
||||||
void HandleNextMessage (const TunnelMessageBlock& msg);
|
void HandleNextMessage (const TunnelMessageBlock& msg);
|
||||||
|
|
||||||
void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data);
|
void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data);
|
||||||
void HandleOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg);
|
void HandleOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages;
|
std::map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages;
|
||||||
std::map<uint32_t, Fragment> m_OutOfSequenceFragments;
|
std::map<uint32_t, Fragment> m_OutOfSequenceFragments;
|
||||||
bool m_IsInbound;
|
bool m_IsInbound;
|
||||||
size_t m_NumReceivedBytes;
|
size_t m_NumReceivedBytes;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,203 +10,203 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
TunnelGatewayBuffer::TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID),
|
TunnelGatewayBuffer::TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID),
|
||||||
m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0)
|
m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0)
|
||||||
{
|
{
|
||||||
context.GetRandomNumberGenerator ().GenerateBlock (m_NonZeroRandomBuffer, TUNNEL_DATA_MAX_PAYLOAD_SIZE);
|
context.GetRandomNumberGenerator ().GenerateBlock (m_NonZeroRandomBuffer, TUNNEL_DATA_MAX_PAYLOAD_SIZE);
|
||||||
for (size_t i = 0; i < TUNNEL_DATA_MAX_PAYLOAD_SIZE; i++)
|
for (size_t i = 0; i < TUNNEL_DATA_MAX_PAYLOAD_SIZE; i++)
|
||||||
if (!m_NonZeroRandomBuffer[i]) m_NonZeroRandomBuffer[i] = 1;
|
if (!m_NonZeroRandomBuffer[i]) m_NonZeroRandomBuffer[i] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TunnelGatewayBuffer::~TunnelGatewayBuffer ()
|
TunnelGatewayBuffer::~TunnelGatewayBuffer ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block)
|
void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block)
|
||||||
{
|
{
|
||||||
bool messageCreated = false;
|
bool messageCreated = false;
|
||||||
if (!m_CurrentTunnelDataMsg)
|
if (!m_CurrentTunnelDataMsg)
|
||||||
{
|
{
|
||||||
CreateCurrentTunnelDataMessage ();
|
CreateCurrentTunnelDataMessage ();
|
||||||
messageCreated = true;
|
messageCreated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create delivery instructions
|
// create delivery instructions
|
||||||
uint8_t di[43]; // max delivery instruction length is 43 for tunnel
|
uint8_t di[43]; // max delivery instruction length is 43 for tunnel
|
||||||
size_t diLen = 1;// flag
|
size_t diLen = 1;// flag
|
||||||
if (block.deliveryType != eDeliveryTypeLocal) // tunnel or router
|
if (block.deliveryType != eDeliveryTypeLocal) // tunnel or router
|
||||||
{
|
{
|
||||||
if (block.deliveryType == eDeliveryTypeTunnel)
|
if (block.deliveryType == eDeliveryTypeTunnel)
|
||||||
{
|
{
|
||||||
htobe32buf (di + diLen, block.tunnelID);
|
htobe32buf (di + diLen, block.tunnelID);
|
||||||
diLen += 4; // tunnelID
|
diLen += 4; // tunnelID
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy (di + diLen, block.hash, 32);
|
memcpy (di + diLen, block.hash, 32);
|
||||||
diLen += 32; //len
|
diLen += 32; //len
|
||||||
}
|
}
|
||||||
di[0] = block.deliveryType << 5; // set delivery type
|
di[0] = block.deliveryType << 5; // set delivery type
|
||||||
|
|
||||||
// create fragments
|
// create fragments
|
||||||
std::shared_ptr<I2NPMessage> msg = block.data;
|
std::shared_ptr<I2NPMessage> msg = block.data;
|
||||||
auto fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length
|
auto fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length
|
||||||
if (fullMsgLen <= m_RemainingSize)
|
if (fullMsgLen <= m_RemainingSize)
|
||||||
{
|
{
|
||||||
// message fits. First and last fragment
|
// message fits. First and last fragment
|
||||||
htobe16buf (di + diLen, msg->GetLength ());
|
htobe16buf (di + diLen, msg->GetLength ());
|
||||||
diLen += 2; // size
|
diLen += 2; // size
|
||||||
memcpy (m_CurrentTunnelDataMsg->buf + m_CurrentTunnelDataMsg->len, di, diLen);
|
memcpy (m_CurrentTunnelDataMsg->buf + m_CurrentTunnelDataMsg->len, di, diLen);
|
||||||
memcpy (m_CurrentTunnelDataMsg->buf + m_CurrentTunnelDataMsg->len + diLen, msg->GetBuffer (), msg->GetLength ());
|
memcpy (m_CurrentTunnelDataMsg->buf + m_CurrentTunnelDataMsg->len + diLen, msg->GetBuffer (), msg->GetLength ());
|
||||||
m_CurrentTunnelDataMsg->len += diLen + msg->GetLength ();
|
m_CurrentTunnelDataMsg->len += diLen + msg->GetLength ();
|
||||||
m_RemainingSize -= diLen + msg->GetLength ();
|
m_RemainingSize -= diLen + msg->GetLength ();
|
||||||
if (!m_RemainingSize)
|
if (!m_RemainingSize)
|
||||||
CompleteCurrentTunnelDataMessage ();
|
CompleteCurrentTunnelDataMessage ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!messageCreated) // check if we should complete previous message
|
if (!messageCreated) // check if we should complete previous message
|
||||||
{
|
{
|
||||||
auto numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
auto numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
||||||
// length of bytes don't fit full tunnel message
|
// length of bytes don't fit full tunnel message
|
||||||
// every follow-on fragment adds 7 bytes
|
// every follow-on fragment adds 7 bytes
|
||||||
auto nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
auto nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
||||||
if (!nonFit || nonFit > m_RemainingSize)
|
if (!nonFit || nonFit > m_RemainingSize)
|
||||||
{
|
{
|
||||||
CompleteCurrentTunnelDataMessage ();
|
CompleteCurrentTunnelDataMessage ();
|
||||||
CreateCurrentTunnelDataMessage ();
|
CreateCurrentTunnelDataMessage ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (diLen + 6 <= m_RemainingSize)
|
if (diLen + 6 <= m_RemainingSize)
|
||||||
{
|
{
|
||||||
// delivery instructions fit
|
// delivery instructions fit
|
||||||
uint32_t msgID;
|
uint32_t msgID;
|
||||||
memcpy (&msgID, msg->GetHeader () + I2NP_HEADER_MSGID_OFFSET, 4); // in network bytes order
|
memcpy (&msgID, msg->GetHeader () + I2NP_HEADER_MSGID_OFFSET, 4); // in network bytes order
|
||||||
size_t size = m_RemainingSize - diLen - 6; // 6 = 4 (msgID) + 2 (size)
|
size_t size = m_RemainingSize - diLen - 6; // 6 = 4 (msgID) + 2 (size)
|
||||||
|
|
||||||
// first fragment
|
// first fragment
|
||||||
di[0] |= 0x08; // fragmented
|
di[0] |= 0x08; // fragmented
|
||||||
htobuf32 (di + diLen, msgID);
|
htobuf32 (di + diLen, msgID);
|
||||||
diLen += 4; // Message ID
|
diLen += 4; // Message ID
|
||||||
htobe16buf (di + diLen, size);
|
htobe16buf (di + diLen, size);
|
||||||
diLen += 2; // size
|
diLen += 2; // size
|
||||||
memcpy (m_CurrentTunnelDataMsg->buf + m_CurrentTunnelDataMsg->len, di, diLen);
|
memcpy (m_CurrentTunnelDataMsg->buf + m_CurrentTunnelDataMsg->len, di, diLen);
|
||||||
memcpy (m_CurrentTunnelDataMsg->buf + m_CurrentTunnelDataMsg->len + diLen, msg->GetBuffer (), size);
|
memcpy (m_CurrentTunnelDataMsg->buf + m_CurrentTunnelDataMsg->len + diLen, msg->GetBuffer (), size);
|
||||||
m_CurrentTunnelDataMsg->len += diLen + size;
|
m_CurrentTunnelDataMsg->len += diLen + size;
|
||||||
CompleteCurrentTunnelDataMessage ();
|
CompleteCurrentTunnelDataMessage ();
|
||||||
// follow on fragments
|
// follow on fragments
|
||||||
int fragmentNumber = 1;
|
int fragmentNumber = 1;
|
||||||
while (size < msg->GetLength ())
|
while (size < msg->GetLength ())
|
||||||
{
|
{
|
||||||
CreateCurrentTunnelDataMessage ();
|
CreateCurrentTunnelDataMessage ();
|
||||||
uint8_t * buf = m_CurrentTunnelDataMsg->GetBuffer ();
|
uint8_t * buf = m_CurrentTunnelDataMsg->GetBuffer ();
|
||||||
buf[0] = 0x80 | (fragmentNumber << 1); // frag
|
buf[0] = 0x80 | (fragmentNumber << 1); // frag
|
||||||
bool isLastFragment = false;
|
bool isLastFragment = false;
|
||||||
size_t s = msg->GetLength () - size;
|
size_t s = msg->GetLength () - size;
|
||||||
if (s > TUNNEL_DATA_MAX_PAYLOAD_SIZE - 7) // 7 follow on instructions
|
if (s > TUNNEL_DATA_MAX_PAYLOAD_SIZE - 7) // 7 follow on instructions
|
||||||
s = TUNNEL_DATA_MAX_PAYLOAD_SIZE - 7;
|
s = TUNNEL_DATA_MAX_PAYLOAD_SIZE - 7;
|
||||||
else // last fragment
|
else // last fragment
|
||||||
{
|
{
|
||||||
buf[0] |= 0x01;
|
buf[0] |= 0x01;
|
||||||
isLastFragment = true;
|
isLastFragment = true;
|
||||||
}
|
}
|
||||||
htobuf32 (buf + 1, msgID); //Message ID
|
htobuf32 (buf + 1, msgID); //Message ID
|
||||||
htobe16buf (buf + 5, s); // size
|
htobe16buf (buf + 5, s); // size
|
||||||
memcpy (buf + 7, msg->GetBuffer () + size, s);
|
memcpy (buf + 7, msg->GetBuffer () + size, s);
|
||||||
m_CurrentTunnelDataMsg->len += s+7;
|
m_CurrentTunnelDataMsg->len += s+7;
|
||||||
if (isLastFragment)
|
if (isLastFragment)
|
||||||
{
|
{
|
||||||
m_RemainingSize -= s+7;
|
m_RemainingSize -= s+7;
|
||||||
if (!m_RemainingSize)
|
if (!m_RemainingSize)
|
||||||
CompleteCurrentTunnelDataMessage ();
|
CompleteCurrentTunnelDataMessage ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
CompleteCurrentTunnelDataMessage ();
|
CompleteCurrentTunnelDataMessage ();
|
||||||
size += s;
|
size += s;
|
||||||
fragmentNumber++;
|
fragmentNumber++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// delivery instructions don't fit. Create new message
|
// delivery instructions don't fit. Create new message
|
||||||
CompleteCurrentTunnelDataMessage ();
|
CompleteCurrentTunnelDataMessage ();
|
||||||
PutI2NPMsg (block);
|
PutI2NPMsg (block);
|
||||||
// don't delete msg because it's taken care inside
|
// don't delete msg because it's taken care inside
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelGatewayBuffer::ClearTunnelDataMsgs ()
|
void TunnelGatewayBuffer::ClearTunnelDataMsgs ()
|
||||||
{
|
{
|
||||||
m_TunnelDataMsgs.clear ();
|
m_TunnelDataMsgs.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage ()
|
void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage ()
|
||||||
{
|
{
|
||||||
m_CurrentTunnelDataMsg = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
m_CurrentTunnelDataMsg = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
||||||
m_CurrentTunnelDataMsg->Align (12);
|
m_CurrentTunnelDataMsg->Align (12);
|
||||||
// we reserve space for padding
|
// we reserve space for padding
|
||||||
m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE;
|
m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE;
|
||||||
m_CurrentTunnelDataMsg->len = m_CurrentTunnelDataMsg->offset;
|
m_CurrentTunnelDataMsg->len = m_CurrentTunnelDataMsg->offset;
|
||||||
m_RemainingSize = TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
m_RemainingSize = TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelGatewayBuffer::CompleteCurrentTunnelDataMessage ()
|
void TunnelGatewayBuffer::CompleteCurrentTunnelDataMessage ()
|
||||||
{
|
{
|
||||||
if (!m_CurrentTunnelDataMsg) return;
|
if (!m_CurrentTunnelDataMsg) return;
|
||||||
uint8_t * payload = m_CurrentTunnelDataMsg->GetBuffer ();
|
uint8_t * payload = m_CurrentTunnelDataMsg->GetBuffer ();
|
||||||
size_t size = m_CurrentTunnelDataMsg->len - m_CurrentTunnelDataMsg->offset;
|
size_t size = m_CurrentTunnelDataMsg->len - m_CurrentTunnelDataMsg->offset;
|
||||||
|
|
||||||
m_CurrentTunnelDataMsg->offset = m_CurrentTunnelDataMsg->len - TUNNEL_DATA_MSG_SIZE - I2NP_HEADER_SIZE;
|
m_CurrentTunnelDataMsg->offset = m_CurrentTunnelDataMsg->len - TUNNEL_DATA_MSG_SIZE - I2NP_HEADER_SIZE;
|
||||||
uint8_t * buf = m_CurrentTunnelDataMsg->GetPayload ();
|
uint8_t * buf = m_CurrentTunnelDataMsg->GetPayload ();
|
||||||
htobe32buf (buf, m_TunnelID);
|
htobe32buf (buf, m_TunnelID);
|
||||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
rnd.GenerateBlock (buf + 4, 16); // original IV
|
rnd.GenerateBlock (buf + 4, 16); // original IV
|
||||||
memcpy (payload + size, buf + 4, 16); // copy IV for checksum
|
memcpy (payload + size, buf + 4, 16); // copy IV for checksum
|
||||||
uint8_t hash[32];
|
uint8_t hash[32];
|
||||||
CryptoPP::SHA256().CalculateDigest (hash, payload, size+16);
|
CryptoPP::SHA256().CalculateDigest (hash, payload, size+16);
|
||||||
memcpy (buf+20, hash, 4); // checksum
|
memcpy (buf+20, hash, 4); // checksum
|
||||||
payload[-1] = 0; // zero
|
payload[-1] = 0; // zero
|
||||||
ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1
|
ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1
|
||||||
if (paddingSize > 0)
|
if (paddingSize > 0)
|
||||||
{
|
{
|
||||||
// non-zero padding
|
// non-zero padding
|
||||||
auto randomOffset = rnd.GenerateWord32 (0, TUNNEL_DATA_MAX_PAYLOAD_SIZE - paddingSize);
|
auto randomOffset = rnd.GenerateWord32 (0, TUNNEL_DATA_MAX_PAYLOAD_SIZE - paddingSize);
|
||||||
memcpy (buf + 24, m_NonZeroRandomBuffer + randomOffset, paddingSize);
|
memcpy (buf + 24, m_NonZeroRandomBuffer + randomOffset, paddingSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we can't fill message header yet because encryption is required
|
// we can't fill message header yet because encryption is required
|
||||||
m_TunnelDataMsgs.push_back (m_CurrentTunnelDataMsg);
|
m_TunnelDataMsgs.push_back (m_CurrentTunnelDataMsg);
|
||||||
m_CurrentTunnelDataMsg = nullptr;
|
m_CurrentTunnelDataMsg = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelGateway::SendTunnelDataMsg (const TunnelMessageBlock& block)
|
void TunnelGateway::SendTunnelDataMsg (const TunnelMessageBlock& block)
|
||||||
{
|
{
|
||||||
if (block.data)
|
if (block.data)
|
||||||
{
|
{
|
||||||
PutTunnelDataMsg (block);
|
PutTunnelDataMsg (block);
|
||||||
SendBuffer ();
|
SendBuffer ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelGateway::PutTunnelDataMsg (const TunnelMessageBlock& block)
|
void TunnelGateway::PutTunnelDataMsg (const TunnelMessageBlock& block)
|
||||||
{
|
{
|
||||||
if (block.data)
|
if (block.data)
|
||||||
m_Buffer.PutI2NPMsg (block);
|
m_Buffer.PutI2NPMsg (block);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelGateway::SendBuffer ()
|
void TunnelGateway::SendBuffer ()
|
||||||
{
|
{
|
||||||
m_Buffer.CompleteCurrentTunnelDataMessage ();
|
m_Buffer.CompleteCurrentTunnelDataMessage ();
|
||||||
auto tunnelMsgs = m_Buffer.GetTunnelDataMsgs ();
|
auto tunnelMsgs = m_Buffer.GetTunnelDataMsgs ();
|
||||||
for (auto tunnelMsg : tunnelMsgs)
|
for (auto tunnelMsg : tunnelMsgs)
|
||||||
{
|
{
|
||||||
m_Tunnel->EncryptTunnelMsg (tunnelMsg, tunnelMsg);
|
m_Tunnel->EncryptTunnelMsg (tunnelMsg, tunnelMsg);
|
||||||
tunnelMsg->FillI2NPMessageHeader (eI2NPTunnelData);
|
tunnelMsg->FillI2NPMessageHeader (eI2NPTunnelData);
|
||||||
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
|
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
|
||||||
}
|
}
|
||||||
i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), tunnelMsgs);
|
i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), tunnelMsgs);
|
||||||
m_Buffer.ClearTunnelDataMsgs ();
|
m_Buffer.ClearTunnelDataMsgs ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,47 +11,47 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
class TunnelGatewayBuffer
|
class TunnelGatewayBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TunnelGatewayBuffer (uint32_t tunnelID);
|
TunnelGatewayBuffer (uint32_t tunnelID);
|
||||||
~TunnelGatewayBuffer ();
|
~TunnelGatewayBuffer ();
|
||||||
void PutI2NPMsg (const TunnelMessageBlock& block);
|
void PutI2NPMsg (const TunnelMessageBlock& block);
|
||||||
const std::vector<std::shared_ptr<I2NPMessage> >& GetTunnelDataMsgs () const { return m_TunnelDataMsgs; };
|
const std::vector<std::shared_ptr<I2NPMessage> >& GetTunnelDataMsgs () const { return m_TunnelDataMsgs; };
|
||||||
void ClearTunnelDataMsgs ();
|
void ClearTunnelDataMsgs ();
|
||||||
void CompleteCurrentTunnelDataMessage ();
|
void CompleteCurrentTunnelDataMessage ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateCurrentTunnelDataMessage ();
|
void CreateCurrentTunnelDataMessage ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint32_t m_TunnelID;
|
uint32_t m_TunnelID;
|
||||||
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelDataMsgs;
|
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelDataMsgs;
|
||||||
std::shared_ptr<I2NPMessage> m_CurrentTunnelDataMsg;
|
std::shared_ptr<I2NPMessage> m_CurrentTunnelDataMsg;
|
||||||
size_t m_RemainingSize;
|
size_t m_RemainingSize;
|
||||||
uint8_t m_NonZeroRandomBuffer[TUNNEL_DATA_MAX_PAYLOAD_SIZE];
|
uint8_t m_NonZeroRandomBuffer[TUNNEL_DATA_MAX_PAYLOAD_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
class TunnelGateway
|
class TunnelGateway
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TunnelGateway (TunnelBase * tunnel):
|
TunnelGateway (TunnelBase * tunnel):
|
||||||
m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {};
|
m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {};
|
||||||
void SendTunnelDataMsg (const TunnelMessageBlock& block);
|
void SendTunnelDataMsg (const TunnelMessageBlock& block);
|
||||||
void PutTunnelDataMsg (const TunnelMessageBlock& block);
|
void PutTunnelDataMsg (const TunnelMessageBlock& block);
|
||||||
void SendBuffer ();
|
void SendBuffer ();
|
||||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
TunnelBase * m_Tunnel;
|
TunnelBase * m_Tunnel;
|
||||||
TunnelGatewayBuffer m_Buffer;
|
TunnelGatewayBuffer m_Buffer;
|
||||||
size_t m_NumSentBytes;
|
size_t m_NumSentBytes;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
796
TunnelPool.cpp
796
TunnelPool.cpp
|
@ -12,424 +12,424 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
TunnelPool::TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
|
TunnelPool::TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
|
||||||
m_LocalDestination (localDestination), m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
|
m_LocalDestination (localDestination), m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
|
||||||
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true)
|
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
TunnelPool::~TunnelPool ()
|
TunnelPool::~TunnelPool ()
|
||||||
{
|
{
|
||||||
DetachTunnels ();
|
DetachTunnels ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::SetExplicitPeers (std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers)
|
void TunnelPool::SetExplicitPeers (std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers)
|
||||||
{
|
{
|
||||||
m_ExplicitPeers = explicitPeers;
|
m_ExplicitPeers = explicitPeers;
|
||||||
if (m_ExplicitPeers)
|
if (m_ExplicitPeers)
|
||||||
{
|
{
|
||||||
int size = m_ExplicitPeers->size ();
|
int size = m_ExplicitPeers->size ();
|
||||||
if (m_NumInboundHops > size)
|
if (m_NumInboundHops > size)
|
||||||
{
|
{
|
||||||
m_NumInboundHops = size;
|
m_NumInboundHops = size;
|
||||||
LogPrint (eLogInfo, "Inbound tunnel length has beed adjusted to ", size, " for explicit peers");
|
LogPrint (eLogInfo, "Inbound tunnel length has beed adjusted to ", size, " for explicit peers");
|
||||||
}
|
}
|
||||||
if (m_NumOutboundHops > size)
|
if (m_NumOutboundHops > size)
|
||||||
{
|
{
|
||||||
m_NumOutboundHops = size;
|
m_NumOutboundHops = size;
|
||||||
LogPrint (eLogInfo, "Outbound tunnel length has beed adjusted to ", size, " for explicit peers");
|
LogPrint (eLogInfo, "Outbound tunnel length has beed adjusted to ", size, " for explicit peers");
|
||||||
}
|
}
|
||||||
m_NumInboundTunnels = 1;
|
m_NumInboundTunnels = 1;
|
||||||
m_NumOutboundTunnels = 1;
|
m_NumOutboundTunnels = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::DetachTunnels ()
|
void TunnelPool::DetachTunnels ()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||||
for (auto it: m_InboundTunnels)
|
for (auto it: m_InboundTunnels)
|
||||||
it->SetTunnelPool (nullptr);
|
it->SetTunnelPool (nullptr);
|
||||||
m_InboundTunnels.clear ();
|
m_InboundTunnels.clear ();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||||
for (auto it: m_OutboundTunnels)
|
for (auto it: m_OutboundTunnels)
|
||||||
it->SetTunnelPool (nullptr);
|
it->SetTunnelPool (nullptr);
|
||||||
m_OutboundTunnels.clear ();
|
m_OutboundTunnels.clear ();
|
||||||
}
|
}
|
||||||
m_Tests.clear ();
|
m_Tests.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel)
|
void TunnelPool::TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel)
|
||||||
{
|
{
|
||||||
if (!m_IsActive) return;
|
if (!m_IsActive) return;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||||
m_InboundTunnels.insert (createdTunnel);
|
m_InboundTunnels.insert (createdTunnel);
|
||||||
}
|
}
|
||||||
if (m_LocalDestination)
|
if (m_LocalDestination)
|
||||||
m_LocalDestination->SetLeaseSetUpdated ();
|
m_LocalDestination->SetLeaseSetUpdated ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::TunnelExpired (std::shared_ptr<InboundTunnel> expiredTunnel)
|
void TunnelPool::TunnelExpired (std::shared_ptr<InboundTunnel> expiredTunnel)
|
||||||
{
|
{
|
||||||
if (expiredTunnel)
|
if (expiredTunnel)
|
||||||
{
|
{
|
||||||
expiredTunnel->SetTunnelPool (nullptr);
|
expiredTunnel->SetTunnelPool (nullptr);
|
||||||
for (auto it: m_Tests)
|
for (auto it: m_Tests)
|
||||||
if (it.second.second == expiredTunnel) it.second.second = nullptr;
|
if (it.second.second == expiredTunnel) it.second.second = nullptr;
|
||||||
|
|
||||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||||
m_InboundTunnels.erase (expiredTunnel);
|
m_InboundTunnels.erase (expiredTunnel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel)
|
void TunnelPool::TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel)
|
||||||
{
|
{
|
||||||
if (!m_IsActive) return;
|
if (!m_IsActive) return;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||||
m_OutboundTunnels.insert (createdTunnel);
|
m_OutboundTunnels.insert (createdTunnel);
|
||||||
}
|
}
|
||||||
//CreatePairedInboundTunnel (createdTunnel);
|
//CreatePairedInboundTunnel (createdTunnel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::TunnelExpired (std::shared_ptr<OutboundTunnel> expiredTunnel)
|
void TunnelPool::TunnelExpired (std::shared_ptr<OutboundTunnel> expiredTunnel)
|
||||||
{
|
{
|
||||||
if (expiredTunnel)
|
if (expiredTunnel)
|
||||||
{
|
{
|
||||||
expiredTunnel->SetTunnelPool (nullptr);
|
expiredTunnel->SetTunnelPool (nullptr);
|
||||||
for (auto it: m_Tests)
|
for (auto it: m_Tests)
|
||||||
if (it.second.first == expiredTunnel) it.second.first = nullptr;
|
if (it.second.first == expiredTunnel) it.second.first = nullptr;
|
||||||
|
|
||||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||||
m_OutboundTunnels.erase (expiredTunnel);
|
m_OutboundTunnels.erase (expiredTunnel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<InboundTunnel> > TunnelPool::GetInboundTunnels (int num) const
|
std::vector<std::shared_ptr<InboundTunnel> > TunnelPool::GetInboundTunnels (int num) const
|
||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<InboundTunnel> > v;
|
std::vector<std::shared_ptr<InboundTunnel> > v;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||||
for (auto it : m_InboundTunnels)
|
for (auto it : m_InboundTunnels)
|
||||||
{
|
{
|
||||||
if (i >= num) break;
|
if (i >= num) break;
|
||||||
if (it->IsEstablished ())
|
if (it->IsEstablished ())
|
||||||
{
|
{
|
||||||
v.push_back (it);
|
v.push_back (it);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<OutboundTunnel> TunnelPool::GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded) const
|
std::shared_ptr<OutboundTunnel> TunnelPool::GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded) const
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||||
return GetNextTunnel (m_OutboundTunnels, excluded);
|
return GetNextTunnel (m_OutboundTunnels, excluded);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<InboundTunnel> TunnelPool::GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded) const
|
std::shared_ptr<InboundTunnel> TunnelPool::GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded) const
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||||
return GetNextTunnel (m_InboundTunnels, excluded);
|
return GetNextTunnel (m_InboundTunnels, excluded);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class TTunnels>
|
template<class TTunnels>
|
||||||
typename TTunnels::value_type TunnelPool::GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const
|
typename TTunnels::value_type TunnelPool::GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const
|
||||||
{
|
{
|
||||||
if (tunnels.empty ()) return nullptr;
|
if (tunnels.empty ()) return nullptr;
|
||||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
uint32_t ind = rnd.GenerateWord32 (0, tunnels.size ()/2), i = 0;
|
uint32_t ind = rnd.GenerateWord32 (0, tunnels.size ()/2), i = 0;
|
||||||
typename TTunnels::value_type tunnel = nullptr;
|
typename TTunnels::value_type tunnel = nullptr;
|
||||||
for (auto it: tunnels)
|
for (auto it: tunnels)
|
||||||
{
|
{
|
||||||
if (it->IsEstablished () && it != excluded)
|
if (it->IsEstablished () && it != excluded)
|
||||||
{
|
{
|
||||||
tunnel = it;
|
tunnel = it;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (i > ind && tunnel) break;
|
if (i > ind && tunnel) break;
|
||||||
}
|
}
|
||||||
if (!tunnel && excluded && excluded->IsEstablished ()) tunnel = excluded;
|
if (!tunnel && excluded && excluded->IsEstablished ()) tunnel = excluded;
|
||||||
return tunnel;
|
return tunnel;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<OutboundTunnel> TunnelPool::GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const
|
std::shared_ptr<OutboundTunnel> TunnelPool::GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const
|
||||||
{
|
{
|
||||||
if (old && old->IsEstablished ()) return old;
|
if (old && old->IsEstablished ()) return old;
|
||||||
std::shared_ptr<OutboundTunnel> tunnel;
|
std::shared_ptr<OutboundTunnel> tunnel;
|
||||||
if (old)
|
if (old)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||||
for (auto it: m_OutboundTunnels)
|
for (auto it: m_OutboundTunnels)
|
||||||
if (it->IsEstablished () && old->GetEndpointRouter ()->GetIdentHash () == it->GetEndpointRouter ()->GetIdentHash ())
|
if (it->IsEstablished () && old->GetEndpointRouter ()->GetIdentHash () == it->GetEndpointRouter ()->GetIdentHash ())
|
||||||
{
|
{
|
||||||
tunnel = it;
|
tunnel = it;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tunnel)
|
if (!tunnel)
|
||||||
tunnel = GetNextOutboundTunnel ();
|
tunnel = GetNextOutboundTunnel ();
|
||||||
return tunnel;
|
return tunnel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::CreateTunnels ()
|
void TunnelPool::CreateTunnels ()
|
||||||
{
|
{
|
||||||
int num = 0;
|
int num = 0;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||||
for (auto it : m_InboundTunnels)
|
for (auto it : m_InboundTunnels)
|
||||||
if (it->IsEstablished ()) num++;
|
if (it->IsEstablished ()) num++;
|
||||||
}
|
}
|
||||||
for (int i = num; i < m_NumInboundTunnels; i++)
|
for (int i = num; i < m_NumInboundTunnels; i++)
|
||||||
CreateInboundTunnel ();
|
CreateInboundTunnel ();
|
||||||
|
|
||||||
num = 0;
|
num = 0;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||||
for (auto it : m_OutboundTunnels)
|
for (auto it : m_OutboundTunnels)
|
||||||
if (it->IsEstablished ()) num++;
|
if (it->IsEstablished ()) num++;
|
||||||
}
|
}
|
||||||
for (int i = num; i < m_NumOutboundTunnels; i++)
|
for (int i = num; i < m_NumOutboundTunnels; i++)
|
||||||
CreateOutboundTunnel ();
|
CreateOutboundTunnel ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::TestTunnels ()
|
void TunnelPool::TestTunnels ()
|
||||||
{
|
{
|
||||||
auto& rnd = i2p::context.GetRandomNumberGenerator ();
|
auto& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
for (auto it: m_Tests)
|
for (auto it: m_Tests)
|
||||||
{
|
{
|
||||||
LogPrint ("Tunnel test ", (int)it.first, " failed");
|
LogPrint ("Tunnel test ", (int)it.first, " failed");
|
||||||
// if test failed again with another tunnel we consider it failed
|
// if test failed again with another tunnel we consider it failed
|
||||||
if (it.second.first)
|
if (it.second.first)
|
||||||
{
|
{
|
||||||
if (it.second.first->GetState () == eTunnelStateTestFailed)
|
if (it.second.first->GetState () == eTunnelStateTestFailed)
|
||||||
{
|
{
|
||||||
it.second.first->SetState (eTunnelStateFailed);
|
it.second.first->SetState (eTunnelStateFailed);
|
||||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||||
m_OutboundTunnels.erase (it.second.first);
|
m_OutboundTunnels.erase (it.second.first);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
it.second.first->SetState (eTunnelStateTestFailed);
|
it.second.first->SetState (eTunnelStateTestFailed);
|
||||||
}
|
}
|
||||||
if (it.second.second)
|
if (it.second.second)
|
||||||
{
|
{
|
||||||
if (it.second.second->GetState () == eTunnelStateTestFailed)
|
if (it.second.second->GetState () == eTunnelStateTestFailed)
|
||||||
{
|
{
|
||||||
it.second.second->SetState (eTunnelStateFailed);
|
it.second.second->SetState (eTunnelStateFailed);
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||||
m_InboundTunnels.erase (it.second.second);
|
m_InboundTunnels.erase (it.second.second);
|
||||||
}
|
}
|
||||||
if (m_LocalDestination)
|
if (m_LocalDestination)
|
||||||
m_LocalDestination->SetLeaseSetUpdated ();
|
m_LocalDestination->SetLeaseSetUpdated ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
it.second.second->SetState (eTunnelStateTestFailed);
|
it.second.second->SetState (eTunnelStateTestFailed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_Tests.clear ();
|
m_Tests.clear ();
|
||||||
// new tests
|
// new tests
|
||||||
auto it1 = m_OutboundTunnels.begin ();
|
auto it1 = m_OutboundTunnels.begin ();
|
||||||
auto it2 = m_InboundTunnels.begin ();
|
auto it2 = m_InboundTunnels.begin ();
|
||||||
while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ())
|
while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ())
|
||||||
{
|
{
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
if ((*it1)->IsFailed ())
|
if ((*it1)->IsFailed ())
|
||||||
{
|
{
|
||||||
failed = true;
|
failed = true;
|
||||||
it1++;
|
it1++;
|
||||||
}
|
}
|
||||||
if ((*it2)->IsFailed ())
|
if ((*it2)->IsFailed ())
|
||||||
{
|
{
|
||||||
failed = true;
|
failed = true;
|
||||||
it2++;
|
it2++;
|
||||||
}
|
}
|
||||||
if (!failed)
|
if (!failed)
|
||||||
{
|
{
|
||||||
uint32_t msgID = rnd.GenerateWord32 ();
|
uint32_t msgID = rnd.GenerateWord32 ();
|
||||||
m_Tests[msgID] = std::make_pair (*it1, *it2);
|
m_Tests[msgID] = std::make_pair (*it1, *it2);
|
||||||
(*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
|
(*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
|
||||||
CreateDeliveryStatusMsg (msgID));
|
CreateDeliveryStatusMsg (msgID));
|
||||||
it1++; it2++;
|
it1++; it2++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
void TunnelPool::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
if (m_LocalDestination)
|
if (m_LocalDestination)
|
||||||
m_LocalDestination->ProcessGarlicMessage (msg);
|
m_LocalDestination->ProcessGarlicMessage (msg);
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Local destination doesn't exist. Dropped");
|
LogPrint (eLogWarning, "Local destination doesn't exist. Dropped");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg)
|
void TunnelPool::ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
const uint8_t * buf = msg->GetPayload ();
|
const uint8_t * buf = msg->GetPayload ();
|
||||||
uint32_t msgID = bufbe32toh (buf);
|
uint32_t msgID = bufbe32toh (buf);
|
||||||
buf += 4;
|
buf += 4;
|
||||||
uint64_t timestamp = bufbe64toh (buf);
|
uint64_t timestamp = bufbe64toh (buf);
|
||||||
|
|
||||||
auto it = m_Tests.find (msgID);
|
auto it = m_Tests.find (msgID);
|
||||||
if (it != m_Tests.end ())
|
if (it != m_Tests.end ())
|
||||||
{
|
{
|
||||||
// restore from test failed state if any
|
// restore from test failed state if any
|
||||||
if (it->second.first->GetState () == eTunnelStateTestFailed)
|
if (it->second.first->GetState () == eTunnelStateTestFailed)
|
||||||
it->second.first->SetState (eTunnelStateEstablished);
|
it->second.first->SetState (eTunnelStateEstablished);
|
||||||
if (it->second.second->GetState () == eTunnelStateTestFailed)
|
if (it->second.second->GetState () == eTunnelStateTestFailed)
|
||||||
it->second.second->SetState (eTunnelStateEstablished);
|
it->second.second->SetState (eTunnelStateEstablished);
|
||||||
LogPrint ("Tunnel test ", it->first, " successive. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds");
|
LogPrint ("Tunnel test ", it->first, " successive. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds");
|
||||||
m_Tests.erase (it);
|
m_Tests.erase (it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_LocalDestination)
|
if (m_LocalDestination)
|
||||||
m_LocalDestination->ProcessDeliveryStatusMessage (msg);
|
m_LocalDestination->ProcessDeliveryStatusMessage (msg);
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Local destination doesn't exist. Dropped");
|
LogPrint (eLogWarning, "Local destination doesn't exist. Dropped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const
|
std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const
|
||||||
{
|
{
|
||||||
bool isExploratory = (m_LocalDestination == &i2p::context); // TODO: implement it better
|
bool isExploratory = (m_LocalDestination == &i2p::context); // TODO: implement it better
|
||||||
auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop):
|
auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop):
|
||||||
i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop);
|
i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop);
|
||||||
|
|
||||||
if (!hop || hop->GetProfile ()->IsBad ())
|
if (!hop || hop->GetProfile ()->IsBad ())
|
||||||
hop = i2p::data::netdb.GetRandomRouter ();
|
hop = i2p::data::netdb.GetRandomRouter ();
|
||||||
return hop;
|
return hop;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TunnelPool::SelectPeers (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >& hops, bool isInbound)
|
bool TunnelPool::SelectPeers (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >& hops, bool isInbound)
|
||||||
{
|
{
|
||||||
if (m_ExplicitPeers) return SelectExplicitPeers (hops, isInbound);
|
if (m_ExplicitPeers) return SelectExplicitPeers (hops, isInbound);
|
||||||
auto prevHop = i2p::context.GetSharedRouterInfo ();
|
auto prevHop = i2p::context.GetSharedRouterInfo ();
|
||||||
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
|
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
|
||||||
if (i2p::transport::transports.GetNumPeers () > 25)
|
if (i2p::transport::transports.GetNumPeers () > 25)
|
||||||
{
|
{
|
||||||
auto r = i2p::transport::transports.GetRandomPeer ();
|
auto r = i2p::transport::transports.GetRandomPeer ();
|
||||||
if (r && !r->GetProfile ()->IsBad ())
|
if (r && !r->GetProfile ()->IsBad ())
|
||||||
{
|
{
|
||||||
prevHop = r;
|
prevHop = r;
|
||||||
hops.push_back (r);
|
hops.push_back (r);
|
||||||
numHops--;
|
numHops--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < numHops; i++)
|
for (int i = 0; i < numHops; i++)
|
||||||
{
|
{
|
||||||
auto hop = SelectNextHop (prevHop);
|
auto hop = SelectNextHop (prevHop);
|
||||||
if (!hop)
|
if (!hop)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Can't select next hop");
|
LogPrint (eLogError, "Can't select next hop");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
prevHop = hop;
|
prevHop = hop;
|
||||||
hops.push_back (hop);
|
hops.push_back (hop);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TunnelPool::SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >& hops, bool isInbound)
|
bool TunnelPool::SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >& hops, bool isInbound)
|
||||||
{
|
{
|
||||||
int size = m_ExplicitPeers->size ();
|
int size = m_ExplicitPeers->size ();
|
||||||
std::vector<int> peerIndicies;
|
std::vector<int> peerIndicies;
|
||||||
for (int i = 0; i < size; i++) peerIndicies.push_back(i);
|
for (int i = 0; i < size; i++) peerIndicies.push_back(i);
|
||||||
std::random_shuffle (peerIndicies.begin(), peerIndicies.end());
|
std::random_shuffle (peerIndicies.begin(), peerIndicies.end());
|
||||||
|
|
||||||
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
|
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
|
||||||
for (int i = 0; i < numHops; i++)
|
for (int i = 0; i < numHops; i++)
|
||||||
{
|
{
|
||||||
auto& ident = (*m_ExplicitPeers)[peerIndicies[i]];
|
auto& ident = (*m_ExplicitPeers)[peerIndicies[i]];
|
||||||
auto r = i2p::data::netdb.FindRouter (ident);
|
auto r = i2p::data::netdb.FindRouter (ident);
|
||||||
if (r)
|
if (r)
|
||||||
hops.push_back (r);
|
hops.push_back (r);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Can't find router for ", ident.ToBase64 ());
|
LogPrint (eLogInfo, "Can't find router for ", ident.ToBase64 ());
|
||||||
i2p::data::netdb.RequestDestination (ident);
|
i2p::data::netdb.RequestDestination (ident);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::CreateInboundTunnel ()
|
void TunnelPool::CreateInboundTunnel ()
|
||||||
{
|
{
|
||||||
auto outboundTunnel = GetNextOutboundTunnel ();
|
auto outboundTunnel = GetNextOutboundTunnel ();
|
||||||
if (!outboundTunnel)
|
if (!outboundTunnel)
|
||||||
outboundTunnel = tunnels.GetNextOutboundTunnel ();
|
outboundTunnel = tunnels.GetNextOutboundTunnel ();
|
||||||
LogPrint ("Creating destination inbound tunnel...");
|
LogPrint ("Creating destination inbound tunnel...");
|
||||||
std::vector<std::shared_ptr<const i2p::data::RouterInfo> > hops;
|
std::vector<std::shared_ptr<const i2p::data::RouterInfo> > hops;
|
||||||
if (SelectPeers (hops, true))
|
if (SelectPeers (hops, true))
|
||||||
{
|
{
|
||||||
std::reverse (hops.begin (), hops.end ());
|
std::reverse (hops.begin (), hops.end ());
|
||||||
auto tunnel = tunnels.CreateTunnel<InboundTunnel> (std::make_shared<TunnelConfig> (hops), outboundTunnel);
|
auto tunnel = tunnels.CreateTunnel<InboundTunnel> (std::make_shared<TunnelConfig> (hops), outboundTunnel);
|
||||||
tunnel->SetTunnelPool (shared_from_this ());
|
tunnel->SetTunnelPool (shared_from_this ());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "Can't create inbound tunnel. No peers available");
|
LogPrint (eLogError, "Can't create inbound tunnel. No peers available");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::RecreateInboundTunnel (std::shared_ptr<InboundTunnel> tunnel)
|
void TunnelPool::RecreateInboundTunnel (std::shared_ptr<InboundTunnel> tunnel)
|
||||||
{
|
{
|
||||||
auto outboundTunnel = GetNextOutboundTunnel ();
|
auto outboundTunnel = GetNextOutboundTunnel ();
|
||||||
if (!outboundTunnel)
|
if (!outboundTunnel)
|
||||||
outboundTunnel = tunnels.GetNextOutboundTunnel ();
|
outboundTunnel = tunnels.GetNextOutboundTunnel ();
|
||||||
LogPrint ("Re-creating destination inbound tunnel...");
|
LogPrint ("Re-creating destination inbound tunnel...");
|
||||||
auto newTunnel = tunnels.CreateTunnel<InboundTunnel> (tunnel->GetTunnelConfig ()->Clone (), outboundTunnel);
|
auto newTunnel = tunnels.CreateTunnel<InboundTunnel> (tunnel->GetTunnelConfig ()->Clone (), outboundTunnel);
|
||||||
newTunnel->SetTunnelPool (shared_from_this());
|
newTunnel->SetTunnelPool (shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::CreateOutboundTunnel ()
|
void TunnelPool::CreateOutboundTunnel ()
|
||||||
{
|
{
|
||||||
auto inboundTunnel = GetNextInboundTunnel ();
|
auto inboundTunnel = GetNextInboundTunnel ();
|
||||||
if (!inboundTunnel)
|
if (!inboundTunnel)
|
||||||
inboundTunnel = tunnels.GetNextInboundTunnel ();
|
inboundTunnel = tunnels.GetNextInboundTunnel ();
|
||||||
if (inboundTunnel)
|
if (inboundTunnel)
|
||||||
{
|
{
|
||||||
LogPrint ("Creating destination outbound tunnel...");
|
LogPrint ("Creating destination outbound tunnel...");
|
||||||
std::vector<std::shared_ptr<const i2p::data::RouterInfo> > hops;
|
std::vector<std::shared_ptr<const i2p::data::RouterInfo> > hops;
|
||||||
if (SelectPeers (hops, false))
|
if (SelectPeers (hops, false))
|
||||||
{
|
{
|
||||||
auto tunnel = tunnels.CreateTunnel<OutboundTunnel> (
|
auto tunnel = tunnels.CreateTunnel<OutboundTunnel> (
|
||||||
std::make_shared<TunnelConfig> (hops, inboundTunnel->GetTunnelConfig ()));
|
std::make_shared<TunnelConfig> (hops, inboundTunnel->GetTunnelConfig ()));
|
||||||
tunnel->SetTunnelPool (shared_from_this ());
|
tunnel->SetTunnelPool (shared_from_this ());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "Can't create outbound tunnel. No peers available");
|
LogPrint (eLogError, "Can't create outbound tunnel. No peers available");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "Can't create outbound tunnel. No inbound tunnels found");
|
LogPrint (eLogError, "Can't create outbound tunnel. No inbound tunnels found");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel)
|
void TunnelPool::RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel)
|
||||||
{
|
{
|
||||||
auto inboundTunnel = GetNextInboundTunnel ();
|
auto inboundTunnel = GetNextInboundTunnel ();
|
||||||
if (!inboundTunnel)
|
if (!inboundTunnel)
|
||||||
inboundTunnel = tunnels.GetNextInboundTunnel ();
|
inboundTunnel = tunnels.GetNextInboundTunnel ();
|
||||||
if (inboundTunnel)
|
if (inboundTunnel)
|
||||||
{
|
{
|
||||||
LogPrint ("Re-creating destination outbound tunnel...");
|
LogPrint ("Re-creating destination outbound tunnel...");
|
||||||
auto newTunnel = tunnels.CreateTunnel<OutboundTunnel> (
|
auto newTunnel = tunnels.CreateTunnel<OutboundTunnel> (
|
||||||
tunnel->GetTunnelConfig ()->Clone (inboundTunnel->GetTunnelConfig ()));
|
tunnel->GetTunnelConfig ()->Clone (inboundTunnel->GetTunnelConfig ()));
|
||||||
newTunnel->SetTunnelPool (shared_from_this ());
|
newTunnel->SetTunnelPool (shared_from_this ());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint ("Can't re-create outbound tunnel. No inbound tunnels found");
|
LogPrint ("Can't re-create outbound tunnel. No inbound tunnels found");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel)
|
void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Creating paired inbound tunnel...");
|
LogPrint (eLogInfo, "Creating paired inbound tunnel...");
|
||||||
auto tunnel = tunnels.CreateTunnel<InboundTunnel> (outboundTunnel->GetTunnelConfig ()->Invert (), outboundTunnel);
|
auto tunnel = tunnels.CreateTunnel<InboundTunnel> (outboundTunnel->GetTunnelConfig ()->Invert (), outboundTunnel);
|
||||||
tunnel->SetTunnelPool (shared_from_this ());
|
tunnel->SetTunnelPool (shared_from_this ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
108
TunnelPool.h
108
TunnelPool.h
|
@ -19,71 +19,71 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
class Tunnel;
|
class Tunnel;
|
||||||
class InboundTunnel;
|
class InboundTunnel;
|
||||||
class OutboundTunnel;
|
class OutboundTunnel;
|
||||||
|
|
||||||
class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination
|
class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels);
|
TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels);
|
||||||
~TunnelPool ();
|
~TunnelPool ();
|
||||||
|
|
||||||
i2p::garlic::GarlicDestination * GetLocalDestination () const { return m_LocalDestination; };
|
i2p::garlic::GarlicDestination * GetLocalDestination () const { return m_LocalDestination; };
|
||||||
void SetLocalDestination (i2p::garlic::GarlicDestination * destination) { m_LocalDestination = destination; };
|
void SetLocalDestination (i2p::garlic::GarlicDestination * destination) { m_LocalDestination = destination; };
|
||||||
void SetExplicitPeers (std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers);
|
void SetExplicitPeers (std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers);
|
||||||
|
|
||||||
void CreateTunnels ();
|
void CreateTunnels ();
|
||||||
void TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel);
|
void TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel);
|
||||||
void TunnelExpired (std::shared_ptr<InboundTunnel> expiredTunnel);
|
void TunnelExpired (std::shared_ptr<InboundTunnel> expiredTunnel);
|
||||||
void TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel);
|
void TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel);
|
||||||
void TunnelExpired (std::shared_ptr<OutboundTunnel> expiredTunnel);
|
void TunnelExpired (std::shared_ptr<OutboundTunnel> expiredTunnel);
|
||||||
void RecreateInboundTunnel (std::shared_ptr<InboundTunnel> tunnel);
|
void RecreateInboundTunnel (std::shared_ptr<InboundTunnel> tunnel);
|
||||||
void RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel);
|
void RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel);
|
||||||
std::vector<std::shared_ptr<InboundTunnel> > GetInboundTunnels (int num) const;
|
std::vector<std::shared_ptr<InboundTunnel> > GetInboundTunnels (int num) const;
|
||||||
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded = nullptr) const;
|
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded = nullptr) const;
|
||||||
std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr) const;
|
std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr) const;
|
||||||
std::shared_ptr<OutboundTunnel> GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const;
|
std::shared_ptr<OutboundTunnel> GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const;
|
||||||
|
|
||||||
void TestTunnels ();
|
void TestTunnels ();
|
||||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg);
|
void ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
bool IsActive () const { return m_IsActive; };
|
bool IsActive () const { return m_IsActive; };
|
||||||
void SetActive (bool isActive) { m_IsActive = isActive; };
|
void SetActive (bool isActive) { m_IsActive = isActive; };
|
||||||
void DetachTunnels ();
|
void DetachTunnels ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateInboundTunnel ();
|
void CreateInboundTunnel ();
|
||||||
void CreateOutboundTunnel ();
|
void CreateOutboundTunnel ();
|
||||||
void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel);
|
void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel);
|
||||||
template<class TTunnels>
|
template<class TTunnels>
|
||||||
typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const;
|
typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const;
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
|
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
|
||||||
bool SelectPeers (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >& hops, bool isInbound);
|
bool SelectPeers (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >& hops, bool isInbound);
|
||||||
bool SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >& hops, bool isInbound);
|
bool SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >& hops, bool isInbound);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
i2p::garlic::GarlicDestination * m_LocalDestination;
|
i2p::garlic::GarlicDestination * m_LocalDestination;
|
||||||
int m_NumInboundHops, m_NumOutboundHops, m_NumInboundTunnels, m_NumOutboundTunnels;
|
int m_NumInboundHops, m_NumOutboundHops, m_NumInboundTunnels, m_NumOutboundTunnels;
|
||||||
std::shared_ptr<std::vector<i2p::data::IdentHash> > m_ExplicitPeers;
|
std::shared_ptr<std::vector<i2p::data::IdentHash> > m_ExplicitPeers;
|
||||||
mutable std::mutex m_InboundTunnelsMutex;
|
mutable std::mutex m_InboundTunnelsMutex;
|
||||||
std::set<std::shared_ptr<InboundTunnel>, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first
|
std::set<std::shared_ptr<InboundTunnel>, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first
|
||||||
mutable std::mutex m_OutboundTunnelsMutex;
|
mutable std::mutex m_OutboundTunnelsMutex;
|
||||||
std::set<std::shared_ptr<OutboundTunnel>, TunnelCreationTimeCmp> m_OutboundTunnels;
|
std::set<std::shared_ptr<OutboundTunnel>, TunnelCreationTimeCmp> m_OutboundTunnels;
|
||||||
std::map<uint32_t, std::pair<std::shared_ptr<OutboundTunnel>, std::shared_ptr<InboundTunnel> > > m_Tests;
|
std::map<uint32_t, std::pair<std::shared_ptr<OutboundTunnel>, std::shared_ptr<InboundTunnel> > > m_Tests;
|
||||||
bool m_IsActive;
|
bool m_IsActive;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; };
|
const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; };
|
||||||
const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; };
|
const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; };
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
22
UPnP.h
22
UPnP.h
|
@ -21,22 +21,22 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
class UPnP
|
class UPnP
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
UPnP ();
|
UPnP ();
|
||||||
~UPnP ();
|
~UPnP ();
|
||||||
void Close ();
|
void Close ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
void Discover ();
|
void Discover ();
|
||||||
void TryPortMapping (int type, int port);
|
void TryPortMapping (int type, int port);
|
||||||
void CloseMapping (int type, int port);
|
void CloseMapping (int type, int port);
|
||||||
private:
|
private:
|
||||||
void Run ();
|
void Run ();
|
||||||
|
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
struct UPNPUrls m_upnpUrls;
|
struct UPNPUrls m_upnpUrls;
|
||||||
|
@ -54,7 +54,7 @@ namespace transport
|
||||||
#else
|
#else
|
||||||
HINSTANCE m_Module;
|
HINSTANCE m_Module;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
622
aes.cpp
622
aes.cpp
|
@ -8,350 +8,350 @@ namespace crypto
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef AESNI
|
#ifdef AESNI
|
||||||
|
|
||||||
#define KeyExpansion256(round0,round1) \
|
#define KeyExpansion256(round0,round1) \
|
||||||
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
|
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
|
||||||
"movaps %%xmm1, %%xmm4 \n" \
|
"movaps %%xmm1, %%xmm4 \n" \
|
||||||
"pslldq $4, %%xmm4 \n" \
|
"pslldq $4, %%xmm4 \n" \
|
||||||
"pxor %%xmm4, %%xmm1 \n" \
|
"pxor %%xmm4, %%xmm1 \n" \
|
||||||
"pslldq $4, %%xmm4 \n" \
|
"pslldq $4, %%xmm4 \n" \
|
||||||
"pxor %%xmm4, %%xmm1 \n" \
|
"pxor %%xmm4, %%xmm1 \n" \
|
||||||
"pslldq $4, %%xmm4 \n" \
|
"pslldq $4, %%xmm4 \n" \
|
||||||
"pxor %%xmm4, %%xmm1 \n" \
|
"pxor %%xmm4, %%xmm1 \n" \
|
||||||
"pxor %%xmm2, %%xmm1 \n" \
|
"pxor %%xmm2, %%xmm1 \n" \
|
||||||
"movaps %%xmm1, "#round0"(%[sched]) \n" \
|
"movaps %%xmm1, "#round0"(%[sched]) \n" \
|
||||||
"aeskeygenassist $0, %%xmm1, %%xmm4 \n" \
|
"aeskeygenassist $0, %%xmm1, %%xmm4 \n" \
|
||||||
"pshufd $0xaa, %%xmm4, %%xmm2 \n" \
|
"pshufd $0xaa, %%xmm4, %%xmm2 \n" \
|
||||||
"movaps %%xmm3, %%xmm4 \n" \
|
"movaps %%xmm3, %%xmm4 \n" \
|
||||||
"pslldq $4, %%xmm4 \n" \
|
"pslldq $4, %%xmm4 \n" \
|
||||||
"pxor %%xmm4, %%xmm3 \n" \
|
"pxor %%xmm4, %%xmm3 \n" \
|
||||||
"pslldq $4, %%xmm4 \n" \
|
"pslldq $4, %%xmm4 \n" \
|
||||||
"pxor %%xmm4, %%xmm3 \n" \
|
"pxor %%xmm4, %%xmm3 \n" \
|
||||||
"pslldq $4, %%xmm4 \n" \
|
"pslldq $4, %%xmm4 \n" \
|
||||||
"pxor %%xmm4, %%xmm3 \n" \
|
"pxor %%xmm4, %%xmm3 \n" \
|
||||||
"pxor %%xmm2, %%xmm3 \n" \
|
"pxor %%xmm2, %%xmm3 \n" \
|
||||||
"movaps %%xmm3, "#round1"(%[sched]) \n"
|
"movaps %%xmm3, "#round1"(%[sched]) \n"
|
||||||
|
|
||||||
void ECBCryptoAESNI::ExpandKey (const AESKey& key)
|
void ECBCryptoAESNI::ExpandKey (const AESKey& key)
|
||||||
{
|
{
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[key]), %%xmm1 \n"
|
"movups (%[key]), %%xmm1 \n"
|
||||||
"movups 16(%[key]), %%xmm3 \n"
|
"movups 16(%[key]), %%xmm3 \n"
|
||||||
"movaps %%xmm1, (%[sched]) \n"
|
"movaps %%xmm1, (%[sched]) \n"
|
||||||
"movaps %%xmm3, 16(%[sched]) \n"
|
"movaps %%xmm3, 16(%[sched]) \n"
|
||||||
"aeskeygenassist $1, %%xmm3, %%xmm2 \n"
|
"aeskeygenassist $1, %%xmm3, %%xmm2 \n"
|
||||||
KeyExpansion256(32,48)
|
KeyExpansion256(32,48)
|
||||||
"aeskeygenassist $2, %%xmm3, %%xmm2 \n"
|
"aeskeygenassist $2, %%xmm3, %%xmm2 \n"
|
||||||
KeyExpansion256(64,80)
|
KeyExpansion256(64,80)
|
||||||
"aeskeygenassist $4, %%xmm3, %%xmm2 \n"
|
"aeskeygenassist $4, %%xmm3, %%xmm2 \n"
|
||||||
KeyExpansion256(96,112)
|
KeyExpansion256(96,112)
|
||||||
"aeskeygenassist $8, %%xmm3, %%xmm2 \n"
|
"aeskeygenassist $8, %%xmm3, %%xmm2 \n"
|
||||||
KeyExpansion256(128,144)
|
KeyExpansion256(128,144)
|
||||||
"aeskeygenassist $16, %%xmm3, %%xmm2 \n"
|
"aeskeygenassist $16, %%xmm3, %%xmm2 \n"
|
||||||
KeyExpansion256(160,176)
|
KeyExpansion256(160,176)
|
||||||
"aeskeygenassist $32, %%xmm3, %%xmm2 \n"
|
"aeskeygenassist $32, %%xmm3, %%xmm2 \n"
|
||||||
KeyExpansion256(192,208)
|
KeyExpansion256(192,208)
|
||||||
"aeskeygenassist $64, %%xmm3, %%xmm2 \n"
|
"aeskeygenassist $64, %%xmm3, %%xmm2 \n"
|
||||||
// key expansion final
|
// key expansion final
|
||||||
"pshufd $0xff, %%xmm2, %%xmm2 \n"
|
"pshufd $0xff, %%xmm2, %%xmm2 \n"
|
||||||
"movaps %%xmm1, %%xmm4 \n"
|
"movaps %%xmm1, %%xmm4 \n"
|
||||||
"pslldq $4, %%xmm4 \n"
|
"pslldq $4, %%xmm4 \n"
|
||||||
"pxor %%xmm4, %%xmm1 \n"
|
"pxor %%xmm4, %%xmm1 \n"
|
||||||
"pslldq $4, %%xmm4 \n"
|
"pslldq $4, %%xmm4 \n"
|
||||||
"pxor %%xmm4, %%xmm1 \n"
|
"pxor %%xmm4, %%xmm1 \n"
|
||||||
"pslldq $4, %%xmm4 \n"
|
"pslldq $4, %%xmm4 \n"
|
||||||
"pxor %%xmm4, %%xmm1 \n"
|
"pxor %%xmm4, %%xmm1 \n"
|
||||||
"pxor %%xmm2, %%xmm1 \n"
|
"pxor %%xmm2, %%xmm1 \n"
|
||||||
"movups %%xmm1, 224(%[sched]) \n"
|
"movups %%xmm1, 224(%[sched]) \n"
|
||||||
: // output
|
: // output
|
||||||
: [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input
|
: [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input
|
||||||
: "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged
|
: "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EncryptAES256(sched) \
|
#define EncryptAES256(sched) \
|
||||||
"pxor (%["#sched"]), %%xmm0 \n" \
|
"pxor (%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 16(%["#sched"]), %%xmm0 \n" \
|
"aesenc 16(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 32(%["#sched"]), %%xmm0 \n" \
|
"aesenc 32(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 48(%["#sched"]), %%xmm0 \n" \
|
"aesenc 48(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 64(%["#sched"]), %%xmm0 \n" \
|
"aesenc 64(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 80(%["#sched"]), %%xmm0 \n" \
|
"aesenc 80(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 96(%["#sched"]), %%xmm0 \n" \
|
"aesenc 96(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 112(%["#sched"]), %%xmm0 \n" \
|
"aesenc 112(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 128(%["#sched"]), %%xmm0 \n" \
|
"aesenc 128(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 144(%["#sched"]), %%xmm0 \n" \
|
"aesenc 144(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 160(%["#sched"]), %%xmm0 \n" \
|
"aesenc 160(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 176(%["#sched"]), %%xmm0 \n" \
|
"aesenc 176(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 192(%["#sched"]), %%xmm0 \n" \
|
"aesenc 192(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenc 208(%["#sched"]), %%xmm0 \n" \
|
"aesenc 208(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesenclast 224(%["#sched"]), %%xmm0 \n"
|
"aesenclast 224(%["#sched"]), %%xmm0 \n"
|
||||||
|
|
||||||
void ECBEncryptionAESNI::Encrypt (const ChipherBlock * in, ChipherBlock * out)
|
void ECBEncryptionAESNI::Encrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||||
{
|
{
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
EncryptAES256(sched)
|
EncryptAES256(sched)
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
|
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DecryptAES256(sched) \
|
#define DecryptAES256(sched) \
|
||||||
"pxor 224(%["#sched"]), %%xmm0 \n" \
|
"pxor 224(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 208(%["#sched"]), %%xmm0 \n" \
|
"aesdec 208(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 192(%["#sched"]), %%xmm0 \n" \
|
"aesdec 192(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 176(%["#sched"]), %%xmm0 \n" \
|
"aesdec 176(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 160(%["#sched"]), %%xmm0 \n" \
|
"aesdec 160(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 144(%["#sched"]), %%xmm0 \n" \
|
"aesdec 144(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 128(%["#sched"]), %%xmm0 \n" \
|
"aesdec 128(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 112(%["#sched"]), %%xmm0 \n" \
|
"aesdec 112(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 96(%["#sched"]), %%xmm0 \n" \
|
"aesdec 96(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 80(%["#sched"]), %%xmm0 \n" \
|
"aesdec 80(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 64(%["#sched"]), %%xmm0 \n" \
|
"aesdec 64(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 48(%["#sched"]), %%xmm0 \n" \
|
"aesdec 48(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 32(%["#sched"]), %%xmm0 \n" \
|
"aesdec 32(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdec 16(%["#sched"]), %%xmm0 \n" \
|
"aesdec 16(%["#sched"]), %%xmm0 \n" \
|
||||||
"aesdeclast (%["#sched"]), %%xmm0 \n"
|
"aesdeclast (%["#sched"]), %%xmm0 \n"
|
||||||
|
|
||||||
void ECBDecryptionAESNI::Decrypt (const ChipherBlock * in, ChipherBlock * out)
|
void ECBDecryptionAESNI::Decrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||||
{
|
{
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
DecryptAES256(sched)
|
DecryptAES256(sched)
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
|
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CallAESIMC(offset) \
|
#define CallAESIMC(offset) \
|
||||||
"movaps "#offset"(%[shed]), %%xmm0 \n" \
|
"movaps "#offset"(%[shed]), %%xmm0 \n" \
|
||||||
"aesimc %%xmm0, %%xmm0 \n" \
|
"aesimc %%xmm0, %%xmm0 \n" \
|
||||||
"movaps %%xmm0, "#offset"(%[shed]) \n"
|
"movaps %%xmm0, "#offset"(%[shed]) \n"
|
||||||
|
|
||||||
void ECBDecryptionAESNI::SetKey (const AESKey& key)
|
void ECBDecryptionAESNI::SetKey (const AESKey& key)
|
||||||
{
|
{
|
||||||
ExpandKey (key); // expand encryption key first
|
ExpandKey (key); // expand encryption key first
|
||||||
// then invert it using aesimc
|
// then invert it using aesimc
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
CallAESIMC(16)
|
CallAESIMC(16)
|
||||||
CallAESIMC(32)
|
CallAESIMC(32)
|
||||||
CallAESIMC(48)
|
CallAESIMC(48)
|
||||||
CallAESIMC(64)
|
CallAESIMC(64)
|
||||||
CallAESIMC(80)
|
CallAESIMC(80)
|
||||||
CallAESIMC(96)
|
CallAESIMC(96)
|
||||||
CallAESIMC(112)
|
CallAESIMC(112)
|
||||||
CallAESIMC(128)
|
CallAESIMC(128)
|
||||||
CallAESIMC(144)
|
CallAESIMC(144)
|
||||||
CallAESIMC(160)
|
CallAESIMC(160)
|
||||||
CallAESIMC(176)
|
CallAESIMC(176)
|
||||||
CallAESIMC(192)
|
CallAESIMC(192)
|
||||||
CallAESIMC(208)
|
CallAESIMC(208)
|
||||||
: : [shed]"r"(GetKeySchedule ()) : "%xmm0", "memory"
|
: : [shed]"r"(GetKeySchedule ()) : "%xmm0", "memory"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
|
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
|
||||||
{
|
{
|
||||||
#ifdef AESNI
|
#ifdef AESNI
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[iv]), %%xmm1 \n"
|
"movups (%[iv]), %%xmm1 \n"
|
||||||
"1: \n"
|
"1: \n"
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
EncryptAES256(sched)
|
EncryptAES256(sched)
|
||||||
"movaps %%xmm0, %%xmm1 \n"
|
"movaps %%xmm0, %%xmm1 \n"
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
"add $16, %[in] \n"
|
"add $16, %[in] \n"
|
||||||
"add $16, %[out] \n"
|
"add $16, %[out] \n"
|
||||||
"dec %[num] \n"
|
"dec %[num] \n"
|
||||||
"jnz 1b \n"
|
"jnz 1b \n"
|
||||||
"movups %%xmm1, (%[iv]) \n"
|
"movups %%xmm1, (%[iv]) \n"
|
||||||
:
|
:
|
||||||
: [iv]"r"(&m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
: [iv]"r"(&m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
||||||
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
||||||
: "%xmm0", "%xmm1", "cc", "memory"
|
: "%xmm0", "%xmm1", "cc", "memory"
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
for (int i = 0; i < numBlocks; i++)
|
for (int i = 0; i < numBlocks; i++)
|
||||||
{
|
{
|
||||||
m_LastBlock ^= in[i];
|
m_LastBlock ^= in[i];
|
||||||
m_ECBEncryption.Encrypt (&m_LastBlock, &m_LastBlock);
|
m_ECBEncryption.Encrypt (&m_LastBlock, &m_LastBlock);
|
||||||
out[i] = m_LastBlock;
|
out[i] = m_LastBlock;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBCEncryption::Encrypt (const uint8_t * in, std::size_t len, uint8_t * out)
|
void CBCEncryption::Encrypt (const uint8_t * in, std::size_t len, uint8_t * out)
|
||||||
{
|
{
|
||||||
// len/16
|
// len/16
|
||||||
int numBlocks = len >> 4;
|
int numBlocks = len >> 4;
|
||||||
if (numBlocks > 0)
|
if (numBlocks > 0)
|
||||||
Encrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out);
|
Encrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out)
|
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out)
|
||||||
{
|
{
|
||||||
#ifdef AESNI
|
#ifdef AESNI
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[iv]), %%xmm1 \n"
|
"movups (%[iv]), %%xmm1 \n"
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
EncryptAES256(sched)
|
EncryptAES256(sched)
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
"movups %%xmm0, (%[iv]) \n"
|
"movups %%xmm0, (%[iv]) \n"
|
||||||
:
|
:
|
||||||
: [iv]"r"(&m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
: [iv]"r"(&m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
||||||
[in]"r"(in), [out]"r"(out)
|
[in]"r"(in), [out]"r"(out)
|
||||||
: "%xmm0", "%xmm1", "memory"
|
: "%xmm0", "%xmm1", "memory"
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
|
Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
|
void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
|
||||||
{
|
{
|
||||||
#ifdef AESNI
|
#ifdef AESNI
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[iv]), %%xmm1 \n"
|
"movups (%[iv]), %%xmm1 \n"
|
||||||
"1: \n"
|
"1: \n"
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
"movaps %%xmm0, %%xmm2 \n"
|
"movaps %%xmm0, %%xmm2 \n"
|
||||||
DecryptAES256(sched)
|
DecryptAES256(sched)
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
"movaps %%xmm2, %%xmm1 \n"
|
"movaps %%xmm2, %%xmm1 \n"
|
||||||
"add $16, %[in] \n"
|
"add $16, %[in] \n"
|
||||||
"add $16, %[out] \n"
|
"add $16, %[out] \n"
|
||||||
"dec %[num] \n"
|
"dec %[num] \n"
|
||||||
"jnz 1b \n"
|
"jnz 1b \n"
|
||||||
"movups %%xmm1, (%[iv]) \n"
|
"movups %%xmm1, (%[iv]) \n"
|
||||||
:
|
:
|
||||||
: [iv]"r"(&m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
: [iv]"r"(&m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
||||||
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
||||||
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
|
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
for (int i = 0; i < numBlocks; i++)
|
for (int i = 0; i < numBlocks; i++)
|
||||||
{
|
{
|
||||||
ChipherBlock tmp = in[i];
|
ChipherBlock tmp = in[i];
|
||||||
m_ECBDecryption.Decrypt (in + i, out + i);
|
m_ECBDecryption.Decrypt (in + i, out + i);
|
||||||
out[i] ^= m_IV;
|
out[i] ^= m_IV;
|
||||||
m_IV = tmp;
|
m_IV = tmp;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBCDecryption::Decrypt (const uint8_t * in, std::size_t len, uint8_t * out)
|
void CBCDecryption::Decrypt (const uint8_t * in, std::size_t len, uint8_t * out)
|
||||||
{
|
{
|
||||||
int numBlocks = len >> 4;
|
int numBlocks = len >> 4;
|
||||||
if (numBlocks > 0)
|
if (numBlocks > 0)
|
||||||
Decrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out);
|
Decrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out)
|
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out)
|
||||||
{
|
{
|
||||||
#ifdef AESNI
|
#ifdef AESNI
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[iv]), %%xmm1 \n"
|
"movups (%[iv]), %%xmm1 \n"
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
"movups %%xmm0, (%[iv]) \n"
|
"movups %%xmm0, (%[iv]) \n"
|
||||||
DecryptAES256(sched)
|
DecryptAES256(sched)
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
:
|
:
|
||||||
: [iv]"r"(&m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
: [iv]"r"(&m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
||||||
[in]"r"(in), [out]"r"(out)
|
[in]"r"(in), [out]"r"(out)
|
||||||
: "%xmm0", "%xmm1", "memory"
|
: "%xmm0", "%xmm1", "memory"
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
|
Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out)
|
void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out)
|
||||||
{
|
{
|
||||||
#ifdef AESNI
|
#ifdef AESNI
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
// encrypt IV
|
// encrypt IV
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
EncryptAES256(sched_iv)
|
EncryptAES256(sched_iv)
|
||||||
"movaps %%xmm0, %%xmm1 \n"
|
"movaps %%xmm0, %%xmm1 \n"
|
||||||
// double IV encryption
|
// double IV encryption
|
||||||
EncryptAES256(sched_iv)
|
EncryptAES256(sched_iv)
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
// encrypt data, IV is xmm1
|
// encrypt data, IV is xmm1
|
||||||
"1: \n"
|
"1: \n"
|
||||||
"add $16, %[in] \n"
|
"add $16, %[in] \n"
|
||||||
"add $16, %[out] \n"
|
"add $16, %[out] \n"
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
EncryptAES256(sched_l)
|
EncryptAES256(sched_l)
|
||||||
"movaps %%xmm0, %%xmm1 \n"
|
"movaps %%xmm0, %%xmm1 \n"
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
"dec %[num] \n"
|
"dec %[num] \n"
|
||||||
"jnz 1b \n"
|
"jnz 1b \n"
|
||||||
:
|
:
|
||||||
: [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.GetKeySchedule ()),
|
: [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.GetKeySchedule ()),
|
||||||
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
|
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
|
||||||
: "%xmm0", "%xmm1", "cc", "memory"
|
: "%xmm0", "%xmm1", "cc", "memory"
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
|
m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
|
||||||
m_LayerEncryption.SetIV (out);
|
m_LayerEncryption.SetIV (out);
|
||||||
m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
|
m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
|
||||||
m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
|
m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out)
|
void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out)
|
||||||
{
|
{
|
||||||
#ifdef AESNI
|
#ifdef AESNI
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
// decrypt IV
|
// decrypt IV
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
DecryptAES256(sched_iv)
|
DecryptAES256(sched_iv)
|
||||||
"movaps %%xmm0, %%xmm1 \n"
|
"movaps %%xmm0, %%xmm1 \n"
|
||||||
// double IV encryption
|
// double IV encryption
|
||||||
DecryptAES256(sched_iv)
|
DecryptAES256(sched_iv)
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
// decrypt data, IV is xmm1
|
// decrypt data, IV is xmm1
|
||||||
"1: \n"
|
"1: \n"
|
||||||
"add $16, %[in] \n"
|
"add $16, %[in] \n"
|
||||||
"add $16, %[out] \n"
|
"add $16, %[out] \n"
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
"movaps %%xmm0, %%xmm2 \n"
|
"movaps %%xmm0, %%xmm2 \n"
|
||||||
DecryptAES256(sched_l)
|
DecryptAES256(sched_l)
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
"movaps %%xmm2, %%xmm1 \n"
|
"movaps %%xmm2, %%xmm1 \n"
|
||||||
"dec %[num] \n"
|
"dec %[num] \n"
|
||||||
"jnz 1b \n"
|
"jnz 1b \n"
|
||||||
:
|
:
|
||||||
: [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.GetKeySchedule ()),
|
: [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.GetKeySchedule ()),
|
||||||
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
|
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
|
||||||
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
|
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
|
m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
|
||||||
m_LayerDecryption.SetIV (out);
|
m_LayerDecryption.SetIV (out);
|
||||||
m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
|
m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
|
||||||
m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
|
m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
318
aes.h
318
aes.h
|
@ -9,215 +9,221 @@
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace crypto
|
namespace crypto
|
||||||
{
|
{
|
||||||
struct ChipherBlock
|
struct ChipherBlock
|
||||||
{
|
{
|
||||||
uint8_t buf[16];
|
uint8_t buf[16];
|
||||||
|
|
||||||
void operator^=(const ChipherBlock& other) // XOR
|
void operator^=(const ChipherBlock& other) // XOR
|
||||||
{
|
{
|
||||||
#if defined(__x86_64__) // for Intel x64
|
#if defined(__x86_64__) // for Intel x64
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[buf]), %%xmm0 \n"
|
"movups (%[buf]), %%xmm0 \n"
|
||||||
"movups (%[other]), %%xmm1 \n"
|
"movups (%[other]), %%xmm1 \n"
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
"movups %%xmm0, (%[buf]) \n"
|
"movups %%xmm0, (%[buf]) \n"
|
||||||
:
|
:
|
||||||
: [buf]"r"(buf), [other]"r"(other.buf)
|
: [buf]"r"(buf), [other]"r"(other.buf)
|
||||||
: "%xmm0", "%xmm1", "memory"
|
: "%xmm0", "%xmm1", "memory"
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
// TODO: implement it better
|
// TODO: implement it better
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
buf[i] ^= other.buf[i];
|
buf[i] ^= other.buf[i];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef i2p::data::Tag<32> AESKey;
|
typedef i2p::data::Tag<32> AESKey;
|
||||||
|
|
||||||
template<size_t sz>
|
template<size_t sz>
|
||||||
class AESAlignedBuffer // 16 bytes alignment
|
class AESAlignedBuffer // 16 bytes alignment
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AESAlignedBuffer ()
|
AESAlignedBuffer ()
|
||||||
{
|
{
|
||||||
m_Buf = m_UnalignedBuffer;
|
m_Buf = m_UnalignedBuffer;
|
||||||
uint8_t rem = ((size_t)m_Buf) & 0x0f;
|
uint8_t rem = ((size_t)m_Buf) & 0x0f;
|
||||||
if (rem)
|
if (rem)
|
||||||
m_Buf += (16 - rem);
|
m_Buf += (16 - rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
operator uint8_t * () { return m_Buf; };
|
operator uint8_t * () { return m_Buf; };
|
||||||
operator const uint8_t * () const { return m_Buf; };
|
operator const uint8_t * () const { return m_Buf; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment
|
uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment
|
||||||
uint8_t * m_Buf;
|
uint8_t * m_Buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef AESNI
|
#ifdef AESNI
|
||||||
class ECBCryptoAESNI
|
class ECBCryptoAESNI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
uint8_t * GetKeySchedule () { return m_KeySchedule; };
|
uint8_t * GetKeySchedule () { return m_KeySchedule; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void ExpandKey (const AESKey& key);
|
void ExpandKey (const AESKey& key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
AESAlignedBuffer<240> m_KeySchedule; // 14 rounds for AES-256, 240 bytes
|
AESAlignedBuffer<240> m_KeySchedule; // 14 rounds for AES-256, 240 bytes
|
||||||
};
|
};
|
||||||
|
|
||||||
class ECBEncryptionAESNI: public ECBCryptoAESNI
|
class ECBEncryptionAESNI: public ECBCryptoAESNI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void SetKey (const AESKey& key) { ExpandKey (key); };
|
void SetKey (const AESKey& key) { ExpandKey (key); };
|
||||||
void Encrypt (const ChipherBlock * in, ChipherBlock * out);
|
void Encrypt (const ChipherBlock * in, ChipherBlock * out);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ECBDecryptionAESNI: public ECBCryptoAESNI
|
class ECBDecryptionAESNI: public ECBCryptoAESNI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void SetKey (const AESKey& key);
|
void SetKey (const AESKey& key);
|
||||||
void Decrypt (const ChipherBlock * in, ChipherBlock * out);
|
void Decrypt (const ChipherBlock * in, ChipherBlock * out);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ECBEncryptionAESNI ECBEncryption;
|
typedef ECBEncryptionAESNI ECBEncryption;
|
||||||
typedef ECBDecryptionAESNI ECBDecryption;
|
typedef ECBDecryptionAESNI ECBDecryption;
|
||||||
|
|
||||||
#else // use crypto++
|
#else // use crypto++
|
||||||
|
|
||||||
class ECBEncryption
|
class ECBEncryption
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void SetKey (const AESKey& key)
|
void SetKey (const AESKey& key)
|
||||||
{
|
{
|
||||||
m_Encryption.SetKey (key, 32);
|
m_Encryption.SetKey (key, 32);
|
||||||
}
|
}
|
||||||
void Encrypt (const ChipherBlock * in, ChipherBlock * out)
|
void Encrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||||
{
|
{
|
||||||
m_Encryption.ProcessData (out->buf, in->buf, 16);
|
m_Encryption.ProcessData (out->buf, in->buf, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption m_Encryption;
|
CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption m_Encryption;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ECBDecryption
|
class ECBDecryption
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void SetKey (const AESKey& key)
|
void SetKey (const AESKey& key)
|
||||||
{
|
{
|
||||||
m_Decryption.SetKey (key, 32);
|
m_Decryption.SetKey (key, 32);
|
||||||
}
|
}
|
||||||
void Decrypt (const ChipherBlock * in, ChipherBlock * out)
|
void Decrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||||
{
|
{
|
||||||
m_Decryption.ProcessData (out->buf, in->buf, 16);
|
m_Decryption.ProcessData (out->buf, in->buf, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption m_Decryption;
|
CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption m_Decryption;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class CBCEncryption
|
class CBCEncryption
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CBCEncryption () { memset (m_LastBlock.buf, 0, 16); };
|
CBCEncryption () { memset (m_LastBlock.buf, 0, 16); };
|
||||||
|
CBCEncryption(const AESKey& key, const uint8_t* iv)
|
||||||
|
: CBCEncryption()
|
||||||
|
{
|
||||||
|
SetKey(key);
|
||||||
|
SetIV(iv);
|
||||||
|
};
|
||||||
|
|
||||||
void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
|
void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
|
||||||
void SetIV (const uint8_t * iv) { memcpy (m_LastBlock.buf, iv, 16); }; // 16 bytes
|
void SetIV (const uint8_t * iv) { memcpy (m_LastBlock.buf, iv, 16); }; // 16 bytes
|
||||||
|
|
||||||
void Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
|
void Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
|
||||||
void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out);
|
void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out);
|
||||||
void Encrypt (const uint8_t * in, uint8_t * out); // one block
|
void Encrypt (const uint8_t * in, uint8_t * out); // one block
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ChipherBlock m_LastBlock;
|
ChipherBlock m_LastBlock;
|
||||||
|
|
||||||
ECBEncryption m_ECBEncryption;
|
ECBEncryption m_ECBEncryption;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CBCDecryption
|
class CBCDecryption
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CBCDecryption () { memset (m_IV.buf, 0, 16); };
|
CBCDecryption () { memset (m_IV.buf, 0, 16); };
|
||||||
|
|
||||||
void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
|
void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
|
||||||
void SetIV (const uint8_t * iv) { memcpy (m_IV.buf, iv, 16); }; // 16 bytes
|
void SetIV (const uint8_t * iv) { memcpy (m_IV.buf, iv, 16); }; // 16 bytes
|
||||||
|
|
||||||
void Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
|
void Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
|
||||||
void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out);
|
void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out);
|
||||||
void Decrypt (const uint8_t * in, uint8_t * out); // one block
|
void Decrypt (const uint8_t * in, uint8_t * out); // one block
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ChipherBlock m_IV;
|
ChipherBlock m_IV;
|
||||||
ECBDecryption m_ECBDecryption;
|
ECBDecryption m_ECBDecryption;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TunnelEncryption // with double IV encryption
|
class TunnelEncryption // with double IV encryption
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
|
void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
|
||||||
{
|
{
|
||||||
m_LayerEncryption.SetKey (layerKey);
|
m_LayerEncryption.SetKey (layerKey);
|
||||||
m_IVEncryption.SetKey (ivKey);
|
m_IVEncryption.SetKey (ivKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Encrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
|
void Encrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ECBEncryption m_IVEncryption;
|
ECBEncryption m_IVEncryption;
|
||||||
#ifdef AESNI
|
#ifdef AESNI
|
||||||
ECBEncryption m_LayerEncryption;
|
ECBEncryption m_LayerEncryption;
|
||||||
#else
|
#else
|
||||||
CBCEncryption m_LayerEncryption;
|
CBCEncryption m_LayerEncryption;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class TunnelDecryption // with double IV encryption
|
class TunnelDecryption // with double IV encryption
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
|
void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
|
||||||
{
|
{
|
||||||
m_LayerDecryption.SetKey (layerKey);
|
m_LayerDecryption.SetKey (layerKey);
|
||||||
m_IVDecryption.SetKey (ivKey);
|
m_IVDecryption.SetKey (ivKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Decrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
|
void Decrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ECBDecryption m_IVDecryption;
|
ECBDecryption m_IVDecryption;
|
||||||
#ifdef AESNI
|
#ifdef AESNI
|
||||||
ECBDecryption m_LayerDecryption;
|
ECBDecryption m_LayerDecryption;
|
||||||
#else
|
#else
|
||||||
CBCDecryption m_LayerDecryption;
|
CBCDecryption m_LayerDecryption;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
168
api.cpp
168
api.cpp
|
@ -14,99 +14,99 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace api
|
namespace api
|
||||||
{
|
{
|
||||||
void InitI2P (int argc, char* argv[], const char * appName)
|
void InitI2P (int argc, char* argv[], const char * appName)
|
||||||
{
|
{
|
||||||
i2p::util::filesystem::SetAppName (appName);
|
i2p::util::filesystem::SetAppName (appName);
|
||||||
i2p::util::config::OptionParser(argc, argv);
|
i2p::util::config::OptionParser(argc, argv);
|
||||||
i2p::context.Init ();
|
i2p::context.Init ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartI2P (std::ostream * logStream)
|
void StartI2P (std::ostream * logStream)
|
||||||
{
|
{
|
||||||
if (logStream)
|
if (logStream)
|
||||||
StartLog (logStream);
|
StartLog (logStream);
|
||||||
else
|
else
|
||||||
StartLog (i2p::util::filesystem::GetAppName () + ".log");
|
StartLog (i2p::util::filesystem::GetAppName () + ".log");
|
||||||
i2p::data::netdb.Start();
|
i2p::data::netdb.Start();
|
||||||
LogPrint("NetDB started");
|
LogPrint("NetDB started");
|
||||||
i2p::transport::transports.Start();
|
i2p::transport::transports.Start();
|
||||||
LogPrint("Transports started");
|
LogPrint("Transports started");
|
||||||
i2p::tunnel::tunnels.Start();
|
i2p::tunnel::tunnels.Start();
|
||||||
LogPrint("Tunnels started");
|
LogPrint("Tunnels started");
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopI2P ()
|
void StopI2P ()
|
||||||
{
|
{
|
||||||
LogPrint("Shutdown started.");
|
LogPrint("Shutdown started.");
|
||||||
i2p::tunnel::tunnels.Stop();
|
i2p::tunnel::tunnels.Stop();
|
||||||
LogPrint("Tunnels stopped");
|
LogPrint("Tunnels stopped");
|
||||||
i2p::transport::transports.Stop();
|
i2p::transport::transports.Stop();
|
||||||
LogPrint("Transports stopped");
|
LogPrint("Transports stopped");
|
||||||
i2p::data::netdb.Stop();
|
i2p::data::netdb.Stop();
|
||||||
LogPrint("NetDB stopped");
|
LogPrint("NetDB stopped");
|
||||||
StopLog ();
|
StopLog ();
|
||||||
}
|
}
|
||||||
|
|
||||||
i2p::client::ClientDestination * CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
|
i2p::client::ClientDestination * CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
|
||||||
const std::map<std::string, std::string> * params)
|
const std::map<std::string, std::string> * params)
|
||||||
{
|
{
|
||||||
auto localDestination = new i2p::client::ClientDestination (keys, isPublic, params);
|
auto localDestination = new i2p::client::ClientDestination (keys, isPublic, params);
|
||||||
localDestination->Start ();
|
localDestination->Start ();
|
||||||
return localDestination;
|
return localDestination;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2p::client::ClientDestination * CreateLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
|
i2p::client::ClientDestination * CreateLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
|
||||||
const std::map<std::string, std::string> * params)
|
const std::map<std::string, std::string> * params)
|
||||||
{
|
{
|
||||||
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
||||||
auto localDestination = new i2p::client::ClientDestination (keys, isPublic, params);
|
auto localDestination = new i2p::client::ClientDestination (keys, isPublic, params);
|
||||||
localDestination->Start ();
|
localDestination->Start ();
|
||||||
return localDestination;
|
return localDestination;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyLocalDestination (i2p::client::ClientDestination * dest)
|
void DestroyLocalDestination (i2p::client::ClientDestination * dest)
|
||||||
{
|
{
|
||||||
if (dest)
|
if (dest)
|
||||||
{
|
{
|
||||||
dest->Stop ();
|
dest->Stop ();
|
||||||
delete dest;
|
delete dest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestLeaseSet (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote)
|
void RequestLeaseSet (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote)
|
||||||
{
|
{
|
||||||
if (dest)
|
if (dest)
|
||||||
dest->RequestDestination (remote);
|
dest->RequestDestination (remote);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<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)
|
||||||
{
|
{
|
||||||
if (!dest) return nullptr;
|
if (!dest) return nullptr;
|
||||||
auto leaseSet = dest->FindLeaseSet (remote);
|
auto leaseSet = dest->FindLeaseSet (remote);
|
||||||
if (leaseSet)
|
if (leaseSet)
|
||||||
{
|
{
|
||||||
auto stream = dest->CreateStream (leaseSet);
|
auto stream = dest->CreateStream (leaseSet);
|
||||||
stream->Send (nullptr, 0); // connect
|
stream->Send (nullptr, 0); // connect
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RequestLeaseSet (dest, remote);
|
RequestLeaseSet (dest, remote);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AcceptStream (i2p::client::ClientDestination * dest, const i2p::stream::StreamingDestination::Acceptor& acceptor)
|
void AcceptStream (i2p::client::ClientDestination * dest, const i2p::stream::StreamingDestination::Acceptor& acceptor)
|
||||||
{
|
{
|
||||||
if (dest)
|
if (dest)
|
||||||
dest->AcceptStreams (acceptor);
|
dest->AcceptStreams (acceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyStream (std::shared_ptr<i2p::stream::Stream> stream)
|
void DestroyStream (std::shared_ptr<i2p::stream::Stream> stream)
|
||||||
{
|
{
|
||||||
if (stream)
|
if (stream)
|
||||||
stream->Close ();
|
stream->Close ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
32
api.h
32
api.h
|
@ -11,24 +11,24 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace api
|
namespace api
|
||||||
{
|
{
|
||||||
// initialization start and stop
|
// initialization start and stop
|
||||||
void InitI2P (int argc, char* argv[], const char * appName);
|
void InitI2P (int argc, char* argv[], const char * appName);
|
||||||
void StartI2P (std::ostream * logStream = nullptr);
|
void StartI2P (std::ostream * logStream = nullptr);
|
||||||
// write system log to logStream, if not specified to <appName>.log in application's folder
|
// write system log to logStream, if not specified to <appName>.log in application's folder
|
||||||
void StopI2P ();
|
void StopI2P ();
|
||||||
|
|
||||||
// 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,
|
||||||
const std::map<std::string, std::string> * params = nullptr);
|
const std::map<std::string, std::string> * params = nullptr);
|
||||||
i2p::client::ClientDestination * CreateLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256,
|
i2p::client::ClientDestination * CreateLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256,
|
||||||
const std::map<std::string, std::string> * params = nullptr); // transient destinations usually not published
|
const std::map<std::string, std::string> * params = nullptr); // transient destinations usually not published
|
||||||
void DestroyLocalDestination (i2p::client::ClientDestination * dest);
|
void DestroyLocalDestination (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);
|
||||||
std::shared_ptr<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 (std::shared_ptr<i2p::stream::Stream> stream);
|
void DestroyStream (std::shared_ptr<i2p::stream::Stream> stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
476
base64.cpp
476
base64.cpp
|
@ -6,264 +6,264 @@ namespace i2p
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
|
|
||||||
static void iT64Build(void);
|
static void iT64Build(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* BASE64 Substitution Table
|
* BASE64 Substitution Table
|
||||||
* -------------------------
|
* -------------------------
|
||||||
*
|
*
|
||||||
* Direct Substitution Table
|
* Direct Substitution Table
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static char T64[64] = {
|
static char T64[64] = {
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||||
'4', '5', '6', '7', '8', '9', '-', '~'
|
'4', '5', '6', '7', '8', '9', '-', '~'
|
||||||
};
|
};
|
||||||
|
|
||||||
const char * GetBase64SubstitutionTable ()
|
const char * GetBase64SubstitutionTable ()
|
||||||
{
|
{
|
||||||
return T64;
|
return T64;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reverse Substitution Table (built in run time)
|
* Reverse Substitution Table (built in run time)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static char iT64[256];
|
static char iT64[256];
|
||||||
static int isFirstTime = 1;
|
static int isFirstTime = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Padding
|
* Padding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static char P64 = '=';
|
static char P64 = '=';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* ByteStreamToBase64
|
* ByteStreamToBase64
|
||||||
* ------------------
|
* ------------------
|
||||||
*
|
*
|
||||||
* Converts binary encoded data to BASE64 format.
|
* Converts binary encoded data to BASE64 format.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
size_t /* Number of bytes in the encoded buffer */
|
size_t /* Number of bytes in the encoded buffer */
|
||||||
ByteStreamToBase64 (
|
ByteStreamToBase64 (
|
||||||
const uint8_t * InBuffer, /* Input buffer, binary data */
|
const uint8_t * InBuffer, /* Input buffer, binary data */
|
||||||
size_t InCount, /* Number of bytes in the input buffer */
|
size_t InCount, /* Number of bytes in the input buffer */
|
||||||
char * OutBuffer, /* output buffer */
|
char * OutBuffer, /* output buffer */
|
||||||
size_t len /* length of output buffer */
|
size_t len /* length of output buffer */
|
||||||
)
|
)
|
||||||
|
|
||||||
{
|
{
|
||||||
unsigned char * ps;
|
unsigned char * ps;
|
||||||
unsigned char * pd;
|
unsigned char * pd;
|
||||||
unsigned char acc_1;
|
unsigned char acc_1;
|
||||||
unsigned char acc_2;
|
unsigned char acc_2;
|
||||||
int i;
|
int i;
|
||||||
int n;
|
int n;
|
||||||
int m;
|
int m;
|
||||||
size_t outCount;
|
size_t outCount;
|
||||||
|
|
||||||
ps = (unsigned char *)InBuffer;
|
ps = (unsigned char *)InBuffer;
|
||||||
n = InCount/3;
|
n = InCount/3;
|
||||||
m = InCount%3;
|
m = InCount%3;
|
||||||
if (!m)
|
if (!m)
|
||||||
outCount = 4*n;
|
outCount = 4*n;
|
||||||
else
|
else
|
||||||
outCount = 4*(n+1);
|
outCount = 4*(n+1);
|
||||||
if (outCount > len) return 0;
|
if (outCount > len) return 0;
|
||||||
pd = (unsigned char *)OutBuffer;
|
pd = (unsigned char *)OutBuffer;
|
||||||
for ( i = 0; i<n; i++ ){
|
for ( i = 0; i<n; i++ ){
|
||||||
acc_1 = *ps++;
|
acc_1 = *ps++;
|
||||||
acc_2 = (acc_1<<4)&0x30;
|
acc_2 = (acc_1<<4)&0x30;
|
||||||
acc_1 >>= 2; /* base64 digit #1 */
|
acc_1 >>= 2; /* base64 digit #1 */
|
||||||
*pd++ = T64[acc_1];
|
*pd++ = T64[acc_1];
|
||||||
acc_1 = *ps++;
|
acc_1 = *ps++;
|
||||||
acc_2 |= acc_1 >> 4; /* base64 digit #2 */
|
acc_2 |= acc_1 >> 4; /* base64 digit #2 */
|
||||||
*pd++ = T64[acc_2];
|
*pd++ = T64[acc_2];
|
||||||
acc_1 &= 0x0f;
|
acc_1 &= 0x0f;
|
||||||
acc_1 <<=2;
|
acc_1 <<=2;
|
||||||
acc_2 = *ps++;
|
acc_2 = *ps++;
|
||||||
acc_1 |= acc_2>>6; /* base64 digit #3 */
|
acc_1 |= acc_2>>6; /* base64 digit #3 */
|
||||||
*pd++ = T64[acc_1];
|
*pd++ = T64[acc_1];
|
||||||
acc_2 &= 0x3f; /* base64 digit #4 */
|
acc_2 &= 0x3f; /* base64 digit #4 */
|
||||||
*pd++ = T64[acc_2];
|
*pd++ = T64[acc_2];
|
||||||
}
|
}
|
||||||
if ( m == 1 ){
|
if ( m == 1 ){
|
||||||
acc_1 = *ps++;
|
acc_1 = *ps++;
|
||||||
acc_2 = (acc_1<<4)&0x3f; /* base64 digit #2 */
|
acc_2 = (acc_1<<4)&0x3f; /* base64 digit #2 */
|
||||||
acc_1 >>= 2; /* base64 digit #1 */
|
acc_1 >>= 2; /* base64 digit #1 */
|
||||||
*pd++ = T64[acc_1];
|
*pd++ = T64[acc_1];
|
||||||
*pd++ = T64[acc_2];
|
*pd++ = T64[acc_2];
|
||||||
*pd++ = P64;
|
*pd++ = P64;
|
||||||
*pd++ = P64;
|
*pd++ = P64;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if ( m == 2 ){
|
else if ( m == 2 ){
|
||||||
acc_1 = *ps++;
|
acc_1 = *ps++;
|
||||||
acc_2 = (acc_1<<4)&0x3f;
|
acc_2 = (acc_1<<4)&0x3f;
|
||||||
acc_1 >>= 2; /* base64 digit #1 */
|
acc_1 >>= 2; /* base64 digit #1 */
|
||||||
*pd++ = T64[acc_1];
|
*pd++ = T64[acc_1];
|
||||||
acc_1 = *ps++;
|
acc_1 = *ps++;
|
||||||
acc_2 |= acc_1 >> 4; /* base64 digit #2 */
|
acc_2 |= acc_1 >> 4; /* base64 digit #2 */
|
||||||
*pd++ = T64[acc_2];
|
*pd++ = T64[acc_2];
|
||||||
acc_1 &= 0x0f;
|
acc_1 &= 0x0f;
|
||||||
acc_1 <<=2; /* base64 digit #3 */
|
acc_1 <<=2; /* base64 digit #3 */
|
||||||
*pd++ = T64[acc_1];
|
*pd++ = T64[acc_1];
|
||||||
*pd++ = P64;
|
*pd++ = P64;
|
||||||
}
|
}
|
||||||
|
|
||||||
return outCount;
|
return outCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Base64ToByteStream
|
* Base64ToByteStream
|
||||||
* ------------------
|
* ------------------
|
||||||
*
|
*
|
||||||
* Converts BASE64 encoded data to binary format. If input buffer is
|
* Converts BASE64 encoded data to binary format. If input buffer is
|
||||||
* not properly padded, buffer of negative length is returned
|
* not properly padded, buffer of negative length is returned
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
size_t /* Number of output bytes */
|
size_t /* Number of output bytes */
|
||||||
Base64ToByteStream (
|
Base64ToByteStream (
|
||||||
const char * InBuffer, /* BASE64 encoded buffer */
|
const char * InBuffer, /* BASE64 encoded buffer */
|
||||||
size_t InCount, /* Number of input bytes */
|
size_t InCount, /* Number of input bytes */
|
||||||
uint8_t * OutBuffer, /* output buffer length */
|
uint8_t * OutBuffer, /* output buffer length */
|
||||||
size_t len /* length of output buffer */
|
size_t len /* length of output buffer */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
unsigned char * ps;
|
unsigned char * ps;
|
||||||
unsigned char * pd;
|
unsigned char * pd;
|
||||||
unsigned char acc_1;
|
unsigned char acc_1;
|
||||||
unsigned char acc_2;
|
unsigned char acc_2;
|
||||||
int i;
|
int i;
|
||||||
int n;
|
int n;
|
||||||
int m;
|
int m;
|
||||||
size_t outCount;
|
size_t outCount;
|
||||||
|
|
||||||
if (isFirstTime) iT64Build();
|
if (isFirstTime) iT64Build();
|
||||||
n = InCount/4;
|
n = InCount/4;
|
||||||
m = InCount%4;
|
m = InCount%4;
|
||||||
if (!m)
|
if (!m)
|
||||||
outCount = 3*n;
|
outCount = 3*n;
|
||||||
else {
|
else {
|
||||||
outCount = 0;
|
outCount = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ps = (unsigned char *)(InBuffer + InCount - 1);
|
ps = (unsigned char *)(InBuffer + InCount - 1);
|
||||||
while ( *ps-- == P64 ) outCount--;
|
while ( *ps-- == P64 ) outCount--;
|
||||||
ps = (unsigned char *)InBuffer;
|
ps = (unsigned char *)InBuffer;
|
||||||
|
|
||||||
if (outCount > len) return -1;
|
if (outCount > len) return -1;
|
||||||
pd = OutBuffer;
|
pd = OutBuffer;
|
||||||
auto endOfOutBuffer = OutBuffer + outCount;
|
auto endOfOutBuffer = OutBuffer + outCount;
|
||||||
for ( i = 0; i < n; i++ ){
|
for ( i = 0; i < n; i++ ){
|
||||||
acc_1 = iT64[*ps++];
|
acc_1 = iT64[*ps++];
|
||||||
acc_2 = iT64[*ps++];
|
acc_2 = iT64[*ps++];
|
||||||
acc_1 <<= 2;
|
acc_1 <<= 2;
|
||||||
acc_1 |= acc_2>>4;
|
acc_1 |= acc_2>>4;
|
||||||
*pd++ = acc_1;
|
*pd++ = acc_1;
|
||||||
if (pd >= endOfOutBuffer) break;
|
if (pd >= endOfOutBuffer) break;
|
||||||
|
|
||||||
acc_2 <<= 4;
|
acc_2 <<= 4;
|
||||||
acc_1 = iT64[*ps++];
|
acc_1 = iT64[*ps++];
|
||||||
acc_2 |= acc_1 >> 2;
|
acc_2 |= acc_1 >> 2;
|
||||||
*pd++ = acc_2;
|
*pd++ = acc_2;
|
||||||
if (pd >= endOfOutBuffer) break;
|
if (pd >= endOfOutBuffer) break;
|
||||||
|
|
||||||
acc_2 = iT64[*ps++];
|
acc_2 = iT64[*ps++];
|
||||||
acc_2 |= acc_1 << 6;
|
acc_2 |= acc_1 << 6;
|
||||||
*pd++ = acc_2;
|
*pd++ = acc_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return outCount;
|
return outCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* iT64
|
* iT64
|
||||||
* ----
|
* ----
|
||||||
* Reverse table builder. P64 character is replaced with 0
|
* Reverse table builder. P64 character is replaced with 0
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void iT64Build()
|
static void iT64Build()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
isFirstTime = 0;
|
isFirstTime = 0;
|
||||||
for ( i=0; i<256; i++ ) iT64[i] = -1;
|
for ( i=0; i<256; i++ ) iT64[i] = -1;
|
||||||
for ( i=0; i<64; i++ ) iT64[(int)T64[i]] = i;
|
for ( i=0; i<64; i++ ) iT64[(int)T64[i]] = i;
|
||||||
iT64[(int)P64] = 0;
|
iT64[(int)P64] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen)
|
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen)
|
||||||
{
|
{
|
||||||
int tmp = 0, bits = 0;
|
int tmp = 0, bits = 0;
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
for (size_t i = 0; i < len; i++)
|
for (size_t i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
char ch = inBuf[i];
|
char ch = inBuf[i];
|
||||||
if (ch >= '2' && ch <= '7') // digit
|
if (ch >= '2' && ch <= '7') // digit
|
||||||
ch = (ch - '2') + 26; // 26 means a-z
|
ch = (ch - '2') + 26; // 26 means a-z
|
||||||
else if (ch >= 'a' && ch <= 'z')
|
else if (ch >= 'a' && ch <= 'z')
|
||||||
ch = ch - 'a'; // a = 0
|
ch = ch - 'a'; // a = 0
|
||||||
else
|
else
|
||||||
return 0; // unexpected character
|
return 0; // unexpected character
|
||||||
|
|
||||||
tmp |= ch;
|
tmp |= ch;
|
||||||
bits += 5;
|
bits += 5;
|
||||||
if (bits >= 8)
|
if (bits >= 8)
|
||||||
{
|
{
|
||||||
if (ret >= outLen) return ret;
|
if (ret >= outLen) return ret;
|
||||||
outBuf[ret] = tmp >> (bits - 8);
|
outBuf[ret] = tmp >> (bits - 8);
|
||||||
bits -= 8;
|
bits -= 8;
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
tmp <<= 5;
|
tmp <<= 5;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen)
|
size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen)
|
||||||
{
|
{
|
||||||
size_t ret = 0, pos = 1;
|
size_t ret = 0, pos = 1;
|
||||||
int bits = 8, tmp = inBuf[0];
|
int bits = 8, tmp = inBuf[0];
|
||||||
while (ret < outLen && (bits > 0 || pos < len))
|
while (ret < outLen && (bits > 0 || pos < len))
|
||||||
{
|
{
|
||||||
if (bits < 5)
|
if (bits < 5)
|
||||||
{
|
{
|
||||||
if (pos < len)
|
if (pos < len)
|
||||||
{
|
{
|
||||||
tmp <<= 8;
|
tmp <<= 8;
|
||||||
tmp |= inBuf[pos] & 0xFF;
|
tmp |= inBuf[pos] & 0xFF;
|
||||||
pos++;
|
pos++;
|
||||||
bits += 8;
|
bits += 8;
|
||||||
}
|
}
|
||||||
else // last byte
|
else // last byte
|
||||||
{
|
{
|
||||||
tmp <<= (5 - bits);
|
tmp <<= (5 - bits);
|
||||||
bits = 5;
|
bits = 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bits -= 5;
|
bits -= 5;
|
||||||
int ind = (tmp >> bits) & 0x1F;
|
int ind = (tmp >> bits) & 0x1F;
|
||||||
outBuf[ret] = (ind < 26) ? (ind + 'a') : ((ind - 26) + '2');
|
outBuf[ret] = (ind < 26) ? (ind + 'a') : ((ind - 26) + '2');
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
base64.h
12
base64.h
|
@ -9,12 +9,12 @@ namespace i2p
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
|
|
||||||
size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len);
|
size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len);
|
||||||
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
|
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
|
||||||
const char * GetBase64SubstitutionTable ();
|
const char * GetBase64SubstitutionTable ();
|
||||||
|
|
||||||
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
|
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
|
||||||
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
|
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,3 +23,6 @@ DAEMON_SRC = $(COMMON_SRC) \
|
||||||
|
|
||||||
LIB_SRC := $(COMMON_SRC) \
|
LIB_SRC := $(COMMON_SRC) \
|
||||||
api.cpp
|
api.cpp
|
||||||
|
|
||||||
|
TESTS_SRC := $(COMMON_SRC) \
|
||||||
|
tests/Utility.cpp tests/Identity.cpp
|
||||||
|
|
85
hmac.h
85
hmac.h
|
@ -11,51 +11,50 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace crypto
|
namespace crypto
|
||||||
{
|
{
|
||||||
const uint64_t IPAD = 0x3636363636363636;
|
const uint64_t IPAD = 0x3636363636363636;
|
||||||
const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C;
|
const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C;
|
||||||
|
|
||||||
typedef i2p::data::Tag<32> MACKey;
|
typedef i2p::data::Tag<32> MACKey;
|
||||||
|
|
||||||
inline void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest)
|
inline void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest)
|
||||||
// key is 32 bytes
|
// key is 32 bytes
|
||||||
// digest is 16 bytes
|
// digest is 16 bytes
|
||||||
// block size is 64 bytes
|
// block size is 64 bytes
|
||||||
{
|
{
|
||||||
uint64_t buf[256];
|
uint64_t buf[256];
|
||||||
// ikeypad
|
// ikeypad
|
||||||
buf[0] = key.GetLL ()[0] ^ IPAD;
|
buf[0] = key.GetLL ()[0] ^ IPAD;
|
||||||
buf[1] = key.GetLL ()[1] ^ IPAD;
|
buf[1] = key.GetLL ()[1] ^ IPAD;
|
||||||
buf[2] = key.GetLL ()[2] ^ IPAD;
|
buf[2] = key.GetLL ()[2] ^ IPAD;
|
||||||
buf[3] = key.GetLL ()[3] ^ IPAD;
|
buf[3] = key.GetLL ()[3] ^ IPAD;
|
||||||
buf[4] = IPAD;
|
buf[4] = IPAD;
|
||||||
buf[5] = IPAD;
|
buf[5] = IPAD;
|
||||||
buf[6] = IPAD;
|
buf[6] = IPAD;
|
||||||
buf[7] = IPAD;
|
buf[7] = IPAD;
|
||||||
// concatenate with msg
|
// concatenate with msg
|
||||||
memcpy (buf + 8, msg, len);
|
memcpy (buf + 8, msg, len);
|
||||||
// calculate first hash
|
// calculate first hash
|
||||||
uint8_t hash[16]; // MD5
|
uint8_t hash[16]; // MD5
|
||||||
CryptoPP::Weak1::MD5().CalculateDigest (hash, (uint8_t *)buf, len + 64);
|
CryptoPP::Weak1::MD5().CalculateDigest (hash, (uint8_t *)buf, len + 64);
|
||||||
|
|
||||||
// okeypad
|
// okeypad
|
||||||
buf[0] = key.GetLL ()[0] ^ OPAD;
|
buf[0] = key.GetLL ()[0] ^ OPAD;
|
||||||
buf[1] = key.GetLL ()[1] ^ OPAD;
|
buf[1] = key.GetLL ()[1] ^ OPAD;
|
||||||
buf[2] = key.GetLL ()[2] ^ OPAD;
|
buf[2] = key.GetLL ()[2] ^ OPAD;
|
||||||
buf[3] = key.GetLL ()[3] ^ OPAD;
|
buf[3] = key.GetLL ()[3] ^ OPAD;
|
||||||
buf[4] = OPAD;
|
buf[4] = OPAD;
|
||||||
buf[5] = OPAD;
|
buf[5] = OPAD;
|
||||||
buf[6] = OPAD;
|
buf[6] = OPAD;
|
||||||
buf[7] = OPAD;
|
buf[7] = OPAD;
|
||||||
// copy first hash after okeypad
|
// copy first hash after okeypad
|
||||||
memcpy (buf + 8, hash, 16);
|
memcpy (buf + 8, hash, 16);
|
||||||
// fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
|
// fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
|
||||||
memset (buf + 10, 0, 16);
|
memset (buf + 10, 0, 16);
|
||||||
|
|
||||||
// calculate digest
|
// calculate digest
|
||||||
CryptoPP::Weak1::MD5().CalculateDigest (digest, (uint8_t *)buf, 96);
|
CryptoPP::Weak1::MD5().CalculateDigest (digest, (uint8_t *)buf, 96);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue