Browse Source

Merge pull request #511 from PurpleI2P/openssl

recent changes
pull/580/head
orignal 9 years ago committed by GitHub
parent
commit
ccc24337be
  1. 1
      .travis.yml
  2. 2
      AddressBook.cpp
  3. 86
      ChangeLog
  4. 26
      ClientContext.cpp
  5. 8
      Config.cpp
  6. 4
      Config.h
  7. 4
      Daemon.cpp
  8. 2
      Daemon.h
  9. 10
      DaemonLinux.cpp
  10. 2
      DaemonWin32.cpp
  11. 84
      Destination.cpp
  12. 26
      Destination.h
  13. 12
      HTTP.cpp
  14. 17
      HTTP.h
  15. 59
      HTTPProxy.cpp
  16. 7
      HTTPProxy.h
  17. 164
      HTTPServer.cpp
  18. 1
      HTTPServer.h
  19. 587
      I2CP.cpp
  20. 115
      I2CP.h
  21. 28
      I2PService.cpp
  22. 2
      Identity.h
  23. 9
      LeaseSet.cpp
  24. 8
      LeaseSet.h
  25. 20
      Log.cpp
  26. 7
      Log.h
  27. 5
      Makefile
  28. 2
      Makefile.bsd
  29. 2
      Makefile.homebrew
  30. 5
      Makefile.linux
  31. 1
      Makefile.mingw
  32. 2
      Makefile.osx
  33. 3
      NetDb.cpp
  34. 1
      Reseed.cpp
  35. 2
      RouterInfo.cpp
  36. 11
      Streaming.cpp
  37. 2
      Transports.cpp
  38. 2
      Tunnel.cpp
  39. 2
      Tunnel.h
  40. 2
      appveyor.yml
  41. 2
      build/CMakeLists.txt
  42. 2
      build/Dockerfile
  43. 6
      debian/changelog
  44. 1
      debian/control
  45. 1
      debian/i2pd.default
  46. 6
      debian/i2pd.init
  47. 41
      debian/i2pd.openrc
  48. 259
      docs/Doxyfile
  49. 2
      docs/build_notes_cross.md
  50. 1
      docs/build_notes_unix.md
  51. 4
      docs/build_notes_windows.md
  52. 6
      docs/configuration.md
  53. BIN
      docs/itoopieImage.png
  54. 1
      stdafx.h
  55. 3
      tests/Makefile
  56. 25
      tests/test-http-merge_chunked.cpp
  57. 2
      version.h

1
.travis.yml

@ -17,7 +17,6 @@ addons:
- libboost-date-time-dev - libboost-date-time-dev
- libboost-filesystem-dev - libboost-filesystem-dev
- libboost-program-options-dev - libboost-program-options-dev
- libboost-regex-dev
- libboost-system-dev - libboost-system-dev
- libboost-thread-dev - libboost-thread-dev
- libminiupnpc-dev - libminiupnpc-dev

2
AddressBook.cpp

@ -159,7 +159,7 @@ namespace client
int AddressBookFilesystemStorage::Save (const std::map<std::string, i2p::data::IdentHash>& addresses) int AddressBookFilesystemStorage::Save (const std::map<std::string, i2p::data::IdentHash>& addresses)
{ {
if (addresses.size() == 0) { if (addresses.empty()) {
LogPrint(eLogWarning, "Addressbook: not saving empty addressbook"); LogPrint(eLogWarning, "Addressbook: not saving empty addressbook");
return 0; return 0;
} }

86
ChangeLog

@ -0,0 +1,86 @@
# for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog
## [2.8.0] - UNRELEASED
### Changed
- Proxy refactoring & speedup
- I2PControl refactoring & fixes (proper jsonrpc responses on errors)
- boost::regex no more needed
### Fixed
- initscripts: added openrc one, in sysv-ish make I2PD_PORT optional
## [2.7.0] - 2016-05-18
### Added
- Precomputed El-Gamal/DH tables
- Configurable limit of transit tunnels
### Changed
- Speed-up of assymetric crypto for non-x64 platforms
- Refactoring of web-console
## [2.6.0] - 2016-03-31
### Added
- Gracefull shutdown on SIGINT
- Numeric bandwidth limits (was: by router class)
- Jumpservices in web-console
- Logging to syslog
- Tray icon for windows application
### Changed
- Logs refactoring
- Improved statistics in web-console
### Deprecated:
- Renamed main/tunnels config files (will use old, if found, but emits warning)
## [2.5.1] - 2016-03-10
### Fixed
- Doesn't create ~/.i2pd dir if missing
## [2.5.0] - 2016-03-04
### Added
- IRC server tunnels
- SOCKS outproxy support
- Support for gzipped addressbook updates
- Support for router families
### Changed
- Shared RTT/RTO between streams
- Filesystem work refactoring
## [2.4.0] - 2016-02-03
### Added
- X-I2P-* headers for server http-tunnels
- I2CP options for I2P tunnels
- Show I2P tunnels in webconsole
### Changed
- Refactoring of cmdline/config parsing
## [2.3.0] - 2016-01-12
### Added
- Support for new router bandwidth class codes (P and X)
- I2PControl supports external webui
- Added --pidfile and --notransit parameters
- Ability to specify signature type for i2p tunnel
### Changed
- Fixed multiple floodfill-related bugs
- New webconsole layout
## [2.2.0] - 2015-12-22
### Added
- Ability to connect to router without ip via introducer
### Changed
- Persist temporary encryption keys for local destinations
- Performance improvements for EdDSA
- New addressbook structure
## [2.1.0] - 2015-11-12
### Added
- Implementation of EdDSA
### Changed
- EdDSA is default signature type for new RouterInfos

26
ClientContext.cpp

@ -114,6 +114,24 @@ namespace client
} }
} }
// I2CP
bool i2cp; i2p::config::GetOption("i2cp.enabled", i2cp);
if (i2cp)
{
std::string i2cpAddr; i2p::config::GetOption("i2cp.address", i2cpAddr);
uint16_t i2cpPort; i2p::config::GetOption("i2cp.port", i2cpPort);
LogPrint(eLogInfo, "Clients: starting I2CP at ", i2cpAddr, ":", i2cpPort);
try
{
m_I2CPServer = new I2CPServer (i2cpAddr, i2cpPort);
m_I2CPServer->Start ();
}
catch (std::exception& e)
{
LogPrint(eLogError, "Clients: Exception in I2CP: ", e.what());
}
}
m_AddressBook.StartResolvers (); m_AddressBook.StartResolvers ();
} }
@ -165,6 +183,14 @@ namespace client
m_BOBCommandChannel = nullptr; m_BOBCommandChannel = nullptr;
} }
if (m_I2CPServer)
{
LogPrint(eLogInfo, "Clients: stopping I2CP");
m_I2CPServer->Stop ();
delete m_I2CPServer;
m_I2CPServer = nullptr;
}
LogPrint(eLogInfo, "Clients: stopping AddressBook"); LogPrint(eLogInfo, "Clients: stopping AddressBook");
m_AddressBook.Stop (); m_AddressBook.Stop ();
for (auto it: m_Destinations) for (auto it: m_Destinations)

8
Config.cpp

@ -178,6 +178,13 @@ namespace config {
("bob.port", value<uint16_t>()->default_value(2827), "BOB listen port") ("bob.port", value<uint16_t>()->default_value(2827), "BOB listen port")
; ;
options_description i2cp("I2CP options");
i2cp.add_options()
("i2cp.enabled", value<bool>()->default_value(false), "Enable or disable I2CP")
("i2cp.address", value<std::string>()->default_value("127.0.0.1"), "I2CP listen address")
("i2cp.port", value<uint16_t>()->default_value(7654), "I2CP listen port")
;
options_description i2pcontrol("I2PControl options"); options_description i2pcontrol("I2PControl options");
i2pcontrol.add_options() i2pcontrol.add_options()
("i2pcontrol.enabled", value<bool>()->default_value(false), "Enable or disable I2P Control Protocol") ("i2pcontrol.enabled", value<bool>()->default_value(false), "Enable or disable I2P Control Protocol")
@ -207,6 +214,7 @@ namespace config {
.add(socksproxy) .add(socksproxy)
.add(sam) .add(sam)
.add(bob) .add(bob)
.add(i2cp)
.add(i2pcontrol) .add(i2pcontrol)
.add(precomputation) .add(precomputation)
; ;

4
Config.h

@ -68,7 +68,7 @@ namespace config {
* @param value Variable where to store option * @param value Variable where to store option
* @return this function returns false if parameter not found * @return this function returns false if parameter not found
* *
* @example uint16_t port; GetOption("sam.port", port); * Example: uint16_t port; GetOption("sam.port", port);
*/ */
template<typename T> template<typename T>
bool GetOption(const char *name, T& value) { bool GetOption(const char *name, T& value) {
@ -84,7 +84,7 @@ namespace config {
* @param value New parameter value * @param value New parameter value
* @return true if value set up successful, false otherwise * @return true if value set up successful, false otherwise
* *
* @example uint16_t port = 2827; SetOption("bob.port", port); * Example: uint16_t port = 2827; SetOption("bob.port", port);
*/ */
template<typename T> template<typename T>
bool SetOption(const char *name, const T& value) { bool SetOption(const char *name, const T& value) {

4
Daemon.cpp

@ -45,10 +45,10 @@ namespace i2p
#endif #endif
}; };
Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {}; Daemon_Singleton::Daemon_Singleton() : isDaemon(false), running(true), 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
{ {

2
Daemon.h

@ -22,9 +22,7 @@ namespace i2p
virtual bool stop(); virtual bool stop();
virtual void run () {}; virtual void run () {};
bool isLogging;
bool isDaemon; bool isDaemon;
bool running; bool running;
protected: protected:

10
DaemonLinux.cpp

@ -45,7 +45,7 @@ namespace i2p
{ {
bool DaemonLinux::start() bool DaemonLinux::start()
{ {
if (isDaemon == 1) if (isDaemon)
{ {
pid_t pid; pid_t pid;
pid = fork(); pid = fork();
@ -73,10 +73,10 @@ namespace i2p
return false; return false;
} }
// close stdin/stdout/stderr descriptors // point std{in,out,err} descriptors to /dev/null
freopen("/dev/null", "r", stdin); stdin = freopen("/dev/null", "r", stdin);
freopen("/dev/null", "w", stdout); stdout = freopen("/dev/null", "w", stdout);
freopen("/dev/null", "w", stderr); stderr = freopen("/dev/null", "w", stderr);
} }
// Pidfile // Pidfile

2
DaemonWin32.cpp

@ -45,7 +45,7 @@ namespace i2p
return false; return false;
} }
if (isDaemon == 1) if (isDaemon)
{ {
LogPrint(eLogDebug, "Daemon: running as service"); LogPrint(eLogDebug, "Daemon: running as service");
I2PService service(SERVICE_NAME); I2PService service(SERVICE_NAME);

84
Destination.cpp

@ -130,10 +130,6 @@ namespace client
if (!m_IsRunning) if (!m_IsRunning)
{ {
m_IsRunning = true; m_IsRunning = true;
if (m_IsPublic)
PersistTemporaryKeys ();
else
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
m_Pool->SetLocalDestination (shared_from_this ()); m_Pool->SetLocalDestination (shared_from_this ());
m_Pool->SetActive (true); m_Pool->SetActive (true);
m_Thread = new std::thread (std::bind (&LeaseSetDestination::Run, shared_from_this ())); m_Thread = new std::thread (std::bind (&LeaseSetDestination::Run, shared_from_this ()));
@ -204,14 +200,21 @@ namespace client
return m_LeaseSet; return m_LeaseSet;
} }
void LeaseSetDestination::SetLeaseSet (i2p::data::LocalLeaseSet * newLeaseSet)
{
m_LeaseSet.reset (newLeaseSet);
if (m_IsPublic)
{
m_PublishVerificationTimer.cancel ();
Publish ();
}
}
void LeaseSetDestination::UpdateLeaseSet () void LeaseSetDestination::UpdateLeaseSet ()
{ {
int numTunnels = m_Pool->GetNumInboundTunnels () + 2; // 2 backup tunnels int numTunnels = m_Pool->GetNumInboundTunnels () + 2; // 2 backup tunnels
if (numTunnels > i2p::data::MAX_NUM_LEASES) numTunnels = i2p::data::MAX_NUM_LEASES; // 16 tunnels maximum if (numTunnels > i2p::data::MAX_NUM_LEASES) numTunnels = i2p::data::MAX_NUM_LEASES; // 16 tunnels maximum
auto leaseSet = new i2p::data::LocalLeaseSet (GetIdentity (), GetEncryptionPublicKey (), CreateNewLeaseSet (m_Pool->GetInboundTunnels (numTunnels));
m_Pool->GetInboundTunnels (numTunnels));
Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ()); // TODO
m_LeaseSet.reset (leaseSet);
} }
bool LeaseSetDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) bool LeaseSetDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
@ -391,11 +394,6 @@ namespace client
{ {
i2p::garlic::GarlicDestination::SetLeaseSetUpdated (); i2p::garlic::GarlicDestination::SetLeaseSetUpdated ();
UpdateLeaseSet (); UpdateLeaseSet ();
if (m_IsPublic)
{
m_PublishVerificationTimer.cancel ();
Publish ();
}
} }
void LeaseSetDestination::Publish () void LeaseSetDestination::Publish ()
@ -642,36 +640,16 @@ namespace client
else else
it++; it++;
} }
}
void LeaseSetDestination::PersistTemporaryKeys ()
{
std::string ident = GetIdentHash().ToBase32();
std::string path = i2p::fs::DataDirPath("destinations", (ident + ".dat"));
std::ifstream f(path, std::ifstream::binary);
if (f) {
f.read ((char *)m_EncryptionPublicKey, 256);
f.read ((char *)m_EncryptionPrivateKey, 256);
return;
}
LogPrint (eLogInfo, "Destination: Creating new temporary keys for address ", ident, ".b32.i2p");
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);
if (f1) {
f1.write ((char *)m_EncryptionPublicKey, 256);
f1.write ((char *)m_EncryptionPrivateKey, 256);
return;
}
LogPrint(eLogError, "Destinations: Can't save keys to ", path);
} }
ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params): ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params):
LeaseSetDestination (isPublic, params), LeaseSetDestination (isPublic, params),
m_Keys (keys), m_DatagramDestination (nullptr) m_Keys (keys), m_DatagramDestination (nullptr)
{ {
if (isPublic)
PersistTemporaryKeys ();
else
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
if (isPublic) if (isPublic)
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
} }
@ -840,5 +818,37 @@ namespace client
ret.push_back (it1.second); ret.push_back (it1.second);
return ret; return ret;
} }
void ClientDestination::PersistTemporaryKeys ()
{
std::string ident = GetIdentHash().ToBase32();
std::string path = i2p::fs::DataDirPath("destinations", (ident + ".dat"));
std::ifstream f(path, std::ifstream::binary);
if (f) {
f.read ((char *)m_EncryptionPublicKey, 256);
f.read ((char *)m_EncryptionPrivateKey, 256);
return;
}
LogPrint (eLogInfo, "Destination: Creating new temporary keys for address ", ident, ".b32.i2p");
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);
if (f1) {
f1.write ((char *)m_EncryptionPublicKey, 256);
f1.write ((char *)m_EncryptionPrivateKey, 256);
return;
}
LogPrint(eLogError, "Destinations: Can't save keys to ", path);
}
void ClientDestination::CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels)
{
auto leaseSet = new i2p::data::LocalLeaseSet (GetIdentity (), m_EncryptionPublicKey, tunnels);
// sign
Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ()); // TODO
SetLeaseSet (leaseSet);
}
} }
} }

26
Destination.h

@ -81,10 +81,6 @@ namespace client
bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr); bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr);
void CancelDestinationRequest (const i2p::data::IdentHash& dest); void CancelDestinationRequest (const i2p::data::IdentHash& dest);
// implements LocalDestination
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; };
// implements GarlicDestination // implements GarlicDestination
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet (); std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet ();
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const { return m_Pool; } std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const { return m_Pool; }
@ -98,8 +94,10 @@ namespace client
protected: protected:
void SetLeaseSet (i2p::data::LocalLeaseSet * newLeaseSet);
// I2CP // I2CP
virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0; virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0;
virtual void CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels) = 0;
private: private:
@ -117,13 +115,9 @@ namespace client
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 ();
void PersistTemporaryKeys ();
private: private:
uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256];
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;
@ -156,7 +150,8 @@ namespace client
bool Stop (); bool Stop ();
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
// streaming // streaming
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const; std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
@ -166,28 +161,31 @@ namespace client
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
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); }; const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
protected: protected:
// I2CP // I2CP
void HandleDataMessage (const uint8_t * buf, size_t len); void HandleDataMessage (const uint8_t * buf, size_t len);
void CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
private: private:
std::shared_ptr<ClientDestination> GetSharedFromThis () std::shared_ptr<ClientDestination> GetSharedFromThis ()
{ return std::static_pointer_cast<ClientDestination>(shared_from_this ()); } { return std::static_pointer_cast<ClientDestination>(shared_from_this ()); }
void PersistTemporaryKeys ();
private: private:
i2p::data::PrivateKeys m_Keys; i2p::data::PrivateKeys m_Keys;
uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256];
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;

12
HTTP.cpp

@ -253,21 +253,12 @@ namespace http {
if (pos >= eoh) if (pos >= eoh)
break; break;
} }
auto it = headers.find("Host");
if (it != headers.end ()) {
host = it->second;
} else if (version == "HTTP/1.1") {
return -1; /* 'Host' header required for HTTP/1.1 */
} else if (url.host != "") {
host = url.host;
}
return eoh + strlen(HTTP_EOH); return eoh + strlen(HTTP_EOH);
} }
std::string HTTPReq::to_string() { std::string HTTPReq::to_string() {
std::stringstream ss; std::stringstream ss;
ss << method << " " << uri << " " << version << CRLF; ss << method << " " << uri << " " << version << CRLF;
ss << "Host: " << host << CRLF;
for (auto & h : headers) { for (auto & h : headers) {
ss << h.first << ": " << h.second << CRLF; ss << h.first << ": " << h.second << CRLF;
} }
@ -406,11 +397,10 @@ namespace http {
bool MergeChunkedResponse (std::istream& in, std::ostream& out) { bool MergeChunkedResponse (std::istream& in, std::ostream& out) {
std::string hexLen; std::string hexLen;
long int len;
while (!in.eof ()) { while (!in.eof ()) {
std::getline (in, hexLen); std::getline (in, hexLen);
errno = 0; errno = 0;
len = strtoul(hexLen.c_str(), (char **) NULL, 16); long int len = strtoul(hexLen.c_str(), (char **) NULL, 16);
if (errno != 0) if (errno != 0)
return false; /* conversion error */ return false; /* conversion error */
if (len == 0) if (len == 0)

17
HTTP.h

@ -38,7 +38,7 @@ namespace http {
* @brief Tries to parse url from string * @brief Tries to parse url from string
* @return true on success, false on invalid url * @return true on success, false on invalid url
*/ */
bool parse (const char *str, size_t len = 0); bool parse (const char *str, std::size_t len = 0);
bool parse (const std::string& url); bool parse (const std::string& url);
/** /**
@ -69,7 +69,6 @@ namespace http {
std::string version; std::string version;
std::string method; std::string method;
std::string uri; std::string uri;
std::string host;
HTTPReq (): version("HTTP/1.0"), method("GET"), uri("/") {}; HTTPReq (): version("HTTP/1.0"), method("GET"), uri("/") {};
@ -89,10 +88,12 @@ namespace http {
std::string version; std::string version;
std::string status; std::string status;
unsigned short int code; unsigned short int code;
/** simplifies response generation /**
* If this variable is set: * @brief Simplifies response generation
* a) Content-Length header will be added if missing *
* b) contents of body will be included in response * If this variable is set, on @a to_string() call:
* * Content-Length header will be added if missing,
* * contents of @a body will be included in generated response
*/ */
std::string body; std::string body;
@ -108,9 +109,9 @@ namespace http {
/** /**
* @brief Serialize HTTP response to string * @brief Serialize HTTP response to string
* @note If version is set to HTTP/1.1, and Date header is missing, * @note If @a version is set to HTTP/1.1, and Date header is missing,
* it will be generated based on current time and added to headers * it will be generated based on current time and added to headers
* @note If body member is set and Content-Length header is missing, * @note If @a body is set and Content-Length header is missing,
* this header will be added, based on body's length * this header will be added, based on body's length
*/ */
std::string to_string(); std::string to_string();

59
HTTPProxy.cpp

@ -1,16 +1,8 @@
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
#include <string> #include <string>
#include <atomic> #include <atomic>
#include <memory>
#include <set>
#include <boost/asio.hpp>
#include <mutex>
#include "I2PService.h"
#include "Destination.h"
#include "HTTPProxy.h" #include "HTTPProxy.h"
#include "util.h" #include "util.h"
#include "Identity.h" #include "Identity.h"
@ -20,6 +12,7 @@
#include "I2PEndian.h" #include "I2PEndian.h"
#include "I2PTunnel.h" #include "I2PTunnel.h"
#include "Config.h" #include "Config.h"
#include "HTTP.h"
namespace i2p namespace i2p
{ {
@ -43,7 +36,7 @@ namespace proxy
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(const char *message); void HTTPRequestFailed(/*std::string message*/);
void RedirectToJumpService(); void RedirectToJumpService();
void ExtractRequest(); void ExtractRequest();
bool IsI2PAddress(); bool IsI2PAddress();
@ -56,7 +49,6 @@ namespace proxy
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_Response;
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
@ -99,17 +91,10 @@ namespace proxy
/* 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(const char *message) void HTTPProxyHandler::HTTPRequestFailed(/*HTTPProxyHandler::errTypes error*/)
{ {
std::size_t size = std::strlen(message); static std::string response = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\nContent-length: 0\r\n";
std::stringstream ss; boost::asio::async_write(*m_sock, boost::asio::buffer(response,response.size()),
ss << "HTTP/1.0 500 Internal Server Error\r\n"
<< "Content-Type: text/plain\r\n";
ss << "Content-Length: " << std::to_string(size + 2) << "\r\n"
<< "\r\n"; /* end of headers */
ss << message << "\r\n";
m_Response = ss.str();
boost::asio::async_write(*m_sock, boost::asio::buffer(m_Response),
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
} }
@ -120,8 +105,7 @@ namespace proxy
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
response << "HTTP/1.1 302 Found\r\nLocation: http://" << httpAddr << ":" << httpPort << "/?page=jumpservices&address=" << m_address << "\r\n\r\n"; response << "HTTP/1.1 302 Found\r\nLocation: http://" << httpAddr << ":" << httpPort << "/?page=jumpservices&address=" << m_address << "\r\n\r\n";
m_Response = response.str (); boost::asio::async_write(*m_sock, boost::asio::buffer(response.str (),response.str ().length ()),
boost::asio::async_write(*m_sock, boost::asio::buffer(m_Response),
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
} }
@ -133,21 +117,13 @@ namespace proxy
void HTTPProxyHandler::ExtractRequest() void HTTPProxyHandler::ExtractRequest()
{ {
LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url); LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url);
std::string server=""; i2p::http::URL url;
std::string port="80"; url.parse (m_url);
boost::regex rHTTP("http://(.*?)(:(\\d+))?(/.*)"); m_address = url.host;
boost::smatch m; m_port = url.port;
std::string path; m_path = url.path;
if(boost::regex_search(m_url, m, rHTTP, boost::match_extra)) if (!m_port) m_port = 80;
{ LogPrint(eLogDebug, "HTTPProxy: server: ", m_address, ", port: ", m_port, ", path: ", m_path);
server=m[1].str();
if (m[2].str() != "") port=m[3].str();
path=m[4].str();
}
LogPrint(eLogDebug, "HTTPProxy: server: ", server, ", port: ", port, ", path: ", path);
m_address = server;
m_port = boost::lexical_cast<int>(port);
m_path = path;
} }
bool HTTPProxyHandler::ValidateHTTPRequest() bool HTTPProxyHandler::ValidateHTTPRequest()
@ -155,7 +131,7 @@ namespace proxy
if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" ) if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" )
{ {
LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version); LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version);
HTTPRequestFailed("unsupported HTTP version"); HTTPRequestFailed(); //TODO: send right stuff
return false; return false;
} }
return true; return true;
@ -292,13 +268,13 @@ namespace proxy
case '\n': EnterState(DONE); break; case '\n': EnterState(DONE); break;
default: default:
LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff)); LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff));
HTTPRequestFailed("rejected invalid request"); HTTPRequestFailed(); //TODO: add correct code
return false; return false;
} }
break; break;
default: default:
LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state); LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state);
HTTPRequestFailed("invalid parser state"); HTTPRequestFailed(); //TODO: add correct code 500
return false; return false;
} }
http_buff++; http_buff++;
@ -354,7 +330,7 @@ namespace proxy
else else
{ {
LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info"); LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info");
HTTPRequestFailed("error when creating the stream, check logs"); HTTPRequestFailed(); // TODO: Send correct error message host unreachable
} }
} }
@ -367,5 +343,6 @@ namespace proxy
{ {
return std::make_shared<HTTPProxyHandler> (this, socket); return std::make_shared<HTTPProxyHandler> (this, socket);
} }
} }
} }

7
HTTPProxy.h

@ -1,6 +1,13 @@
#ifndef HTTP_PROXY_H__ #ifndef HTTP_PROXY_H__
#define HTTP_PROXY_H__ #define HTTP_PROXY_H__
#include <memory>
#include <set>
#include <boost/asio.hpp>
#include <mutex>
#include "I2PService.h"
#include "Destination.h"
namespace i2p namespace i2p
{ {
namespace proxy namespace proxy

164
HTTPServer.cpp

@ -27,156 +27,6 @@
namespace i2p { namespace i2p {
namespace http { namespace http {
const char *itoopieImage =
"<img alt=\"ICToopie Icon\" src=\"data:image/png;base64,"
"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\" />";
const char *itoopieFavicon = const char *itoopieFavicon =
"data:image/png;base64," "data:image/png;base64,"
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv" "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv"
@ -667,7 +517,7 @@ namespace http {
i2p::config::GetOption("http.auth", needAuth); i2p::config::GetOption("http.auth", needAuth);
i2p::config::GetOption("http.user", user); i2p::config::GetOption("http.user", user);
i2p::config::GetOption("http.pass", pass); i2p::config::GetOption("http.pass", pass);
}; }
void HTTPConnection::Receive () void HTTPConnection::Receive ()
{ {
@ -755,12 +605,14 @@ namespace http {
// Html5 head start // Html5 head start
ShowPageHead (s); ShowPageHead (s);
if (req.uri.find("page=") != std::string::npos) if (req.uri.find("page=") != std::string::npos) {
HandlePage (req, res, s); HandlePage (req, res, s);
else if (req.uri.find("cmd=") != std::string::npos) } else if (req.uri.find("cmd=") != std::string::npos) {
HandleCommand (req, res, s); HandleCommand (req, res, s);
else } else {
ShowStatus (s); ShowStatus (s);
res.add_header("Refresh", "5");
}
ShowPageTail (s); ShowPageTail (s);
res.code = 200; res.code = 200;
@ -841,7 +693,9 @@ namespace http {
return; return;
} }
s << "<b>SUCCESS</b>:&nbsp;Command accepted<br><br>\r\n"; s << "<b>SUCCESS</b>:&nbsp;Command accepted<br><br>\r\n";
s << "<a href=\"/?page=commands\">Back to commands list</a>"; s << "<a href=\"/?page=commands\">Back to commands list</a><br>\r\n";
s << "<p>You will be redirected in 5 seconds</b>";
res.add_header("Refresh", "5; url=/?page=commands");
} }
void HTTPConnection::SendReply (HTTPRes& reply, std::string& content) void HTTPConnection::SendReply (HTTPRes& reply, std::string& content)

1
HTTPServer.h

@ -3,7 +3,6 @@
namespace i2p { namespace i2p {
namespace http { namespace http {
extern const char *itoopieImage;
extern const char *itoopieFavicon; extern const char *itoopieFavicon;
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192; const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;

587
I2CP.cpp

@ -1,31 +1,141 @@
/*
* Copyright (c) 2013-2016, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <string.h> #include <string.h>
#include <stdlib.h>
#include <openssl/rand.h>
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Log.h" #include "Log.h"
#include "Timestamp.h"
#include "LeaseSet.h"
#include "ClientContext.h"
#include "Transports.h"
#include "Signature.h"
#include "I2CP.h" #include "I2CP.h"
namespace i2p namespace i2p
{ {
namespace client namespace client
{ {
I2CPDestination::I2CPDestination (I2CPSession& owner, std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic): I2CPDestination::I2CPDestination (std::shared_ptr<I2CPSession> owner, std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params):
LeaseSetDestination (isPublic), m_Owner (owner), m_Identity (identity) LeaseSetDestination (isPublic, &params), m_Owner (owner), m_Identity (identity)
{
}
void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key)
{ {
memcpy (m_EncryptionPrivateKey, key, 256);
}
void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len)
{
uint32_t length = bufbe32toh (buf);
if (length > len - 4) length = len - 4;
m_Owner->SendMessagePayloadMessage (buf + 4, length);
}
void I2CPDestination::CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels)
{
i2p::data::LocalLeaseSet ls (m_Identity, m_EncryptionPrivateKey, tunnels); // we don't care about encryption key
m_LeaseSetExpirationTime = ls.GetExpirationTime ();
uint8_t * leases = ls.GetLeases ();
leases[-1] = tunnels.size ();
htobe16buf (leases - 3, m_Owner->GetSessionID ());
size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*tunnels.size ();
m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l);
}
void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len)
{
auto ls = new i2p::data::LocalLeaseSet (m_Identity, buf, len);
ls->SetExpirationTime (m_LeaseSetExpirationTime);
SetLeaseSet (ls);
}
void I2CPDestination::SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce)
{
auto msg = NewI2NPMessage ();
uint8_t * buf = msg->GetPayload ();
htobe32buf (buf, len);
memcpy (buf + 4, payload, len);
msg->len += len + 4;
msg->FillI2NPMessageHeader (eI2NPData);
auto remote = FindLeaseSet (ident);
if (remote)
GetService ().post (std::bind (&I2CPDestination::SendMsg, GetSharedFromThis (), msg, remote));
else
{
auto s = GetSharedFromThis ();
RequestDestination (ident,
[s, msg, nonce](std::shared_ptr<i2p::data::LeaseSet> ls)
{
if (ls)
{
bool sent = s->SendMsg (msg, ls);
s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure);
}
else
s->m_Owner->SendMessageStatusMessage (nonce, eI2CPMessageStatusNoLeaseSet);
});
}
}
bool I2CPDestination::SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote)
{
auto outboundTunnel = GetTunnelPool ()->GetNextOutboundTunnel ();
auto leases = remote->GetNonExpiredLeases ();
if (!leases.empty () && outboundTunnel)
{
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
uint32_t i = rand () % leases.size ();
auto garlic = WrapMessage (remote, msg, true);
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
i2p::tunnel::eDeliveryTypeTunnel,
leases[i]->tunnelGateway, leases[i]->tunnelID,
garlic
});
outboundTunnel->SendTunnelDataMsg (msgs);
return true;
}
else
{
if (outboundTunnel)
LogPrint (eLogWarning, "I2CP: Failed to send message. All leases expired");
else
LogPrint (eLogWarning, "I2CP: Failed to send message. No outbound tunnels");
return false;
}
} }
I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket): I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
m_Owner (owner), m_Socket (socket), m_Owner (owner), m_Socket (socket),
m_NextMessage (nullptr), m_NextMessageLen (0), m_NextMessageOffset (0) m_NextMessage (nullptr), m_NextMessageLen (0), m_NextMessageOffset (0),
m_SessionID (0), m_MessageID (0), m_IsSendAccepted (true)
{ {
ReadProtocolByte ();
} }
I2CPSession::~I2CPSession () I2CPSession::~I2CPSession ()
{ {
delete[] m_NextMessage; delete[] m_NextMessage;
} }
void I2CPSession::Start ()
{
ReadProtocolByte ();
}
void I2CPSession::Stop ()
{
Terminate ();
}
void I2CPSession::ReadProtocolByte () void I2CPSession::ReadProtocolByte ()
{ {
if (m_Socket) if (m_Socket)
@ -34,7 +144,7 @@ namespace client
m_Socket->async_read_some (boost::asio::buffer (m_Buffer, 1), m_Socket->async_read_some (boost::asio::buffer (m_Buffer, 1),
[s](const boost::system::error_code& ecode, std::size_t bytes_transferred) [s](const boost::system::error_code& ecode, std::size_t bytes_transferred)
{ {
if (!ecode && bytes_transferred > 0 && s->m_Buffer[0] == I2CP_PRTOCOL_BYTE) if (!ecode && bytes_transferred > 0 && s->m_Buffer[0] == I2CP_PROTOCOL_BYTE)
s->Receive (); s->Receive ();
else else
s->Terminate (); s->Terminate ();
@ -54,25 +164,34 @@ namespace client
Terminate (); Terminate ();
else else
{ {
size_t offset = 0; size_t offset = 0; // from m_Buffer
if (m_NextMessage) if (m_NextMessage)
{ {
if (m_NextMessageOffset + bytes_transferred <= m_NextMessageLen) if (m_NextMessageOffset + bytes_transferred < m_NextMessageLen)
{ {
memcpy (m_NextMessage + m_NextMessageOffset, m_Buffer, bytes_transferred); memcpy (m_NextMessage + m_NextMessageOffset, m_Buffer, bytes_transferred);
m_NextMessageOffset += bytes_transferred; m_NextMessageOffset += bytes_transferred;
offset = bytes_transferred;
} }
else else
{ {
// m_NextMessage complete
offset = m_NextMessageLen - m_NextMessageOffset; offset = m_NextMessageLen - m_NextMessageOffset;
memcpy (m_NextMessage + m_NextMessageOffset, m_Buffer, offset); memcpy (m_NextMessage + m_NextMessageOffset, m_Buffer, offset);
HandleNextMessage (m_NextMessage); HandleNextMessage (m_NextMessage);
delete[] m_NextMessage; delete[] m_NextMessage;
m_NextMessage = nullptr;
} }
} }
while (offset < bytes_transferred) while (offset < bytes_transferred)
{ {
auto msgLen = bufbe32toh (m_Buffer + offset + I2CP_HEADER_LENGTH_OFFSET) + I2CP_HEADER_SIZE; auto msgLen = bufbe32toh (m_Buffer + offset + I2CP_HEADER_LENGTH_OFFSET) + I2CP_HEADER_SIZE;
if (msgLen > 0xFFFF) // 64K
{
LogPrint (eLogError, "I2CP: message length ", msgLen, " exceeds 64K. Terminated");
Terminate ();
return;
}
if (msgLen <= bytes_transferred - offset) if (msgLen <= bytes_transferred - offset)
{ {
HandleNextMessage (m_Buffer + offset); HandleNextMessage (m_Buffer + offset);
@ -102,17 +221,463 @@ namespace client
void I2CPSession::Terminate () void I2CPSession::Terminate ()
{ {
if (m_Destination)
{
m_Destination->Stop ();
m_Destination = nullptr;
}
if (m_Socket)
{
m_Socket->close ();
m_Socket = nullptr;
}
m_Owner.RemoveSession (GetSessionID ());
}
void I2CPSession::SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len)
{
auto l = len + I2CP_HEADER_SIZE;
uint8_t * buf = new uint8_t[l];
htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len);
buf[I2CP_HEADER_TYPE_OFFSET] = type;
memcpy (buf + I2CP_HEADER_SIZE, payload, len);
boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, l), boost::asio::transfer_all (),
std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (),
std::placeholders::_1, std::placeholders::_2, buf));
}
void I2CPSession::HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, const uint8_t * buf)
{
delete[] buf;
if (ecode && ecode != boost::asio::error::operation_aborted)
Terminate ();
}
std::string I2CPSession::ExtractString (const uint8_t * buf, size_t len)
{
uint8_t l = buf[0];
if (l > len) l = len;
return std::string ((const char *)(buf + 1), l);
}
size_t I2CPSession::PutString (uint8_t * buf, size_t len, const std::string& str)
{
auto l = str.length ();
if (l + 1 >= len) l = len - 1;
if (l > 255) l = 255; // 1 byte max
buf[0] = l;
memcpy (buf + 1, str.c_str (), l);
return l + 1;
}
void I2CPSession::ExtractMapping (const uint8_t * buf, size_t len, std::map<std::string, std::string>& mapping)
// TODO: move to Base.cpp
{
size_t offset = 0;
while (offset < len)
{
std::string param = ExtractString (buf + offset, len - offset);
offset += param.length ();
if (buf[offset] != '=')
{
LogPrint (eLogWarning, "I2CP: Unexpected character ", buf[offset], " instead '=' after ", param);
break;
}
offset++;
std::string value = ExtractString (buf + offset, len - offset);
offset += value.length ();
if (buf[offset] != ';')
{
LogPrint (eLogWarning, "I2CP: Unexpected character ", buf[offset], " instead ';' after ", value);
break;
}
offset++;
mapping.insert (std::make_pair (param, value));
}
} }
void I2CPSession::GetDateMessageHandler (const uint8_t * buf, size_t len) void I2CPSession::GetDateMessageHandler (const uint8_t * buf, size_t len)
{ {
// get version
auto version = ExtractString (buf, len);
auto l = version.length () + 1 + 8;
uint8_t * payload = new uint8_t[l];
// set date
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
htobe64buf (payload, ts);
// echo vesrion back
PutString (payload + 8, l - 8, version);
SendI2CPMessage (I2CP_SET_DATE_MESSAGE, payload, l);
delete[] payload;
}
void I2CPSession::CreateSessionMessageHandler (const uint8_t * buf, size_t len)
{
RAND_bytes ((uint8_t *)&m_SessionID, 2);
auto identity = std::make_shared<i2p::data::IdentityEx>();
size_t offset = identity->FromBuffer (buf, len);
if (!offset)
{
LogPrint (eLogError, "I2CP: create session maformed identity");
SendSessionStatusMessage (3); // invalid
return;
}
uint16_t optionsSize = bufbe16toh (buf + offset);
offset += 2;
if (optionsSize > len - offset)
{
LogPrint (eLogError, "I2CP: options size ", optionsSize, "exceeds message size");
SendSessionStatusMessage (3); // invalid
return;
}
std::map<std::string, std::string> params;
ExtractMapping (buf + offset, optionsSize, params);
offset += optionsSize; // options
if (params[I2CP_PARAM_MESSAGE_RELIABILITY] == "none") m_IsSendAccepted = false;
offset += 8; // date
if (identity->Verify (buf, offset, buf + offset)) // signature
{
bool isPublic = true;
if (params[I2CP_PARAM_DONT_PUBLISH_LEASESET] == "true") isPublic = false;
if (!m_Destination)
{
m_Destination = std::make_shared<I2CPDestination>(shared_from_this (), identity, isPublic, params);
SendSessionStatusMessage (1); // created
LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " created");
m_Destination->Start ();
}
else
{
LogPrint (eLogError, "I2CP: session already exists");
SendSessionStatusMessage (4); // refused
}
}
else
{
LogPrint (eLogError, "I2CP: create session signature verification falied");
SendSessionStatusMessage (3); // invalid
}
}
void I2CPSession::DestroySessionMessageHandler (const uint8_t * buf, size_t len)
{
SendSessionStatusMessage (0); // destroy
LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " destroyed");
if (m_Destination)
{
m_Destination->Stop ();
m_Destination = 0;
}
} }
I2CPServer::I2CPServer (const std::string& interface, int port) void I2CPSession::ReconfigureSessionMessageHandler (const uint8_t * buf, size_t len)
{
// TODO: implement actual reconfiguration
SendSessionStatusMessage (2); // updated
}
void I2CPSession::SendSessionStatusMessage (uint8_t status)
{
uint8_t buf[3];
htobe16buf (buf, m_SessionID);
buf[2] = status;
SendI2CPMessage (I2CP_SESSION_STATUS_MESSAGE, buf, 3);
}
void I2CPSession::SendMessageStatusMessage (uint32_t nonce, I2CPMessageStatus status)
{
if (!nonce) return; // don't send status with zero nonce
uint8_t buf[15];
htobe16buf (buf, m_SessionID);
htobe32buf (buf + 2, m_MessageID++);
buf[6] = (uint8_t)status;
memset (buf + 7, 0, 4); // size
htobe32buf (buf + 11, nonce);
SendI2CPMessage (I2CP_MESSAGE_STATUS_MESSAGE, buf, 15);
}
void I2CPSession::CreateLeaseSetMessageHandler (const uint8_t * buf, size_t len)
{
uint16_t sessionID = bufbe16toh (buf);
if (sessionID == m_SessionID)
{
size_t offset = 2;
if (m_Destination)
{
offset += i2p::crypto::DSA_PRIVATE_KEY_LENGTH; // skip signing private key
// we always assume this field as 20 bytes (DSA) regardless actual size
// instead of
//offset += m_Destination->GetIdentity ()->GetSigningPrivateKeyLen ();
m_Destination->SetEncryptionPrivateKey (buf + offset);
offset += 256;
m_Destination->LeaseSetCreated (buf + offset, len - offset);
}
}
else
LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID);
}
void I2CPSession::SendMessageMessageHandler (const uint8_t * buf, size_t len)
{
uint16_t sessionID = bufbe16toh (buf);
if (sessionID == m_SessionID)
{
size_t offset = 2;
if (m_Destination)
{
i2p::data::IdentityEx identity;
offset += identity.FromBuffer (buf + offset, len - offset);
uint32_t payloadLen = bufbe32toh (buf + offset);
offset += 4;
uint32_t nonce = bufbe32toh (buf + offset + payloadLen);
if (m_IsSendAccepted)
SendMessageStatusMessage (nonce, eI2CPMessageStatusAccepted); // accepted
m_Destination->SendMsgTo (buf + offset, payloadLen, identity.GetIdentHash (), nonce);
}
}
else
LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID);
}
void I2CPSession::SendMessageExpiresMessageHandler (const uint8_t * buf, size_t len)
{
SendMessageMessageHandler (buf, len - 8); // ignore flags(2) and expiration(6)
}
void I2CPSession::HostLookupMessageHandler (const uint8_t * buf, size_t len)
{
uint16_t sessionID = bufbe16toh (buf);
if (sessionID == m_SessionID)
{
uint32_t requestID = bufbe32toh (buf + 2);
//uint32_t timeout = bufbe32toh (buf + 6);
i2p::data::IdentHash ident;
switch (buf[10])
{
case 0: // hash
ident = i2p::data::IdentHash (buf + 11);
break;
case 1: // address
{
auto name = ExtractString (buf + 11, len - 11);
if (!i2p::client::context.GetAddressBook ().GetIdentHash (name, ident))
{
LogPrint (eLogError, "I2CP: address ", name, " not found");
SendHostReplyMessage (requestID, nullptr);
return;
}
break;
}
default:
LogPrint (eLogError, "I2CP: request type ", (int)buf[10], " is not supported");
SendHostReplyMessage (requestID, nullptr);
return;
}
if (m_Destination)
{
auto ls = m_Destination->FindLeaseSet (ident);
if (ls)
SendHostReplyMessage (requestID, ls->GetIdentity ());
else
{
auto s = shared_from_this ();
m_Destination->RequestDestination (ident,
[s, requestID](std::shared_ptr<i2p::data::LeaseSet> leaseSet)
{
s->SendHostReplyMessage (requestID, leaseSet ? leaseSet->GetIdentity () : nullptr);
});
}
}
else
SendHostReplyMessage (requestID, nullptr);
}
else
LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID);
}
void I2CPSession::SendHostReplyMessage (uint32_t requestID, std::shared_ptr<const i2p::data::IdentityEx> identity)
{
if (identity)
{
size_t l = identity->GetFullLen () + 7;
uint8_t * buf = new uint8_t[l];
htobe16buf (buf, m_SessionID);
htobe32buf (buf + 2, requestID);
buf[6] = 0; // result code
identity->ToBuffer (buf + 7, l - 7);
SendI2CPMessage (I2CP_HOST_REPLY_MESSAGE, buf, l);
delete[] buf;
}
else
{
uint8_t buf[7];
htobe16buf (buf, m_SessionID);
htobe32buf (buf + 2, requestID);
buf[6] = 1; // result code
SendI2CPMessage (I2CP_HOST_REPLY_MESSAGE, buf, 7);
}
}
void I2CPSession::DestLookupMessageHandler (const uint8_t * buf, size_t len)
{
if (m_Destination)
{
auto ls = m_Destination->FindLeaseSet (buf);
if (ls)
{
auto l = ls->GetIdentity ()->GetFullLen ();
uint8_t * identBuf = new uint8_t[l];
ls->GetIdentity ()->ToBuffer (identBuf, l);
SendI2CPMessage (I2CP_DEST_REPLY_MESSAGE, identBuf, l);
delete[] identBuf;
}
else
{
auto s = shared_from_this ();
i2p::data::IdentHash ident (buf);
m_Destination->RequestDestination (ident,
[s, ident](std::shared_ptr<i2p::data::LeaseSet> leaseSet)
{
if (leaseSet) // found
{
auto l = leaseSet->GetIdentity ()->GetFullLen ();
uint8_t * identBuf = new uint8_t[l];
leaseSet->GetIdentity ()->ToBuffer (identBuf, l);
s->SendI2CPMessage (I2CP_DEST_REPLY_MESSAGE, identBuf, l);
delete[] identBuf;
}
else
s->SendI2CPMessage (I2CP_DEST_REPLY_MESSAGE, ident, 32); // not found
});
}
}
else
SendI2CPMessage (I2CP_DEST_REPLY_MESSAGE, buf, 32);
}
void I2CPSession::GetBandwidthLimitsMessageHandler (const uint8_t * buf, size_t len)
{
uint8_t limits[64];
memset (limits, 0, 64);
htobe32buf (limits, i2p::transport::transports.GetInBandwidth ()); // inbound
htobe32buf (limits + 4, i2p::transport::transports.GetOutBandwidth ()); // outbound
SendI2CPMessage (I2CP_BANDWIDTH_LIMITS_MESSAGE, limits, 64);
}
void I2CPSession::SendMessagePayloadMessage (const uint8_t * payload, size_t len)
{
// we don't use SendI2CPMessage to eliminate additional copy
auto l = len + 10 + I2CP_HEADER_SIZE;
uint8_t * buf = new uint8_t[l];
htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10);
buf[I2CP_HEADER_TYPE_OFFSET] = I2CP_MESSAGE_PAYLOAD_MESSAGE;
htobe16buf (buf + I2CP_HEADER_SIZE, m_SessionID);
htobe32buf (buf + I2CP_HEADER_SIZE + 2, m_MessageID++);
htobe32buf (buf + I2CP_HEADER_SIZE + 6, len);
memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len);
boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, l), boost::asio::transfer_all (),
std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (),
std::placeholders::_1, std::placeholders::_2, buf));
}
I2CPServer::I2CPServer (const std::string& interface, int port):
m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(interface), port))
{ {
memset (m_MessagesHandlers, 0, sizeof (m_MessagesHandlers)); memset (m_MessagesHandlers, 0, sizeof (m_MessagesHandlers));
m_MessagesHandlers[I2CP_GET_DATE_MESSAGE] = &I2CPSession::GetDateMessageHandler; m_MessagesHandlers[I2CP_GET_DATE_MESSAGE] = &I2CPSession::GetDateMessageHandler;
m_MessagesHandlers[I2CP_CREATE_SESSION_MESSAGE] = &I2CPSession::CreateSessionMessageHandler;
m_MessagesHandlers[I2CP_DESTROY_SESSION_MESSAGE] = &I2CPSession::DestroySessionMessageHandler;
m_MessagesHandlers[I2CP_RECONFIGURE_SESSION_MESSAGE] = &I2CPSession::ReconfigureSessionMessageHandler;
m_MessagesHandlers[I2CP_CREATE_LEASESET_MESSAGE] = &I2CPSession::CreateLeaseSetMessageHandler;
m_MessagesHandlers[I2CP_SEND_MESSAGE_MESSAGE] = &I2CPSession::SendMessageMessageHandler;
m_MessagesHandlers[I2CP_SEND_MESSAGE_EXPIRES_MESSAGE] = &I2CPSession::SendMessageExpiresMessageHandler;
m_MessagesHandlers[I2CP_HOST_LOOKUP_MESSAGE] = &I2CPSession::HostLookupMessageHandler;
m_MessagesHandlers[I2CP_DEST_LOOKUP_MESSAGE] = &I2CPSession::DestLookupMessageHandler;
m_MessagesHandlers[I2CP_GET_BANDWIDTH_LIMITS_MESSAGE] = &I2CPSession::GetBandwidthLimitsMessageHandler;
}
I2CPServer::~I2CPServer ()
{
if (m_IsRunning)
Stop ();
}
void I2CPServer::Start ()
{
Accept ();
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&I2CPServer::Run, this));
} }
void I2CPServer::Stop ()
{
m_IsRunning = false;
m_Acceptor.cancel ();
for (auto it: m_Sessions)
it.second->Stop ();
m_Sessions.clear ();
m_Service.stop ();
if (m_Thread)
{
m_Thread->join ();
delete m_Thread;
m_Thread = nullptr;
}
}
void I2CPServer::Run ()
{
while (m_IsRunning)
{
try
{
m_Service.run ();
}
catch (std::exception& ex)
{
LogPrint (eLogError, "I2CP: runtime exception: ", ex.what ());
}
}
}
void I2CPServer::Accept ()
{
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (m_Service);
m_Acceptor.async_accept (*newSocket, std::bind (&I2CPServer::HandleAccept, this,
std::placeholders::_1, newSocket));
}
void I2CPServer::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{
if (!ecode && socket)
{
boost::system::error_code ec;
auto ep = socket->remote_endpoint (ec);
if (!ec)
{
LogPrint (eLogDebug, "I2CP: new connection from ", ep);
auto session = std::make_shared<I2CPSession>(*this, socket);
m_Sessions[session->GetSessionID ()] = session;
session->Start ();
}
else
LogPrint (eLogError, "I2CP: incoming connection error ", ec.message ());
}
else
LogPrint (eLogError, "I2CP: accept error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Accept ();
}
void I2CPServer::RemoveSession (uint16_t sessionID)
{
m_Sessions.erase (sessionID);
}
} }
} }

115
I2CP.h

@ -1,9 +1,19 @@
/*
* Copyright (c) 2013-2016, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef I2CP_H__ #ifndef I2CP_H__
#define I2CP_H__ #define I2CP_H__
#include <inttypes.h> #include <inttypes.h>
#include <string> #include <string>
#include <memory> #include <memory>
#include <thread>
#include <map>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "Destination.h" #include "Destination.h"
@ -11,7 +21,7 @@ namespace i2p
{ {
namespace client namespace client
{ {
const uint8_t I2CP_PRTOCOL_BYTE = 0x2A; const uint8_t I2CP_PROTOCOL_BYTE = 0x2A;
const size_t I2CP_SESSION_BUFFER_SIZE = 4096; const size_t I2CP_SESSION_BUFFER_SIZE = 4096;
const size_t I2CP_HEADER_LENGTH_OFFSET = 0; const size_t I2CP_HEADER_LENGTH_OFFSET = 0;
@ -19,27 +29,69 @@ namespace client
const size_t I2CP_HEADER_SIZE = I2CP_HEADER_TYPE_OFFSET + 1; const size_t I2CP_HEADER_SIZE = I2CP_HEADER_TYPE_OFFSET + 1;
const uint8_t I2CP_GET_DATE_MESSAGE = 32; const uint8_t I2CP_GET_DATE_MESSAGE = 32;
const uint8_t I2CP_SET_DATE_MESSAGE = 33;
const uint8_t I2CP_CREATE_SESSION_MESSAGE = 1;
const uint8_t I2CP_RECONFIGURE_SESSION_MESSAGE = 2;
const uint8_t I2CP_SESSION_STATUS_MESSAGE = 20;
const uint8_t I2CP_DESTROY_SESSION_MESSAGE = 3;
const uint8_t I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE = 37;
const uint8_t I2CP_CREATE_LEASESET_MESSAGE = 4;
const uint8_t I2CP_SEND_MESSAGE_MESSAGE = 5;
const uint8_t I2CP_SEND_MESSAGE_EXPIRES_MESSAGE = 36;
const uint8_t I2CP_MESSAGE_PAYLOAD_MESSAGE = 31;
const uint8_t I2CP_MESSAGE_STATUS_MESSAGE = 22;
const uint8_t I2CP_HOST_LOOKUP_MESSAGE = 38;
const uint8_t I2CP_HOST_REPLY_MESSAGE = 39;
const uint8_t I2CP_DEST_LOOKUP_MESSAGE = 34;
const uint8_t I2CP_DEST_REPLY_MESSAGE = 35;
const uint8_t I2CP_GET_BANDWIDTH_LIMITS_MESSAGE = 8;
const uint8_t I2CP_BANDWIDTH_LIMITS_MESSAGE = 23;
enum I2CPMessageStatus
{
eI2CPMessageStatusAccepted = 1,
eI2CPMessageStatusGuaranteedSuccess = 4,
eI2CPMessageStatusGuaranteedFailure = 5,
eI2CPMessageStatusNoLeaseSet = 21
};
// params
const char I2CP_PARAM_DONT_PUBLISH_LEASESET[] = "i2cp.dontPublishLeaseSet";
const char I2CP_PARAM_MESSAGE_RELIABILITY[] = "i2cp.messageReliability";
class I2CPSession; class I2CPSession;
class I2CPDestination: public LeaseSetDestination class I2CPDestination: public LeaseSetDestination
{ {
public: public:
I2CPDestination (I2CPSession& owner, std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic); I2CPDestination (std::shared_ptr<I2CPSession> owner, std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params);
protected: void SetEncryptionPrivateKey (const uint8_t * key);
void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession
void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession
// implements LocalDestination // implements LocalDestination
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Identity; }; std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Identity; };
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { /* TODO */};
protected:
// I2CP // I2CP
void HandleDataMessage (const uint8_t * buf, size_t len) {}; void HandleDataMessage (const uint8_t * buf, size_t len);
void CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
private: private:
I2CPSession& m_Owner; std::shared_ptr<I2CPDestination> GetSharedFromThis ()
{ return std::static_pointer_cast<I2CPDestination>(shared_from_this ()); }
bool SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote);
private:
std::shared_ptr<I2CPSession> m_Owner;
std::shared_ptr<const i2p::data::IdentityEx> m_Identity; std::shared_ptr<const i2p::data::IdentityEx> m_Identity;
uint8_t m_EncryptionPrivateKey[256];
uint64_t m_LeaseSetExpirationTime;
}; };
class I2CPServer; class I2CPServer;
@ -50,8 +102,26 @@ namespace client
I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket); I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
~I2CPSession (); ~I2CPSession ();
void Start ();
void Stop ();
uint16_t GetSessionID () const { return m_SessionID; };
// called from I2CPDestination
void SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len);
void SendMessagePayloadMessage (const uint8_t * payload, size_t len);
void SendMessageStatusMessage (uint32_t nonce, I2CPMessageStatus status);
// message handlers // message handlers
void GetDateMessageHandler (const uint8_t * buf, size_t len); void GetDateMessageHandler (const uint8_t * buf, size_t len);
void CreateSessionMessageHandler (const uint8_t * buf, size_t len);
void DestroySessionMessageHandler (const uint8_t * buf, size_t len);
void ReconfigureSessionMessageHandler (const uint8_t * buf, size_t len);
void CreateLeaseSetMessageHandler (const uint8_t * buf, size_t len);
void SendMessageMessageHandler (const uint8_t * buf, size_t len);
void SendMessageExpiresMessageHandler (const uint8_t * buf, size_t len);
void HostLookupMessageHandler (const uint8_t * buf, size_t len);
void DestLookupMessageHandler (const uint8_t * buf, size_t len);
void GetBandwidthLimitsMessageHandler (const uint8_t * buf, size_t len);
private: private:
@ -60,6 +130,14 @@ namespace client
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 HandleNextMessage (const uint8_t * buf); void HandleNextMessage (const uint8_t * buf);
void Terminate (); void Terminate ();
void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, const uint8_t * buf);
std::string ExtractString (const uint8_t * buf, size_t len);
size_t PutString (uint8_t * buf, size_t len, const std::string& str);
void ExtractMapping (const uint8_t * buf, size_t len, std::map<std::string, std::string>& mapping);
void SendSessionStatusMessage (uint8_t status);
void SendHostReplyMessage (uint32_t requestID, std::shared_ptr<const i2p::data::IdentityEx> identity);
private: private:
@ -69,6 +147,9 @@ namespace client
size_t m_NextMessageLen, m_NextMessageOffset; size_t m_NextMessageLen, m_NextMessageOffset;
std::shared_ptr<I2CPDestination> m_Destination; std::shared_ptr<I2CPDestination> m_Destination;
uint16_t m_SessionID;
uint32_t m_MessageID;
bool m_IsSendAccepted;
}; };
typedef void (I2CPSession::*I2CPMessageHandler)(const uint8_t * buf, size_t len); typedef void (I2CPSession::*I2CPMessageHandler)(const uint8_t * buf, size_t len);
@ -77,10 +158,30 @@ namespace client
public: public:
I2CPServer (const std::string& interface, int port); I2CPServer (const std::string& interface, int port);
~I2CPServer ();
void Start ();
void Stop ();
boost::asio::io_service& GetService () { return m_Service; };
void RemoveSession (uint16_t sessionID);
private:
void Run ();
void Accept ();
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
private: private:
I2CPMessageHandler m_MessagesHandlers[256]; I2CPMessageHandler m_MessagesHandlers[256];
std::map<uint16_t, std::shared_ptr<I2CPSession> > m_Sessions;
bool m_IsRunning;
std::thread * m_Thread;
boost::asio::io_service m_Service;
boost::asio::ip::tcp::acceptor m_Acceptor;
public: public:

