mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-13 04:46:38 +01:00
Tabs -> spaces (yes this breaks compatiblity with upstream)
This commit is contained in:
parent
5d78e2f5e4
commit
4412dd198d
96 changed files with 22253 additions and 22254 deletions
1000
AddressBook.cpp
1000
AddressBook.cpp
File diff suppressed because it is too large
Load diff
124
AddressBook.h
124
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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
330
BOB.h
330
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
100
ClientContext.h
100
ClientContext.h
|
@ -17,69 +17,69 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
116
CryptoConst.cpp
116
CryptoConst.cpp
|
@ -5,68 +5,68 @@ 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,31 +7,31 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
198
Daemon.cpp
198
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
90
Daemon.h
90
Daemon.h
|
@ -9,65 +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:
|
||||||
DeamonLinux() = default;
|
DaemonLinux() = default;
|
||||||
|
|
||||||
static DaemonLinux& Instance()
|
static DaemonLinux& Instance()
|
||||||
{
|
{
|
||||||
static DaemonLinux instance;
|
static DaemonLinux instance;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool start();
|
virtual bool start();
|
||||||
virtual bool stop();
|
virtual bool stop();
|
||||||
private:
|
private:
|
||||||
std::string pidfile;
|
std::string pidfile;
|
||||||
int pidFilehandle;
|
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
|
||||||
|
|
128
DaemonWin32.cpp
128
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
|
246
Datagram.cpp
246
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
48
Datagram.h
48
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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1222
Destination.cpp
1222
Destination.cpp
File diff suppressed because it is too large
Load diff
210
Destination.h
210
Destination.h
|
@ -22,134 +22,134 @@ 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 (); };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
114
ElGamal.h
114
ElGamal.h
|
@ -14,73 +14,73 @@ 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1128
Garlic.cpp
1128
Garlic.cpp
File diff suppressed because it is too large
Load diff
224
Garlic.h
224
Garlic.h
|
@ -20,149 +20,149 @@ 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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
512
HTTPProxy.cpp
512
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2042
HTTPServer.cpp
2042
HTTPServer.cpp
File diff suppressed because it is too large
Load diff
186
HTTPServer.h
186
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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1126
I2NPProtocol.cpp
1126
I2NPProtocol.cpp
File diff suppressed because it is too large
Load diff
392
I2NPProtocol.h
392
I2NPProtocol.h
|
@ -13,240 +13,240 @@
|
||||||
|
|
||||||
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;
|
||||||
maxLen = other.maxLen;
|
maxLen = other.maxLen;
|
||||||
return *this;
|
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
|
||||||
|
|
672
I2PControl.cpp
672
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
204
I2PControl.h
204
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
118
I2PService.cpp
118
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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
706
I2PTunnel.cpp
706
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 ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
188
I2PTunnel.h
188
I2PTunnel.h
|
@ -16,137 +16,137 @@ 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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1006
Identity.cpp
1006
Identity.cpp
File diff suppressed because it is too large
Load diff
402
Identity.h
402
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);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
258
LeaseSet.cpp
258
LeaseSet.cpp
|
@ -14,144 +14,144 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
88
LeaseSet.h
88
LeaseSet.h
|
@ -11,63 +11,63 @@ 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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
62
Log.cpp
62
Log.cpp
|
@ -5,58 +5,58 @@ Log * g_Log = nullptr;
|
||||||
|
|
||||||
static const char * g_LogLevelStr[eNumLogLevels] =
|
static const char * g_LogLevelStr[eNumLogLevels] =
|
||||||
{
|
{
|
||||||
"error", // eLogError
|
"error", // eLogError
|
||||||
"warn", // eLogWarning
|
"warn", // eLogWarning
|
||||||
"info", // eLogInfo
|
"info", // eLogInfo
|
||||||
"debug" // eLogDebug
|
"debug" // eLogDebug
|
||||||
};
|
};
|
||||||
|
|
||||||
void LogMsg::Process()
|
void LogMsg::Process()
|
||||||
{
|
{
|
||||||
auto& output = (log && log->GetLogStream ()) ? *log->GetLogStream () : std::cerr;
|
auto& output = (log && log->GetLogStream ()) ? *log->GetLogStream () : std::cerr;
|
||||||
if (log)
|
if (log)
|
||||||
output << log->GetTimestamp ();
|
output << log->GetTimestamp ();
|
||||||
else
|
else
|
||||||
output << boost::posix_time::second_clock::local_time().time_of_day ();
|
output << boost::posix_time::second_clock::local_time().time_of_day ();
|
||||||
output << "/" << g_LogLevelStr[level] << " - ";
|
output << "/" << g_LogLevelStr[level] << " - ";
|
||||||
output << s.str();
|
output << s.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& Log::GetTimestamp ()
|
const std::string& Log::GetTimestamp ()
|
||||||
{
|
{
|
||||||
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6)
|
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6)
|
||||||
auto ts = std::chrono::monotonic_clock::now ();
|
auto ts = std::chrono::monotonic_clock::now ();
|
||||||
#else
|
#else
|
||||||
auto ts = std::chrono::steady_clock::now ();
|
auto ts = std::chrono::steady_clock::now ();
|
||||||
#endif
|
#endif
|
||||||
if (ts > m_LastTimestampUpdate + std::chrono::milliseconds (500)) // 0.5 second
|
if (ts > m_LastTimestampUpdate + std::chrono::milliseconds (500)) // 0.5 second
|
||||||
{
|
{
|
||||||
m_LastTimestampUpdate = ts;
|
m_LastTimestampUpdate = ts;
|
||||||
m_Timestamp = boost::posix_time::to_simple_string (boost::posix_time::second_clock::local_time().time_of_day ());
|
m_Timestamp = boost::posix_time::to_simple_string (boost::posix_time::second_clock::local_time().time_of_day ());
|
||||||
}
|
}
|
||||||
return m_Timestamp;
|
return m_Timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
auto logFile = new std::ofstream (fullFilePath, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
|
auto logFile = new std::ofstream (fullFilePath, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
|
||||||
if (logFile->is_open ())
|
if (logFile->is_open ())
|
||||||
{
|
{
|
||||||
SetLogStream (logFile);
|
SetLogStream (logFile);
|
||||||
LogPrint("Logging to file ", fullFilePath, " enabled.");
|
LogPrint("Logging to file ", fullFilePath, " enabled.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
delete logFile;
|
delete logFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::SetLogStream (std::ostream * logStream)
|
void Log::SetLogStream (std::ostream * logStream)
|
||||||
{
|
{
|
||||||
if (m_LogStream) delete m_LogStream;
|
if (m_LogStream) delete m_LogStream;
|
||||||
m_LogStream = logStream;
|
m_LogStream = logStream;
|
||||||
}
|
}
|
||||||
|
|
118
Log.h
118
Log.h
|
@ -11,49 +11,49 @@
|
||||||
|
|
||||||
enum LogLevel
|
enum LogLevel
|
||||||
{
|
{
|
||||||
eLogError = 0,
|
eLogError = 0,
|
||||||
eLogWarning,
|
eLogWarning,
|
||||||
eLogInfo,
|
eLogInfo,
|
||||||
eLogDebug,
|
eLogDebug,
|
||||||
eNumLogLevels
|
eNumLogLevels
|
||||||
};
|
};
|
||||||
|
|
||||||
class Log;
|
class Log;
|
||||||
struct LogMsg
|
struct LogMsg
|
||||||
{
|
{
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
Log * log;
|
Log * log;
|
||||||
LogLevel level;
|
LogLevel level;
|
||||||
|
|
||||||
LogMsg (Log * l = nullptr, LogLevel lv = eLogInfo): log (l), level (lv) {};
|
LogMsg (Log * l = nullptr, LogLevel lv = eLogInfo): log (l), level (lv) {};
|
||||||
|
|
||||||
void Process();
|
void Process();
|
||||||
};
|
};
|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||
std::ostream * m_LogStream;
|
std::ostream * m_LogStream;
|
||||||
std::string m_Timestamp;
|
std::string m_Timestamp;
|
||||||
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) // gcc 4.6
|
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) // gcc 4.6
|
||||||
std::chrono::monotonic_clock::time_point m_LastTimestampUpdate;
|
std::chrono::monotonic_clock::time_point m_LastTimestampUpdate;
|
||||||
#else
|
#else
|
||||||
std::chrono::steady_clock::time_point m_LastTimestampUpdate;
|
std::chrono::steady_clock::time_point m_LastTimestampUpdate;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,69 +61,69 @@ extern Log * g_Log;
|
||||||
|
|
||||||
inline void StartLog (const std::string& fullFilePath)
|
inline void StartLog (const std::string& fullFilePath)
|
||||||
{
|
{
|
||||||
if (!g_Log)
|
if (!g_Log)
|
||||||
{
|
{
|
||||||
auto log = new Log ();
|
auto log = new Log ();
|
||||||
if (fullFilePath.length () > 0)
|
if (fullFilePath.length () > 0)
|
||||||
log->SetLogFile (fullFilePath);
|
log->SetLogFile (fullFilePath);
|
||||||
g_Log = log;
|
g_Log = log;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void StartLog (std::ostream * s)
|
inline void StartLog (std::ostream * s)
|
||||||
{
|
{
|
||||||
if (!g_Log)
|
if (!g_Log)
|
||||||
{
|
{
|
||||||
auto log = new Log ();
|
auto log = new Log ();
|
||||||
if (s)
|
if (s)
|
||||||
log->SetLogStream (s);
|
log->SetLogStream (s);
|
||||||
g_Log = log;
|
g_Log = log;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void StopLog ()
|
inline void StopLog ()
|
||||||
{
|
{
|
||||||
if (g_Log)
|
if (g_Log)
|
||||||
{
|
{
|
||||||
auto log = g_Log;
|
auto log = g_Log;
|
||||||
g_Log = nullptr;
|
g_Log = nullptr;
|
||||||
log->Stop ();
|
log->Stop ();
|
||||||
delete log;
|
delete log;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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>
|
||||||
void LogPrint (LogLevel level, TArgs... args)
|
void LogPrint (LogLevel level, TArgs... args)
|
||||||
{
|
{
|
||||||
LogMsg * msg = new LogMsg (g_Log, level);
|
LogMsg * msg = new LogMsg (g_Log, level);
|
||||||
LogPrint (msg->s, args...);
|
LogPrint (msg->s, args...);
|
||||||
msg->s << std::endl;
|
msg->s << std::endl;
|
||||||
if (g_Log)
|
if (g_Log)
|
||||||
g_Log->Put (msg);
|
g_Log->Put (msg);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
msg->Process ();
|
msg->Process ();
|
||||||
delete msg;
|
delete msg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... TArgs>
|
template<typename... TArgs>
|
||||||
void LogPrint (TArgs... args)
|
void LogPrint (TArgs... args)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, args...);
|
LogPrint (eLogInfo, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
1746
NTCPSession.cpp
1746
NTCPSession.cpp
File diff suppressed because it is too large
Load diff
238
NTCPSession.h
238
NTCPSession.h
|
@ -21,162 +21,162 @@ 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; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
116
NetDb.h
116
NetDb.h
|
@ -23,83 +23,83 @@ 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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
376
Profiling.cpp
376
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
84
Profiling.h
84
Profiling.h
|
@ -9,60 +9,60 @@ 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 ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
256
Queue.h
256
Queue.h
|
@ -12,157 +12,157 @@ 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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1662
Reseed.cpp
1662
Reseed.cpp
File diff suppressed because it is too large
Load diff
102
Reseed.h
102
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
148
RouterContext.h
148
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
|
||||||
|
|
1194
RouterInfo.cpp
1194
RouterInfo.cpp
File diff suppressed because it is too large
Load diff
278
RouterInfo.h
278
RouterInfo.h
|
@ -14,169 +14,169 @@ 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 (const RouterInfo& ) = default;
|
||||||
RouterInfo& operator=(const RouterInfo& ) = default;
|
RouterInfo& operator=(const RouterInfo& ) = default;
|
||||||
RouterInfo (const uint8_t * buf, int len);
|
RouterInfo (const uint8_t * buf, int len);
|
||||||
~RouterInfo ();
|
~RouterInfo ();
|
||||||
|
|
||||||
const IdentityEx& GetRouterIdentity () const { return m_RouterIdentity; };
|
const IdentityEx& GetRouterIdentity () const { return m_RouterIdentity; };
|
||||||
void SetRouterIdentity (const IdentityEx& identity);
|
void SetRouterIdentity (const IdentityEx& identity);
|
||||||
std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); };
|
std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); };
|
||||||
std::string GetIdentHashAbbreviation () const { return GetIdentHash ().ToBase64 ().substr (0, 4); };
|
std::string GetIdentHashAbbreviation () const { return GetIdentHash ().ToBase64 ().substr (0, 4); };
|
||||||
uint64_t GetTimestamp () const { return m_Timestamp; };
|
uint64_t GetTimestamp () const { return m_Timestamp; };
|
||||||
std::vector<Address>& GetAddresses () { return m_Addresses; };
|
std::vector<Address>& GetAddresses () { return m_Addresses; };
|
||||||
const Address * GetNTCPAddress (bool v4only = true) const;
|
const Address * GetNTCPAddress (bool v4only = true) const;
|
||||||
const Address * GetSSUAddress (bool v4only = true) const;
|
const Address * GetSSUAddress (bool v4only = true) const;
|
||||||
const Address * GetSSUV6Address () const;
|
const Address * GetSSUV6Address () const;
|
||||||
|
|
||||||
void AddNTCPAddress (const char * host, int port);
|
void AddNTCPAddress (const char * host, int port);
|
||||||
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
|
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
|
||||||
bool AddIntroducer (const Address * address, uint32_t tag);
|
bool AddIntroducer (const Address * address, uint32_t tag);
|
||||||
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
||||||
void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only
|
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 DeleteProperty (const std::string& key); // called from RouterContext only
|
||||||
void ClearProperties () { m_Properties.clear (); };
|
void ClearProperties () { m_Properties.clear (); };
|
||||||
bool IsFloodfill () const;
|
bool IsFloodfill () const;
|
||||||
bool IsNTCP (bool v4only = true) const;
|
bool IsNTCP (bool v4only = true) const;
|
||||||
bool IsSSU (bool v4only = true) const;
|
bool IsSSU (bool v4only = true) const;
|
||||||
bool IsV6 () const;
|
bool IsV6 () const;
|
||||||
void EnableV6 ();
|
void EnableV6 ();
|
||||||
void DisableV6 ();
|
void DisableV6 ();
|
||||||
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
|
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
|
||||||
bool UsesIntroducer () const;
|
bool UsesIntroducer () const;
|
||||||
bool IsIntroducer () const { return m_Caps & eSSUIntroducer; };
|
bool IsIntroducer () const { return m_Caps & eSSUIntroducer; };
|
||||||
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
|
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
|
||||||
bool IsHidden () const { return m_Caps & eHidden; };
|
bool IsHidden () const { return m_Caps & eHidden; };
|
||||||
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||||
|
|
||||||
uint8_t GetCaps () const { return m_Caps; };
|
uint8_t GetCaps () const { return m_Caps; };
|
||||||
void SetCaps (uint8_t caps);
|
void SetCaps (uint8_t caps);
|
||||||
void SetCaps (const char * caps);
|
void SetCaps (const char * caps);
|
||||||
|
|
||||||
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
||||||
bool IsUnreachable () const { return m_IsUnreachable; };
|
bool IsUnreachable () const { return m_IsUnreachable; };
|
||||||
|
|
||||||
const uint8_t * GetBuffer () const { return m_Buffer; };
|
const uint8_t * GetBuffer () const { return m_Buffer; };
|
||||||
const uint8_t * LoadBuffer (); // load if necessary
|
const uint8_t * LoadBuffer (); // load if necessary
|
||||||
int GetBufferLen () const { return m_BufferLen; };
|
int GetBufferLen () const { return m_BufferLen; };
|
||||||
void CreateBuffer (const PrivateKeys& privateKeys);
|
void CreateBuffer (const PrivateKeys& privateKeys);
|
||||||
|
|
||||||
bool IsUpdated () const { return m_IsUpdated; };
|
bool IsUpdated () const { return m_IsUpdated; };
|
||||||
void SetUpdated (bool updated) { m_IsUpdated = updated; };
|
void SetUpdated (bool updated) { m_IsUpdated = updated; };
|
||||||
void SaveToFile (const std::string& fullPath);
|
void SaveToFile (const std::string& fullPath);
|
||||||
|
|
||||||
std::shared_ptr<RouterProfile> GetProfile () const;
|
std::shared_ptr<RouterProfile> GetProfile () const;
|
||||||
void SaveProfile () { if (m_Profile) m_Profile->Save (); };
|
void SaveProfile () { if (m_Profile) m_Profile->Save (); };
|
||||||
|
|
||||||
void Update (const uint8_t * buf, int len);
|
void Update (const uint8_t * buf, int len);
|
||||||
void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; };
|
void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; };
|
||||||
|
|
||||||
// implements RoutingDestination
|
// implements RoutingDestination
|
||||||
const IdentHash& GetIdentHash () const { return m_RouterIdentity.GetIdentHash (); };
|
const IdentHash& GetIdentHash () const { return m_RouterIdentity.GetIdentHash (); };
|
||||||
const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity.GetStandardIdentity ().publicKey; };
|
const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity.GetStandardIdentity ().publicKey; };
|
||||||
bool IsDestination () const { return false; };
|
bool IsDestination () const { return false; };
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool LoadFile ();
|
bool LoadFile ();
|
||||||
void ReadFromFile ();
|
void ReadFromFile ();
|
||||||
void ReadFromStream (std::istream& s);
|
void ReadFromStream (std::istream& s);
|
||||||
void ReadFromBuffer (bool verifySignature);
|
void ReadFromBuffer (bool verifySignature);
|
||||||
void WriteToStream (std::ostream& s);
|
void WriteToStream (std::ostream& s);
|
||||||
size_t ReadString (char * str, std::istream& s);
|
size_t ReadString (char * str, std::istream& s);
|
||||||
void WriteString (const std::string& str, std::ostream& s);
|
void WriteString (const std::string& str, std::ostream& s);
|
||||||
void ExtractCaps (const char * value);
|
void ExtractCaps (const char * value);
|
||||||
const Address * GetAddress (TransportStyle s, bool v4only, bool v6only = false) const;
|
const Address * GetAddress (TransportStyle s, bool v4only, bool v6only = false) const;
|
||||||
void UpdateCapsProperty ();
|
void UpdateCapsProperty ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::string m_FullPath;
|
std::string m_FullPath;
|
||||||
IdentityEx m_RouterIdentity;
|
IdentityEx m_RouterIdentity;
|
||||||
uint8_t * m_Buffer;
|
uint8_t * m_Buffer;
|
||||||
int m_BufferLen;
|
int m_BufferLen;
|
||||||
uint64_t m_Timestamp;
|
uint64_t m_Timestamp;
|
||||||
std::vector<Address> m_Addresses;
|
std::vector<Address> m_Addresses;
|
||||||
std::map<std::string, std::string> m_Properties;
|
std::map<std::string, std::string> m_Properties;
|
||||||
bool m_IsUpdated, m_IsUnreachable;
|
bool m_IsUpdated, m_IsUnreachable;
|
||||||
uint8_t m_SupportedTransports, m_Caps;
|
uint8_t m_SupportedTransports, m_Caps;
|
||||||
mutable std::shared_ptr<RouterProfile> m_Profile;
|
mutable std::shared_ptr<RouterProfile> m_Profile;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
282
SAM.h
282
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
146
SSU.h
146
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; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
922
SSUData.cpp
922
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 ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
170
SSUData.h
170
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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2018
SSUSession.cpp
2018
SSUSession.cpp
File diff suppressed because it is too large
Load diff
228
SSUSession.h
228
SSUSession.h
|
@ -17,139 +17,139 @@ namespace transport
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
// Warning: do not change the order of these variables
|
// Warning: do not change the order of these variables
|
||||||
// (or fix the unsafe casts in SSU.h)
|
// (or fix the unsafe casts in SSU.h)
|
||||||
struct SSUHeader
|
struct SSUHeader
|
||||||
{
|
{
|
||||||
uint8_t mac[16];
|
uint8_t mac[16];
|
||||||
uint8_t iv[16];
|
uint8_t iv[16];
|
||||||
uint8_t flag;
|
uint8_t flag;
|
||||||
uint32_t time;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
182
Signature.cpp
182
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
660
Signature.h
660
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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1650
Streaming.cpp
1650
Streaming.cpp
File diff suppressed because it is too large
Load diff
396
Streaming.h
396
Streaming.h
|
@ -22,249 +22,249 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
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 ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,101 +11,101 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
134
TransitTunnel.h
134
TransitTunnel.h
|
@ -15,96 +15,96 @@ 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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
884
Transports.cpp
884
Transports.cpp
|
@ -12,490 +12,490 @@ 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 ();
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
auto it = m_Peers.begin ();
|
auto it = m_Peers.begin ();
|
||||||
std::advance (it, rnd.GenerateWord32 (0, m_Peers.size () - 1));
|
std::advance (it, rnd.GenerateWord32 (0, m_Peers.size () - 1));
|
||||||
return it != m_Peers.end () ? it->second.router : nullptr;
|
return it != m_Peers.end () ? it->second.router : nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
192
Transports.h
192
Transports.h
|
@ -28,132 +28,132 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1302
Tunnel.cpp
1302
Tunnel.cpp
File diff suppressed because it is too large
Load diff
280
Tunnel.h
280
Tunnel.h
|
@ -22,181 +22,181 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
88
TunnelBase.h
88
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;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
374
TunnelConfig.h
374
TunnelConfig.h
|
@ -14,219 +14,219 @@ 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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,43 +11,43 @@ 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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,46 +11,46 @@ 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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
774
TunnelPool.cpp
774
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 ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
104
TunnelPool.h
104
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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
610
aes.cpp
610
aes.cpp
|
@ -9,349 +9,349 @@ 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
288
aes.h
288
aes.h
|
@ -10,220 +10,220 @@ 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(const AESKey& key, const uint8_t* iv)
|
||||||
: CBCEncryption()
|
: CBCEncryption()
|
||||||
{
|
{
|
||||||
SetKey(key);
|
SetKey(key);
|
||||||
SetIV(iv);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
464
base64.cpp
464
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
base64.h
10
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
79
hmac.h
79
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
|
||||||
|
|
||||||
|
|
22
i2p.cpp
22
i2p.cpp
|
@ -5,15 +5,15 @@
|
||||||
|
|
||||||
int main( int argc, char* argv[] )
|
int main( int argc, char* argv[] )
|
||||||
{
|
{
|
||||||
Daemon.init(argc, argv);
|
Daemon.init(argc, argv);
|
||||||
if (Daemon.start())
|
if (Daemon.start())
|
||||||
{
|
{
|
||||||
while (Daemon.running)
|
while (Daemon.running)
|
||||||
{
|
{
|
||||||
//TODO Meeh: Find something better to do here.
|
//TODO Meeh: Find something better to do here.
|
||||||
std::this_thread::sleep_for (std::chrono::seconds(1));
|
std::this_thread::sleep_for (std::chrono::seconds(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Daemon.stop();
|
Daemon.stop();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
96
util.h
96
util.h
|
@ -14,61 +14,61 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
namespace config
|
namespace config
|
||||||
{
|
{
|
||||||
extern std::map<std::string, std::string> mapArgs;
|
extern std::map<std::string, std::string> mapArgs;
|
||||||
extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
|
extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
|
||||||
void OptionParser(int argc, const char* const argv[]);
|
void OptionParser(int argc, const char* const argv[]);
|
||||||
int GetArg(const std::string& strArg, int nDefault);
|
int GetArg(const std::string& strArg, int nDefault);
|
||||||
std::string GetArg(const std::string& strArg, const std::string& strDefault);
|
std::string GetArg(const std::string& strArg, const std::string& strDefault);
|
||||||
const char* GetCharArg(const std::string& strArg, const std::string& nDefault);
|
const char* GetCharArg(const std::string& strArg, const std::string& nDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace filesystem
|
namespace filesystem
|
||||||
{
|
{
|
||||||
void SetAppName (const std::string& name);
|
void SetAppName (const std::string& name);
|
||||||
std::string GetAppName ();
|
std::string GetAppName ();
|
||||||
|
|
||||||
const boost::filesystem::path &GetDataDir();
|
const boost::filesystem::path &GetDataDir();
|
||||||
std::string GetFullPath (const std::string& filename);
|
std::string GetFullPath (const std::string& filename);
|
||||||
boost::filesystem::path GetDefaultDataDir();
|
boost::filesystem::path GetDefaultDataDir();
|
||||||
boost::filesystem::path GetConfigFile();
|
boost::filesystem::path GetConfigFile();
|
||||||
void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet,
|
void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet,
|
||||||
std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
|
std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
|
||||||
boost::filesystem::path GetCertificatesDir();
|
boost::filesystem::path GetCertificatesDir();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace http
|
namespace http
|
||||||
{
|
{
|
||||||
const char ETAG[] = "ETag";
|
const char ETAG[] = "ETag";
|
||||||
const char IF_NONE_MATCH[] = "If-None-Match";
|
const char IF_NONE_MATCH[] = "If-None-Match";
|
||||||
const char IF_MODIFIED_SINCE[] = "If-Modified-Since";
|
const char IF_MODIFIED_SINCE[] = "If-Modified-Since";
|
||||||
const char LAST_MODIFIED[] = "Last-Modified";
|
const char LAST_MODIFIED[] = "Last-Modified";
|
||||||
const char TRANSFER_ENCODING[] = "Transfer-Encoding";
|
const char TRANSFER_ENCODING[] = "Transfer-Encoding";
|
||||||
|
|
||||||
std::string httpRequest(const std::string& address);
|
std::string httpRequest(const std::string& address);
|
||||||
std::string GetHttpContent (std::istream& response);
|
std::string GetHttpContent (std::istream& response);
|
||||||
void MergeChunkedResponse (std::istream& response, std::ostream& merged);
|
void MergeChunkedResponse (std::istream& response, std::ostream& merged);
|
||||||
int httpRequestViaI2pProxy(const std::string& address, std::string &content); // return http code
|
int httpRequestViaI2pProxy(const std::string& address, std::string &content); // return http code
|
||||||
std::string urlDecode(const std::string& data);
|
std::string urlDecode(const std::string& data);
|
||||||
|
|
||||||
struct url {
|
struct url {
|
||||||
url(const std::string& url_s); // omitted copy, ==, accessors, ...
|
url(const std::string& url_s); // omitted copy, ==, accessors, ...
|
||||||
private:
|
private:
|
||||||
void parse(const std::string& url_s);
|
void parse(const std::string& url_s);
|
||||||
public:
|
public:
|
||||||
std::string protocol_, host_, path_, query_;
|
std::string protocol_, host_, path_, query_;
|
||||||
std::string portstr_;
|
std::string portstr_;
|
||||||
unsigned int port_;
|
unsigned int port_;
|
||||||
std::string user_;
|
std::string user_;
|
||||||
std::string pass_;
|
std::string pass_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace net
|
namespace net
|
||||||
{
|
{
|
||||||
int GetMTU (const boost::asio::ip::address& localAddress);
|
int GetMTU (const boost::asio::ip::address& localAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue