diff --git a/ChangeLog b/ChangeLog index 347c8bf2..d3d30a91 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,20 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.13.0] - 2017-04-06 +### Added +- Persist local destination's tags +- GOST signature types 9 and 10 +- Exploratory tunnels configuration +### Changed +- Reseed servers list +- Inactive NTCP sockets get closed faster +- Some EdDSA speed up +### Fixed +- Multiple acceptors for SAM +- Follow on data after STREAM CREATE for SAM +- Memory leaks + ## [2.12.0] - 2017-02-14 ### Added - Additional HTTP and SOCKS proxy tunnels diff --git a/Crypto.h b/Crypto.h index 16a4da3c..cb0152ba 100644 --- a/Crypto.h +++ b/Crypto.h @@ -289,13 +289,26 @@ namespace crypto #if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL // define getters and setters introduced in 1.1.0 inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) - { d->p = p; d->q = q; d->g = g; return 1; } + { + if (d->p) BN_free (d->p); + if (d->q) BN_free (d->q); + if (d->g) BN_free (d->g); + d->p = p; d->q = q; d->g = g; return 1; + } inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) - { d->pub_key = pub_key; d->priv_key = priv_key; return 1; } + { + if (d->pub_key) BN_free (d->pub_key); + if (d->priv_key) BN_free (d->priv_key); + d->pub_key = pub_key; d->priv_key = priv_key; return 1; + } inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key) { *pub_key = d->pub_key; *priv_key = d->priv_key; } inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) - { sig->r = r; sig->s = s; return 1; } + { + if (sig->r) BN_free (sig->r); + if (sig->s) BN_free (sig->s); + sig->r = r; sig->s = s; return 1; + } inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) { *pr = sig->r; *ps = sig->s; } @@ -309,12 +322,22 @@ inline void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM { *pr = sig->r; *ps = sig->s; } inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) - { r->n = n; r->e = e; r->d = d; return 1; } + { + if (r->n) BN_free (r->n); + if (r->e) BN_free (r->e); + if (r->d) BN_free (r->d); + r->n = n; r->e = e; r->d = d; return 1; + } inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) { *n = r->n; *e = r->e; *d = r->d; } inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) - { dh->p = p; dh->q = q; dh->g = g; return 1; } + { + if (dh->p) BN_free (dh->p); + if (dh->q) BN_free (dh->q); + if (dh->g) BN_free (dh->g); + dh->p = p; dh->q = q; dh->g = g; return 1; + } inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) { if (dh->pub_key) BN_free (dh->pub_key); diff --git a/Destination.cpp b/Destination.cpp index 06fcf6b3..dd3edcf6 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -110,6 +110,7 @@ namespace client { if (!m_IsRunning) { + LoadTags (); m_IsRunning = true; m_Pool->SetLocalDestination (shared_from_this ()); m_Pool->SetActive (true); @@ -145,6 +146,7 @@ namespace client delete m_Thread; m_Thread = 0; } + SaveTags (); CleanUp (); // GarlicDestination return true; } diff --git a/FS.cpp b/FS.cpp index 64484b15..713d6ca6 100644 --- a/FS.cpp +++ b/FS.cpp @@ -16,6 +16,7 @@ #include "Base.h" #include "FS.h" #include "Log.h" +#include "Garlic.h" namespace i2p { namespace fs { @@ -93,6 +94,11 @@ namespace fs { std::string destinations = DataDirPath("destinations"); if (!boost::filesystem::exists(destinations)) boost::filesystem::create_directory(destinations); + std::string tags = DataDirPath("tags"); + if (!boost::filesystem::exists(tags)) + boost::filesystem::create_directory(tags); + else + i2p::garlic::CleanUpTagsFiles (); return true; } @@ -116,6 +122,14 @@ namespace fs { return boost::filesystem::exists(path); } + uint32_t GetLastUpdateTime (const std::string & path) + { + if (!boost::filesystem::exists(path)) return 0; + boost::system::error_code ec; + auto t = boost::filesystem::last_write_time (path, ec); + return ec ? 0 : t; + } + bool Remove(const std::string & path) { if (!boost::filesystem::exists(path)) return false; diff --git a/FS.h b/FS.h index c476aa63..cb9b632d 100644 --- a/FS.h +++ b/FS.h @@ -97,7 +97,7 @@ namespace fs { * @param files Vector to store found files * @return true on success and false if directory not exists */ - bool ReadDir(const std::string & path, std::vector & files); + bool ReadDir(const std::string & path, std::vector & files); /** * @brief Remove file with given path @@ -112,6 +112,8 @@ namespace fs { * @return true if file exists, false otherwise */ bool Exists(const std::string & path); + + uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch bool CreateDirectory (const std::string& path); diff --git a/Garlic.cpp b/Garlic.cpp index b2f64000..416b8f68 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -10,6 +10,7 @@ #include "Transports.h" #include "Timestamp.h" #include "Log.h" +#include "FS.h" #include "Garlic.h" namespace i2p @@ -412,9 +413,7 @@ namespace garlic if (key) { uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - auto decryption = std::make_shared(); - decryption->SetKey (key); - m_Tags[SessionTag(tag, ts)] = decryption; + m_Tags[SessionTag(tag, ts)] = std::make_shared(key); } } @@ -456,8 +455,7 @@ namespace garlic ElGamalBlock elGamal; if (length >= 514 && i2p::crypto::ElGamalDecrypt (GetEncryptionPrivateKey (), buf, (uint8_t *)&elGamal, m_Ctx, true)) { - auto decryption = std::make_shared(); - decryption->SetKey (elGamal.sessionKey); + auto decryption = std::make_shared(elGamal.sessionKey); uint8_t iv[32]; // IV is first 16 bytes SHA256(elGamal.preIV, 32, iv); decryption->SetIV (iv); @@ -469,7 +467,7 @@ namespace garlic } } - void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr decryption, + void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr decryption, std::shared_ptr from) { uint16_t tagCount = bufbe16toh (buf); @@ -714,5 +712,75 @@ namespace garlic HandleDeliveryStatusMessage (msg); } + void GarlicDestination::SaveTags () + { + if (m_Tags.empty ()) return; + std::string ident = GetIdentHash().ToBase32(); + std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags")); + std::ofstream f (path, std::ofstream::binary | std::ofstream::out | std::ofstream::trunc); + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + // 4 bytes timestamp, 32 bytes tag, 32 bytes key + for (auto it: m_Tags) + { + if (ts < it.first.creationTime + INCOMING_TAGS_EXPIRATION_TIMEOUT) + { + f.write ((char *)&it.first.creationTime, 4); + f.write ((char *)it.first.data (), 32); + f.write ((char *)it.second->GetKey ().data (), 32); + } + } + } + + void GarlicDestination::LoadTags () + { + std::string ident = GetIdentHash().ToBase32(); + std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags")); + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + if (ts < i2p::fs::GetLastUpdateTime (path) + INCOMING_TAGS_EXPIRATION_TIMEOUT) + { + // might contain non-expired tags + std::ifstream f (path, std::ifstream::binary); + if (f) + { + std::map > keys; + // 4 bytes timestamp, 32 bytes tag, 32 bytes key + while (!f.eof ()) + { + uint32_t t; + uint8_t tag[32], key[32]; + f.read ((char *)&t, 4); if (f.eof ()) break; + if (ts < t + INCOMING_TAGS_EXPIRATION_TIMEOUT) + { + f.read ((char *)tag, 32); + f.read ((char *)key, 32); + } + else + f.seekg (64, std::ios::cur); // skip + if (f.eof ()) break; + + std::shared_ptr decryption; + auto it = keys.find (key); + if (it != keys.end ()) + decryption = it->second; + else + decryption = std::make_shared(key); + m_Tags.insert (std::make_pair (SessionTag (tag, ts), decryption)); + } + if (!m_Tags.empty ()) + LogPrint (eLogInfo, m_Tags.size (), " loaded for ", ident); + } + } + i2p::fs::Remove (path); + } + + void CleanUpTagsFiles () + { + std::vector files; + i2p::fs::ReadDir (i2p::fs::DataDirPath("tags"), files); + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + for (auto it: files) + if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT) + i2p::fs::Remove (it); + } } } diff --git a/Garlic.h b/Garlic.h index 6cc37a7d..b78b89f9 100644 --- a/Garlic.h +++ b/Garlic.h @@ -59,6 +59,22 @@ namespace garlic uint32_t creationTime; // seconds since epoch }; + // AESDecryption is associated with session tags and store key + class AESDecryption: public i2p::crypto::CBCDecryption + { + public: + + AESDecryption (const uint8_t * key): m_Key (key) + { + SetKey (key); + } + const i2p::crypto::AESKey& GetKey () const { return m_Key; }; + + private: + + i2p::crypto::AESKey m_Key; + }; + struct GarlicRoutingPath { std::shared_ptr outboundTunnel; @@ -67,7 +83,7 @@ namespace garlic uint32_t updateTime; // seconds since epoch int numTimesUsed; }; - + class GarlicDestination; class GarlicRoutingSession: public std::enable_shared_from_this { @@ -180,10 +196,13 @@ namespace garlic void HandleGarlicMessage (std::shared_ptr msg); void HandleDeliveryStatusMessage (std::shared_ptr msg); - + + void SaveTags (); + void LoadTags (); + private: - void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr decryption, + void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr decryption, std::shared_ptr from); void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr from); @@ -195,7 +214,7 @@ namespace garlic std::mutex m_SessionsMutex; std::map m_Sessions; // incoming - std::map> m_Tags; + std::map > m_Tags; // DeliveryStatus std::mutex m_DeliveryStatusSessionsMutex; std::map m_DeliveryStatusSessions; // msgID -> session @@ -205,7 +224,10 @@ namespace garlic // for HTTP only size_t GetNumIncomingTags () const { return m_Tags.size (); } const decltype(m_Sessions)& GetSessions () const { return m_Sessions; }; - }; + }; + + void CleanUpTagsFiles (); + } } diff --git a/Win32/installer.iss b/Win32/installer.iss index 7ae21e39..dd3e1da4 100644 --- a/Win32/installer.iss +++ b/Win32/installer.iss @@ -1,5 +1,5 @@ #define I2Pd_AppName "i2pd" -#define I2Pd_ver "2.12.0" +#define I2Pd_ver "2.13.0" #define I2Pd_Publisher "PurpleI2P" [Setup] diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 2870dd29..3ff85fa8 100755 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,7 +2,7 @@ + android:versionName="2.13.0"> diff --git a/appveyor.yml b/appveyor.yml index e55edf39..cb4d3057 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.12.{build} +version: 2.13.{build} pull_requests: do_not_increment_build_number: true branches: diff --git a/debian/changelog b/debian/changelog index 5f745efa..4ffa1cf5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +i2pd (2.13.0-1) unstable; urgency=low + + * updated to version 2.13.0/0.9.29 + * updated debian/control + * renamed logrotate to i2pd.logrotate + * fixed init.d script + + -- orignal Tue, 6 Apr 2017 14:00:00 +0000 + i2pd (2.12.0-1) unstable; urgency=low * updated to version 2.12.0/0.9.28 diff --git a/debian/control b/debian/control index 87f31ccb..b41e4624 100644 --- a/debian/control +++ b/debian/control @@ -1,17 +1,10 @@ Source: i2pd Section: net -Priority: extra +Priority: optional Maintainer: R4SAS -Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~), - gcc (>= 4.7) | clang (>= 3.3), - libboost-system-dev (>= 1.46), - libboost-date-time-dev, - libboost-filesystem-dev, - libboost-program-options-dev, - libminiupnpc-dev, - libssl-dev -Standards-Version: 3.9.3 -Homepage: https://github.com/PurpleI2P/i2pd +Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), gcc (>= 4.7) | clang (>= 3.3), libboost-system-dev (>= 1.46), libboost-date-time-dev, libboost-filesystem-dev, libboost-program-options-dev, libminiupnpc-dev, libssl-dev +Standards-Version: 3.9.6 +Homepage: http://i2pd.website/ Vcs-Git: git://github.com/PurpleI2P/i2pd.git Vcs-Browser: https://github.com/PurpleI2P/i2pd.git @@ -19,26 +12,23 @@ Package: i2pd Architecture: any Pre-Depends: adduser Depends: ${shlibs:Depends}, ${misc:Depends} -Recommends: privoxy -Suggests: tor -Description: load-balanced unspoofable packet switching network - C++ port - I2P is an anonymizing network, offering a simple layer that identity-sensitive - applications can use to securely communicate. All data is wrapped with several - layers of encryption, and the network is both distributed and dynamic, with no - trusted parties. +Suggests: tor, privoxy +Description: i2pd is a full-featured C++ implementation of I2P client. + I2P (Invisible Internet Protocol) is a universal anonymous network layer. All + communications over I2P are anonymous and end-to-end encrypted, participants + don't reveal their real IP addresses. . - This package contains the port of the I2P router to C++. Unless willing - to test and report problems, you should install the 'i2p' package instead. + This package contains the full-featured C++ implementation of I2P router. Package: i2pd-dbg Architecture: any Priority: extra Section: debug Depends: i2pd (= ${binary:Version}), ${misc:Depends} +Suggests: gdb Description: i2pd debugging symbols - I2P is an anonymizing network, offering a simple layer that identity-sensitive - applications can use to securely communicate. All data is wrapped with several - layers of encryption, and the network is both distributed and dynamic, with no - trusted parties. + I2P (Invisible Internet Protocol) is a universal anonymous network layer. All + communications over I2P are anonymous and end-to-end encrypted, participants + don't reveal their real IP addresses. . This package contains symbols required for debugging. diff --git a/debian/logrotate b/debian/i2pd.logrotate similarity index 100% rename from debian/logrotate rename to debian/i2pd.logrotate diff --git a/qt/i2pd_qt/android/AndroidManifest.xml b/qt/i2pd_qt/android/AndroidManifest.xml index 75086b4a..dd5927b7 100644 --- a/qt/i2pd_qt/android/AndroidManifest.xml +++ b/qt/i2pd_qt/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + diff --git a/version.h b/version.h index 440ca0e8..178f8e05 100644 --- a/version.h +++ b/version.h @@ -7,7 +7,7 @@ #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 12 +#define I2PD_VERSION_MINOR 13 #define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)