28
I2PService.cpp

@ -3,7 +3,6 @@
#include "ClientContext.h" #include "ClientContext.h"
#include "I2PService.h" #include "I2PService.h"
namespace i2p namespace i2p
{ {
namespace client namespace client
@ -28,7 +27,7 @@ namespace client
m_LocalDestination->CreateStream (streamRequestComplete, identHash, port); m_LocalDestination->CreateStream (streamRequestComplete, identHash, port);
else else
{ {
LogPrint (eLogWarning, "I2PService: Remote destination ", dest, " not found"); LogPrint (eLogWarning, "I2PService: Remote destination not found: ", dest);
streamRequestComplete (nullptr); streamRequestComplete (nullptr);
} }
} }
@ -71,7 +70,7 @@ namespace client
std::bind(&TCPIPPipe::HandleUpstreamReceived, shared_from_this(), std::bind(&TCPIPPipe::HandleUpstreamReceived, shared_from_this(),
std::placeholders::_1, std::placeholders::_2)); std::placeholders::_1, std::placeholders::_2));
} else { } else {
LogPrint(eLogError, "TCPIPPipe: no upstream socket for read"); LogPrint(eLogError, "TCPIPPipe: upstream receive: no socket");
} }
} }
@ -82,14 +81,14 @@ namespace client
std::bind(&TCPIPPipe::HandleDownstreamReceived, shared_from_this(), std::bind(&TCPIPPipe::HandleDownstreamReceived, shared_from_this(),
std::placeholders::_1, std::placeholders::_2)); std::placeholders::_1, std::placeholders::_2));
} else { } else {
LogPrint(eLogError, "TCPIPPipe: no downstream socket for read"); LogPrint(eLogError, "TCPIPPipe: downstream receive: no socket");
} }
} }
void TCPIPPipe::UpstreamWrite(const uint8_t * buf, size_t len) void TCPIPPipe::UpstreamWrite(const uint8_t * buf, size_t len)
{ {
if (m_up) { if (m_up) {
LogPrint(eLogDebug, "TCPIPPipe: write upstream ", (int)len); LogPrint(eLogDebug, "TCPIPPipe: upstream: ", (int) len, " bytes written");
boost::asio::async_write(*m_up, boost::asio::buffer(buf, len), boost::asio::async_write(*m_up, boost::asio::buffer(buf, len),
boost::asio::transfer_all(), boost::asio::transfer_all(),
std::bind(&TCPIPPipe::HandleUpstreamWrite, std::bind(&TCPIPPipe::HandleUpstreamWrite,
@ -97,14 +96,14 @@ namespace client
std::placeholders::_1) std::placeholders::_1)
); );
} else { } else {
LogPrint(eLogError, "tcpip pipe upstream socket null"); LogPrint(eLogError, "TCPIPPipe: upstream write: no socket");
} }
} }
void TCPIPPipe::DownstreamWrite(const uint8_t * buf, size_t len) void TCPIPPipe::DownstreamWrite(const uint8_t * buf, size_t len)
{ {
if (m_down) { if (m_down) {
LogPrint(eLogDebug, "TCPIPPipe: write downstream ", (int)len); LogPrint(eLogDebug, "TCPIPPipe: downstream: ", (int) len, " bytes written");
boost::asio::async_write(*m_down, boost::asio::buffer(buf, len), boost::asio::async_write(*m_down, boost::asio::buffer(buf, len),
boost::asio::transfer_all(), boost::asio::transfer_all(),
std::bind(&TCPIPPipe::HandleDownstreamWrite, std::bind(&TCPIPPipe::HandleDownstreamWrite,
@ -112,16 +111,16 @@ namespace client
std::placeholders::_1) std::placeholders::_1)
); );
} else { } else {
LogPrint(eLogError, "tcpip pipe downstream socket null"); LogPrint(eLogError, "TCPIPPipe: downstream write: no socket");
} }
} }
void TCPIPPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) void TCPIPPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered)
{ {
LogPrint(eLogDebug, "TCPIPPipe downstream got ", (int) bytes_transfered); LogPrint(eLogDebug, "TCPIPPipe: downstream: ", (int) bytes_transfered, " bytes received");
if (ecode) { if (ecode) {
LogPrint(eLogError, "TCPIPPipe Downstream read error:" , ecode.message()); LogPrint(eLogError, "TCPIPPipe: downstream read error:" , ecode.message());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate(); Terminate();
} else { } else {
@ -135,7 +134,7 @@ namespace client
void TCPIPPipe::HandleDownstreamWrite(const boost::system::error_code & ecode) { void TCPIPPipe::HandleDownstreamWrite(const boost::system::error_code & ecode) {
if (ecode) { if (ecode) {
LogPrint(eLogError, "TCPIPPipe Downstream write error:" , ecode.message()); LogPrint(eLogError, "TCPIPPipe: downstream write error:" , ecode.message());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate(); Terminate();
} }
@ -143,7 +142,7 @@ namespace client
void TCPIPPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) { void TCPIPPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) {
if (ecode) { if (ecode) {
LogPrint(eLogError, "TCPIPPipe Upstream write error:" , ecode.message()); LogPrint(eLogError, "TCPIPPipe: upstream write error:" , ecode.message());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate(); Terminate();
} }
@ -151,9 +150,9 @@ namespace client
void TCPIPPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) void TCPIPPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered)
{ {
LogPrint(eLogDebug, "TCPIPPipe upstream got ", (int) bytes_transfered); LogPrint(eLogDebug, "TCPIPPipe: upstream ", (int)bytes_transfered, " bytes received");
if (ecode) { if (ecode) {
LogPrint(eLogError, "TCPIPPipe Upstream read error:" , ecode.message()); LogPrint(eLogError, "TCPIPPipe: upstream read error:" , ecode.message());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate(); Terminate();
} else { } else {
@ -206,6 +205,5 @@ namespace client
LogPrint (eLogError, "I2PService: ", GetName(), " closing socket on accept because: ", ecode.message ()); LogPrint (eLogError, "I2PService: ", GetName(), " closing socket on accept because: ", ecode.message ());
} }
} }
} }
} }

