Tabs -> spaces (yes this breaks compatiblity with upstream)

This commit is contained in:
EinMByte 2015-07-16 23:29:52 +02:00
parent 5d78e2f5e4
commit 4412dd198d
96 changed files with 22253 additions and 22254 deletions

File diff suppressed because it is too large Load diff

View file

@ -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;
}; };
} }
} }

1162
BOB.cpp

File diff suppressed because it is too large Load diff

330
BOB.h
View file

@ -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; };
}; };
} }
} }

View file

@ -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");
} }
} }
} }

View file

@ -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;
} }
} }

View file

@ -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;
} }
} }
} }

View file

@ -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;
} }
} }

View file

@ -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;
} }
} }
} }

View file

@ -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
} }
} }

View file

@ -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

View file

@ -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

View file

@ -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;
} }
} }
} }

View file

@ -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;
}; };
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -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
View file

@ -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

File diff suppressed because it is too large Load diff

224
Garlic.h
View file

@ -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
}; };
} }
} }

View file

@ -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);
} }
} }
} }

View file

@ -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;
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -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);
}; };
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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);
} }
} }
} }
} }

View file

@ -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;
}; };
} }
} }

View file

@ -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;
} }
*/ */

View file

@ -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));
} }

View file

@ -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 ());
} }
} }
} }
} }

View file

@ -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;
}; };
} }
} }

View file

@ -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 ();
} }
} }
} }

View file

@ -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);
}; };
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -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);
}; };
}; };
} }
} }

View file

@ -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;
} }
} }
} }

View file

@ -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;
}; };
} }
} }

View file

@ -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
View file

@ -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
View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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; };
}; };
} }
} }

1846
NetDb.cpp

File diff suppressed because it is too large Load diff

116
NetDb.h
View file

@ -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;
} }
} }

View file

@ -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++;
} }
} }
} }
} }

View file

@ -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;
}; };
} }
} }

View file

@ -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");
} }
} }
} }

View file

@ -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
View file

@ -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

File diff suppressed because it is too large Load diff

102
Reseed.h
View file

@ -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;
}; };
} }
} }

View file

@ -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;
} }
} }

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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;
}; };
} }
} }

1624
SAM.cpp

File diff suppressed because it is too large Load diff

282
SAM.h
View file

@ -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; };
}; };
} }
} }

1062
SOCKS.cpp

File diff suppressed because it is too large Load diff

22
SOCKS.h
View file

@ -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;
} }
} }

1008
SSU.cpp

File diff suppressed because it is too large Load diff

146
SSU.h
View file

@ -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; };
}; };
} }
} }

View file

@ -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
View file

@ -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;
}; };
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -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;
}; };
} }

View file

@ -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
} }
} }
} }

View file

@ -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;
}; };
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -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);
} }
} }
} }

View file

@ -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 ();
} }
} }
} }

View file

@ -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);
} }
} }
} }
} }

View file

@ -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);
} }
} }

View file

@ -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;
}; };
} }
} }

View file

@ -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;
} }
} }
} }

View file

@ -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

File diff suppressed because it is too large Load diff

280
Tunnel.h
View file

@ -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;
} }
} }

View file

@ -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;
}; };
}; };
} }
} }

View file

@ -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;
}; };
} }
} }

View file

@ -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);
}; };
} }
} }
} }

View file

@ -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;
}; };
} }
} }

View file

@ -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 ();
} }
} }
} }

View file

@ -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;
}; };
} }
} }

View file

@ -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 ());
} }
} }
} }

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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);
} }
} }

View file

@ -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;
} }
} }
} }

View file

@ -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
View file

@ -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
View file

@ -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;
} }

1120
util.cpp

File diff suppressed because it is too large Load diff

96
util.h
View file

@ -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);
} }
} }
} }