2
Identity.h

@ -179,9 +179,7 @@ namespace data
virtual ~LocalDestination() {}; virtual ~LocalDestination() {};
virtual const uint8_t * GetEncryptionPrivateKey () const = 0; virtual const uint8_t * GetEncryptionPrivateKey () const = 0;
virtual const uint8_t * GetEncryptionPublicKey () const = 0;
virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0; virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0;
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); }; const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
}; };

9
LeaseSet.cpp

@ -213,6 +213,7 @@ namespace data
m_Buffer[offset] = num; m_Buffer[offset] = num;
offset++; offset++;
// leases // leases
m_Leases = m_Buffer + offset;
auto currentTime = i2p::util::GetMillisecondsSinceEpoch (); auto currentTime = i2p::util::GetMillisecondsSinceEpoch ();
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
{ {
@ -231,6 +232,14 @@ namespace data
// we don't sign it yet. must be signed later on // we don't sign it yet. must be signed later on
} }
LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len):
m_ExpirationTime (0), m_Identity (identity)
{
m_BufferLen = len;
m_Buffer = new uint8_t[m_BufferLen];
memcpy (m_Buffer, buf, len);
}
bool LocalLeaseSet::IsExpired () const bool LocalLeaseSet::IsExpired () const
{ {
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();

8
LeaseSet.h

@ -4,6 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
#include <vector> #include <vector>
#include <set>
#include <memory> #include <memory>
#include "Identity.h" #include "Identity.h"
@ -88,14 +89,19 @@ namespace data
public: public:
LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * encryptionPublicKey, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels); LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * encryptionPublicKey, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len);
~LocalLeaseSet () { delete[] m_Buffer; }; ~LocalLeaseSet () { delete[] m_Buffer; };
const uint8_t * GetBuffer () const { return m_Buffer; }; const uint8_t * GetBuffer () const { return m_Buffer; };
uint8_t * GetSignature () { return m_Buffer + m_BufferLen - GetSignatureLen (); }; uint8_t * GetSignature () { return m_Buffer + m_BufferLen - GetSignatureLen (); };
size_t GetBufferLen () const { return m_BufferLen; }; size_t GetBufferLen () const { return m_BufferLen; };
size_t GetSignatureLen () const { return m_Identity->GetSignatureLen (); }; size_t GetSignatureLen () const { return m_Identity->GetSignatureLen (); };
uint8_t * GetLeases () { return m_Leases; };
const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); }; const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); };
bool IsExpired () const; bool IsExpired () const;
uint64_t GetExpirationTime () const { return m_ExpirationTime; };
void SetExpirationTime (uint64_t expirationTime) { m_ExpirationTime = expirationTime; };
bool operator== (const LeaseSet& other) const bool operator== (const LeaseSet& other) const
{ return m_BufferLen == other.GetBufferLen () && !memcmp (other.GetBuffer (), other.GetBuffer (), m_BufferLen); }; { return m_BufferLen == other.GetBufferLen () && !memcmp (other.GetBuffer (), other.GetBuffer (), m_BufferLen); };
@ -104,7 +110,7 @@ namespace data
uint64_t m_ExpirationTime; // in milliseconds uint64_t m_ExpirationTime; // in milliseconds
std::shared_ptr<const IdentityEx> m_Identity; std::shared_ptr<const IdentityEx> m_Identity;
uint8_t * m_Buffer; uint8_t * m_Buffer, * m_Leases;
size_t m_BufferLen; size_t m_BufferLen;
}; };
} }

20
Log.cpp

@ -12,7 +12,7 @@ namespace i2p {
namespace log { namespace log {
Log logger; Log logger;
/** /**
* @enum Maps our loglevel to their symbolic name * @brief Maps our loglevel to their symbolic name
*/ */
static const char * g_LogLevelStr[eNumLogLevels] = static const char * g_LogLevelStr[eNumLogLevels] =
{ {
@ -56,7 +56,7 @@ namespace log {
#endif #endif
case eLogFile: case eLogFile:
case eLogStream: case eLogStream:
m_LogStream->flush(); if (m_LogStream) m_LogStream->flush();
break; break;
default: default:
/* do nothing */ /* do nothing */
@ -107,10 +107,11 @@ namespace log {
#endif #endif
case eLogFile: case eLogFile:
case eLogStream: case eLogStream:
*m_LogStream << TimeAsString(msg->timestamp) if (m_LogStream)
<< "@" << short_tid *m_LogStream << TimeAsString(msg->timestamp)
<< "/" << g_LogLevelStr[msg->level] << "@" << short_tid
<< " - " << msg->text << std::endl; << "/" << g_LogLevelStr[msg->level]
<< " - " << msg->text << std::endl;
break; break;
case eLogStdout: case eLogStdout:
default: default:
@ -130,10 +131,13 @@ namespace log {
Process(); Process();
} }
void Log::SendTo (const std::string& path) { void Log::SendTo (const std::string& path)
{
if (m_LogStream) m_LogStream = nullptr; // close previous
auto flags = std::ofstream::out | std::ofstream::app; auto flags = std::ofstream::out | std::ofstream::app;
auto os = std::make_shared<std::ofstream> (path, flags); auto os = std::make_shared<std::ofstream> (path, flags);
if (os->is_open ()) { if (os->is_open ())
{
m_Logfile = path; m_Logfile = path;
m_Destination = eLogFile; m_Destination = eLogFile;
m_LogStream = os; m_LogStream = os;

7
Log.h

@ -86,7 +86,7 @@ namespace log {
LogLevel GetLogLevel () { return m_MinLevel; }; LogLevel GetLogLevel () { return m_MinLevel; };
/** /**
* @brief Sets minimal alloed level for log messages * @brief Sets minimal allowed level for log messages
* @param level String with wanted minimal msg level * @param level String with wanted minimal msg level
*/ */
void SetLogLevel (const std::string& level); void SetLogLevel (const std::string& level);
@ -101,7 +101,7 @@ namespace log {
* @brief Sets log destination to given output stream * @brief Sets log destination to given output stream
* @param os Output stream * @param os Output stream
*/ */
void SendTo (std::shared_ptr<std::ostream> s); void SendTo (std::shared_ptr<std::ostream> os);
#ifndef _WIN32 #ifndef _WIN32
/** /**
@ -129,7 +129,8 @@ namespace log {
}; };
/** /**
* @struct Log message container * @struct LogMsg
* @brief Log message container
* *
* We creating it somewhere with LogPrint(), * We creating it somewhere with LogPrint(),
* then put in MsgQueue for later processing. * then put in MsgQueue for later processing.

5
Makefile

@ -76,6 +76,7 @@ $(ARLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
clean: clean:
rm -rf obj rm -rf obj
rm -rf docs/generated
$(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT) $(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB) strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB)
@ -86,9 +87,13 @@ dist:
git archive --format=tar.gz -9 --worktree-attributes \ git archive --format=tar.gz -9 --worktree-attributes \
--prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz --prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz
doxygen:
doxygen -s docs/Doxyfile
.PHONY: all .PHONY: all
.PHONY: clean .PHONY: clean
.PHONY: deps .PHONY: deps
.PHONY: doxygen
.PHONY: dist .PHONY: dist
.PHONY: api .PHONY: api
.PHONY: api_client .PHONY: api_client

2
Makefile.bsd

@ -9,4 +9,4 @@ CXXFLAGS = -O2
NEEDED_CXXFLAGS = -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 NEEDED_CXXFLAGS = -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
INCFLAGS = -I/usr/include/ -I/usr/local/include/ INCFLAGS = -I/usr/include/ -I/usr/local/include/
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread

2
Makefile.homebrew

@ -6,7 +6,7 @@ CXX = clang++
CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX
INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include
LDFLAGS = -L${SSLROOT}/lib -L${BOOSTROOT}/lib LDFLAGS = -L${SSLROOT}/lib -L${BOOSTROOT}/lib
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
ifeq ($(USE_UPNP),1) ifeq ($(USE_UPNP),1)
LDFLAGS += -ldl LDFLAGS += -ldl

5
Makefile.linux

@ -1,5 +1,5 @@
# set defaults instead redefine # set defaults instead redefine
CXXFLAGS ?= -g -Wall CXXFLAGS ?= -g -Wall -Wextra -Wno-unused-parameter -pedantic
INCFLAGS ?= INCFLAGS ?=
## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time ## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time
@ -32,7 +32,6 @@ ifeq ($(USE_STATIC),yes)
LDLIBS = $(LIBDIR)/libboost_system.a LDLIBS = $(LIBDIR)/libboost_system.a
LDLIBS += $(LIBDIR)/libboost_date_time.a LDLIBS += $(LIBDIR)/libboost_date_time.a
LDLIBS += $(LIBDIR)/libboost_filesystem.a LDLIBS += $(LIBDIR)/libboost_filesystem.a
LDLIBS += $(LIBDIR)/libboost_regex.a
LDLIBS += $(LIBDIR)/libboost_program_options.a LDLIBS += $(LIBDIR)/libboost_program_options.a
LDLIBS += $(LIBDIR)/libcrypto.a LDLIBS += $(LIBDIR)/libcrypto.a
LDLIBS += $(LIBDIR)/libssl.a LDLIBS += $(LIBDIR)/libssl.a
@ -40,7 +39,7 @@ ifeq ($(USE_STATIC),yes)
LDLIBS += -lpthread -static-libstdc++ -static-libgcc LDLIBS += -lpthread -static-libstdc++ -static-libgcc
USE_AESNI := no USE_AESNI := no
else else
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
endif endif
# UPNP Support (miniupnpc 1.5 or 1.6) # UPNP Support (miniupnpc 1.5 or 1.6)

1
Makefile.mingw

@ -13,7 +13,6 @@ LDLIBS = \
-Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_regex$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_program_options$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_program_options$(BOOST_SUFFIX) \
-Wl,-Bstatic -lssl \ -Wl,-Bstatic -lssl \
-Wl,-Bstatic -lcrypto \ -Wl,-Bstatic -lcrypto \

2
Makefile.osx vendored

@ -3,7 +3,7 @@ CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX
#CXXFLAGS = -g -O2 -Wall -std=c++11 #CXXFLAGS = -g -O2 -Wall -std=c++11
INCFLAGS = -I/usr/local/include -I/usr/local/ssl/include INCFLAGS = -I/usr/local/include -I/usr/local/ssl/include
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -L/usr/local/ssl/lib LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -L/usr/local/ssl/lib
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
ifeq ($(USE_UPNP),1) ifeq ($(USE_UPNP),1)
LDFLAGS += -ldl LDFLAGS += -ldl

3
NetDb.cpp

@ -849,7 +849,8 @@ namespace data
template<typename Filter> template<typename Filter>
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (Filter filter) const std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (Filter filter) const
{ {
if (!m_RouterInfos.size ()) return 0; if (m_RouterInfos.empty())
return 0;
uint32_t ind = rand () % m_RouterInfos.size (); uint32_t ind = rand () % m_RouterInfos.size ();
for (int j = 0; j < 2; j++) for (int j = 0; j < 2; j++)
{ {

1
Reseed.cpp

@ -1,7 +1,6 @@
#include <string.h> #include <string.h>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <boost/regex.hpp>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/ssl.hpp> #include <boost/asio/ssl.hpp>
#include <openssl/ssl.h> #include <openssl/ssl.h>

2
RouterInfo.cpp

@ -353,7 +353,7 @@ namespace data
if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
if (m_Caps & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable if (m_Caps & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
SetProperty ("caps", caps.c_str ()); SetProperty ("caps", caps);
} }
void RouterInfo::WriteToStream (std::ostream& s) void RouterInfo::WriteToStream (std::ostream& s)

11
Streaming.cpp

@ -232,6 +232,11 @@ namespace stream
bool acknowledged = false; bool acknowledged = false;
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
uint32_t ackThrough = packet->GetAckThrough (); uint32_t ackThrough = packet->GetAckThrough ();
if (ackThrough > m_SequenceNumber)
{
LogPrint (eLogError, "Streaming: Unexpected ackThrough=", ackThrough, " > seqn=", m_SequenceNumber);
return;
}
int nackCount = packet->GetNACKCount (); int nackCount = packet->GetNACKCount ();
for (auto it = m_SentPackets.begin (); it != m_SentPackets.end ();) for (auto it = m_SentPackets.begin (); it != m_SentPackets.end ();)
{ {
@ -336,9 +341,9 @@ namespace stream
htobe32buf (packet + size, m_SequenceNumber++); htobe32buf (packet + size, m_SequenceNumber++);
size += 4; // sequenceNum size += 4; // sequenceNum
if (isNoAck) if (isNoAck)
htobe32buf (packet + size, m_LastReceivedSequenceNumber);
else
htobuf32 (packet + size, 0); htobuf32 (packet + size, 0);
else
htobe32buf (packet + size, m_LastReceivedSequenceNumber);
size += 4; // ack Through size += 4; // ack Through
packet[size] = 0; packet[size] = 0;
size++; // NACK count size++; // NACK count
@ -521,7 +526,7 @@ namespace stream
size += 4; // receiveStreamID size += 4; // receiveStreamID
htobe32buf (packet + size, m_SequenceNumber++); htobe32buf (packet + size, m_SequenceNumber++);
size += 4; // sequenceNum size += 4; // sequenceNum
htobe32buf (packet + size, m_LastReceivedSequenceNumber); htobe32buf (packet + size, m_LastReceivedSequenceNumber >= 0 ? m_LastReceivedSequenceNumber : 0);
size += 4; // ack Through size += 4; // ack Through
packet[size] = 0; packet[size] = 0;
size++; // NACK count size++; // NACK count

2
Transports.cpp

@ -606,7 +606,7 @@ namespace transport
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer () const std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer () const
{ {
if (!m_Peers.size ()) return nullptr; if (m_Peers.empty ()) return nullptr;
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
auto it = m_Peers.begin (); auto it = m_Peers.begin ();
std::advance (it, rand () % m_Peers.size ()); std::advance (it, rand () % m_Peers.size ());

2
Tunnel.cpp

@ -358,7 +358,7 @@ namespace tunnel
std::shared_ptr<OutboundTunnel> Tunnels::GetNextOutboundTunnel () std::shared_ptr<OutboundTunnel> Tunnels::GetNextOutboundTunnel ()
{ {
if (!m_OutboundTunnels.size ()) return nullptr; if (m_OutboundTunnels.empty ()) return nullptr;
uint32_t ind = rand () % m_OutboundTunnels.size (), i = 0; uint32_t ind = rand () % m_OutboundTunnels.size (), i = 0;
std::shared_ptr<OutboundTunnel> tunnel; std::shared_ptr<OutboundTunnel> tunnel;
for (auto it: m_OutboundTunnels) for (auto it: m_OutboundTunnels)

2
Tunnel.h

@ -73,7 +73,7 @@ namespace tunnel
bool HandleTunnelBuildResponse (uint8_t * msg, size_t len); bool HandleTunnelBuildResponse (uint8_t * msg, size_t len);
virtual void Print (std::stringstream& s) const {}; virtual void Print (std::stringstream&) const {};
// implements TunnelBase // implements TunnelBase
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);

2
appveyor.yml

@ -125,7 +125,7 @@ install:
- cd %BOOST_ROOT% - cd %BOOST_ROOT%
- if defined msvc if not exist "stage%bitness%\lib\%boostlib%boost_system-vc%msvc%0-mt%boostdbg%*" ( - if defined msvc if not exist "stage%bitness%\lib\%boostlib%boost_system-vc%msvc%0-mt%boostdbg%*" (
bootstrap > c:\projects\instdir\build_boost.log bootstrap > c:\projects\instdir\build_boost.log
&& b2 toolset=msvc-%msvc%.0 %boost_variant% link=%type% runtime-link=%type% address-model=%bitness% --build-type=minimal --with-filesystem --with-program_options --with-regex --with-date_time --stagedir=stage%bitness% >> c:\projects\instdir\build_boost.log && b2 toolset=msvc-%msvc%.0 %boost_variant% link=%type% runtime-link=%type% address-model=%bitness% --build-type=minimal --with-filesystem --with-program_options --with-date_time --stagedir=stage%bitness% >> c:\projects\instdir\build_boost.log
|| type c:\projects\instdir\build_boost.log || type c:\projects\instdir\build_boost.log
) )
- if defined msvc if not exist C:\stage\OpenSSL-Win%bitness%-vc%msvc%-%type%\ ( - if defined msvc if not exist C:\stage\OpenSSL-Win%bitness%-vc%msvc%-%type%\ (

2
build/CMakeLists.txt

@ -242,7 +242,7 @@ endif()
target_link_libraries(i2pdclient libi2pd) target_link_libraries(i2pdclient libi2pd)
find_package ( Boost COMPONENTS system filesystem regex program_options date_time REQUIRED ) find_package ( Boost COMPONENTS system filesystem program_options date_time REQUIRED )
if(NOT DEFINED Boost_INCLUDE_DIRS) if(NOT DEFINED Boost_INCLUDE_DIRS)
message(SEND_ERROR "Boost is not found, or your boost version was bellow 1.46. Please download Boost!") message(SEND_ERROR "Boost is not found, or your boost version was bellow 1.46. Please download Boost!")
endif() endif()

2
build/Dockerfile

@ -1,7 +1,7 @@
FROM ubuntu FROM ubuntu
RUN apt-get update && apt-get install -y libboost-dev libboost-filesystem-dev \ RUN apt-get update && apt-get install -y libboost-dev libboost-filesystem-dev \
libboost-program-options-dev libboost-regex-dev libboost-date-time-dev \ libboost-program-options-dev libboost-date-time-dev \
libssl-dev git build-essential libssl-dev git build-essential
RUN git clone https://github.com/PurpleI2P/i2pd.git RUN git clone https://github.com/PurpleI2P/i2pd.git

6
debian/changelog vendored

@ -1,3 +1,9 @@
i2pd (2.7.0-1) unstable; urgency=low
* updated to version 2.7.0/0.9.25
-- hagen <hagen@i2pmail.org> Wed, 18 May 2016 01:11:04 +0000
i2pd (2.2.0-2) unstable; urgency=low i2pd (2.2.0-2) unstable; urgency=low
* updated to version 2.2.0 * updated to version 2.2.0

1
debian/control vendored

@ -4,7 +4,6 @@ Priority: extra
Maintainer: hagen <hagen@i2pmail.org> Maintainer: hagen <hagen@i2pmail.org>
Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~), Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~),
gcc (>= 4.7) | clang (>= 3.3), gcc (>= 4.7) | clang (>= 3.3),
libboost-regex-dev,
libboost-system-dev (>= 1.46), libboost-system-dev (>= 1.46),
libboost-date-time-dev, libboost-date-time-dev,
libboost-filesystem-dev, libboost-filesystem-dev,

1
debian/i2pd.default vendored

@ -4,6 +4,7 @@
I2PD_ENABLED="yes" I2PD_ENABLED="yes"
# port to listen for incoming connections # port to listen for incoming connections
# comment this line if you want to use value from config
I2PD_PORT="4567" I2PD_PORT="4567"
# Additional options that are passed to the Daemon. # Additional options that are passed to the Daemon.

6
debian/i2pd.init vendored

@ -41,6 +41,10 @@ do_start()
return 2 return 2
fi fi
if [ -n "$I2PD_PORT" ]; then
DAEMON_OPTS="--port $I2PD_PORT $DAEMON_OPTS"
fi
touch "$PIDFILE" touch "$PIDFILE"
chown -f $USER:adm "$PIDFILE" chown -f $USER:adm "$PIDFILE"
@ -51,7 +55,7 @@ do_start()
|| return 1 || return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" -- \ start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" -- \
--service --daemon --log=file --logfile=$LOGFILE --conf=$I2PCONF --tunconf=$TUNCONF \ --service --daemon --log=file --logfile=$LOGFILE --conf=$I2PCONF --tunconf=$TUNCONF \
--port=$I2PD_PORT $DAEMON_OPTS > /dev/null 2>&1 \ $DAEMON_OPTS > /dev/null 2>&1 \
|| return 2 || return 2
return $? return $?
} }

41
debian/i2pd.openrc vendored

@ -0,0 +1,41 @@
#!/sbin/openrc-run
pidfile="/var/run/i2pd.pid"
logfile="/var/log/i2pd.log"
mainconf="/etc/i2pd/i2pd.conf"
tunconf="/etc/i2pd/tunnels.conf"
name="i2pd"
command="/usr/sbin/i2pd"
command_args="--service --daemon --log=file --logfile=$logfile --conf=$mainconf --tunconf=$tunconf --pidfile=$pidfile"
description="i2p router written in C++"
required_dirs="/var/lib/i2pd"
required_files="$mainconf"
start_stop_daemon_args="--chuid i2pd"
depend() {
need mountall
use net
after bootmisc
}
start_pre() {
if [ -r /etc/default/i2pd ]; then
. /etc/default/i2pd
fi
if [ "x$I2PD_ENABLED" != "xyes" ]; then
ewarn "i2pd disabled in /etc/default/i2pd"
exit 1
fi
checkpath -f -o i2pd:adm $logfile
checkpath -f -o i2pd:adm $pidfile
if [ -n "$I2PD_PORT" -a "$I2PD_PORT" -gt 0 ]; then
command_args="$command_args --port=$I2PD_PORT"
fi
if [ -n "$DAEMON_OPTS" ]; then
command_args="$command_args $DAEMON_OPTS"
fi
}

259
docs/Doxyfile

@ -0,0 +1,259 @@
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "i2pd"
PROJECT_NUMBER =
PROJECT_BRIEF = "load-balanced unspoofable packet switching network"
PROJECT_LOGO =
OUTPUT_DIRECTORY = docs/generated
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF =
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES =
TCL_SUBST =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTORS_1ST = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_FILES = YES
SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
LAYOUT_FILE =
CITE_BIB_FILES =
QUIET = YES
WARNINGS = YES
WARN_IF_UNDOCUMENTED = NO
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
INPUT =
INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.cpp *.h
RECURSIVE = NO
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = NO
CLANG_ASSISTED_PARSING = NO
CLANG_OPTIONS =
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = YES
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
GENERATE_QHP = NO
QCH_FILE =
QHP_NAMESPACE = org.doxygen.Project
QHP_VIRTUAL_FOLDER = doc
QHP_CUST_FILTER_NAME =
QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
GENERATE_TREEVIEW = NO
ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
USE_MATHJAX = NO
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
MATHJAX_EXTENSIONS =
MATHJAX_CODEFILE =
SEARCHENGINE = YES
SERVER_BASED_SEARCH = NO
EXTERNAL_SEARCH = NO
SEARCHENGINE_URL =
SEARCHDATA_FILE = searchdata.xml
EXTERNAL_SEARCH_ID =
EXTRA_SEARCH_MAPPINGS =
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_SUBDIR =
MAN_LINKS = NO
GENERATE_XML = NO
XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
DOCBOOK_PROGRAMLISTING = NO
GENERATE_AUTOGEN_DEF = NO
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
PERL_PATH = /usr/bin/perl
CLASS_DIAGRAMS = YES
MSCGEN_PATH =
DIA_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
DOT_NUM_THREADS = 0
DOT_FONTNAME = Helvetica
DOT_FONTSIZE = 10
DOT_FONTPATH =
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
INTERACTIVE_SVG = NO
DOT_PATH =
DOTFILE_DIRS =
MSCFILE_DIRS =
DIAFILE_DIRS =
PLANTUML_JAR_PATH =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES

2
docs/build_notes_cross.md

@ -22,7 +22,7 @@ Proceed with building Boost normal way, but let's define dedicated staging direc
```sh ```sh
./bootstrap.sh ./bootstrap.sh
./b2 toolset=gcc-mingw target-os=windows variant=release link=static runtime-link=static address-model=64 \ ./b2 toolset=gcc-mingw target-os=windows variant=release link=static runtime-link=static address-model=64 \
--build-type=minimal --with-filesystem --with-program_options --with-regex --with-date_time \ --build-type=minimal --with-filesystem --with-program_options --with-date_time \
--stagedir=stage-mingw-64 --stagedir=stage-mingw-64
cd .. cd ..
``` ```

1
docs/build_notes_unix.md

@ -46,7 +46,6 @@ sudo apt-get install \
libboost-date-time-dev \ libboost-date-time-dev \
libboost-filesystem-dev \ libboost-filesystem-dev \
libboost-program-options-dev \ libboost-program-options-dev \
libboost-regex-dev \
libboost-system-dev \ libboost-system-dev \
libboost-thread-dev \ libboost-thread-dev \
libssl-dev libssl-dev

4
docs/build_notes_windows.md

@ -110,11 +110,11 @@ prompt to build Boost) and run the following:
cd C:\dev\boost cd C:\dev\boost
bootstrap bootstrap
b2 toolset=msvc-12.0 --build-type=complete --with-filesystem --with-program_options --with-regex --with-date_time b2 toolset=msvc-12.0 --build-type=complete --with-filesystem --with-program_options --with-date_time
If you are on 64-bit Windows and you want to build 64-bit version as well If you are on 64-bit Windows and you want to build 64-bit version as well
b2 toolset=msvc-12.0 --build-type=complete --stagedir=stage64 address-model=64 --with-filesystem --with-program_options --with-regex --with-date_time b2 toolset=msvc-12.0 --build-type=complete --stagedir=stage64 address-model=64 --with-filesystem --with-program_options --with-date_time
After Boost is compiled, set the environment variable `BOOST_ROOT` to After Boost is compiled, set the environment variable `BOOST_ROOT` to
the directory Boost was unpacked to, e.g., C:\dev\boost. the directory Boost was unpacked to, e.g., C:\dev\boost.

6
docs/configuration.md

@ -58,7 +58,11 @@ All options below still possible in cmdline, but better write it in config file:
* --bob.address= - The address to listen on (BOB command channel) * --bob.address= - The address to listen on (BOB command channel)
* --bob.port= - Port of BOB command channel. Usually 2827. BOB is off if not specified * --bob.port= - Port of BOB command channel. Usually 2827. BOB is off if not specified
* --sam.enabled= - If BOB is enabled. false by default * --bob.enabled= - If BOB is enabled. false by default
* --i2cp.address= - The address to listen on
* --i2cp.port= - Port of I2CP server. Usually 7654. IPCP is off if not specified
* --i2cp.enabled= - If I2CP is enabled. false by default. Other services don't requeire I2CP
* --i2pcontrol.address= - The address to listen on (I2P control service) * --i2pcontrol.address= - The address to listen on (I2P control service)
* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified * --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified

BIN
docs/itoopieImage.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

1
stdafx.h

@ -33,7 +33,6 @@
#include <mutex> #include <mutex>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/regex.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/date_time/local_time/local_time.hpp> #include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>

3
tests/Makefile

@ -1,6 +1,7 @@
CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
TESTS = test-http-url test-http-req test-http-res test-http-url_decode TESTS = test-http-url test-http-req test-http-res test-http-url_decode \
test-http-merge_chunked
all: $(TESTS) run all: $(TESTS) run

25
tests/test-http-merge_chunked.cpp

@ -0,0 +1,25 @@
#include <cassert>
#include "../HTTP.h"
using namespace i2p::http;
int main() {
const char *buf =
"4\r\n"
"HTTP\r\n"
"A\r\n"
" response \r\n"
"E\r\n"
"with \r\n"
"chunks.\r\n"
"0\r\n"
"\r\n"
;
std::stringstream in(buf);
std::stringstream out;
assert(MergeChunkedResponse(in, out) == true);
assert(out.str() == "HTTP response with \r\nchunks.");
return 0;
}

2
version.h

@ -16,7 +16,7 @@
#define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MAJOR 0
#define I2P_VERSION_MINOR 9 #define I2P_VERSION_MINOR 9
#define I2P_VERSION_MICRO 25 #define I2P_VERSION_MICRO 26
#define I2P_VERSION_PATCH 0 #define I2P_VERSION_PATCH 0
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)

Loading…
Cancel
Save