diff --git a/Crypto.cpp b/Crypto.cpp index 94d1c4c6..6b5fb7d6 100644 --- a/Crypto.cpp +++ b/Crypto.cpp @@ -227,10 +227,8 @@ namespace crypto DHKeys::DHKeys (): m_IsUpdated (true) { m_DH = DH_new (); - m_DH->p = BN_dup (elgp); - m_DH->g = BN_dup (elgg); - m_DH->priv_key = NULL; - m_DH->pub_key = NULL; + DH_set0_pqg (m_DH, BN_dup (elgp), NULL, BN_dup (elgg)); + DH_set0_key (m_DH, NULL, NULL); } DHKeys::~DHKeys () @@ -240,27 +238,31 @@ namespace crypto void DHKeys::GenerateKeys (uint8_t * priv, uint8_t * pub) { - if (m_DH->priv_key) { BN_free (m_DH->priv_key); m_DH->priv_key = NULL; }; - if (m_DH->pub_key) { BN_free (m_DH->pub_key); m_DH->pub_key = NULL; }; + BIGNUM * priv_key = NULL, * pub_key = NULL; #if !defined(__x86_64__) // use short exponent for non x64 - m_DH->priv_key = BN_new (); - BN_rand (m_DH->priv_key, ELGAMAL_SHORT_EXPONENT_NUM_BITS, 0, 1); + priv_key = BN_new (); + BN_rand (priv_key, ELGAMAL_SHORT_EXPONENT_NUM_BITS, 0, 1); #endif if (g_ElggTable) { #if defined(__x86_64__) - m_DH->priv_key = BN_new (); - BN_rand (m_DH->priv_key, ELGAMAL_FULL_EXPONENT_NUM_BITS, 0, 1); + priv_key = BN_new (); + BN_rand (priv_key, ELGAMAL_FULL_EXPONENT_NUM_BITS, 0, 1); #endif auto ctx = BN_CTX_new (); - m_DH->pub_key = ElggPow (m_DH->priv_key, g_ElggTable, ctx); + pub_key = ElggPow (priv_key, g_ElggTable, ctx); + DH_set0_key (m_DH, pub_key, priv_key); BN_CTX_free (ctx); } else + { + DH_set0_key (m_DH, NULL, priv_key); DH_generate_key (m_DH); + DH_get0_key (m_DH, (const BIGNUM **)&pub_key, (const BIGNUM **)&priv_key); + } - if (priv) bn2buf (m_DH->priv_key, priv, 256); - if (pub) bn2buf (m_DH->pub_key, pub, 256); + if (priv) bn2buf (priv_key, priv, 256); + if (pub) bn2buf (pub_key, pub, 256); m_IsUpdated = true; } diff --git a/Crypto.h b/Crypto.h index 1644e147..efbc7165 100644 --- a/Crypto.h +++ b/Crypto.h @@ -301,6 +301,17 @@ inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) 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; } +inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) + { + if (dh->pub_key) BN_free (dh->pub_key); + if (dh->priv_key) BN_free (dh->priv_key); + dh->pub_key = pub_key; dh->priv_key = priv_key; return 1; + } +inline void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) + { *pub_key = dh->pub_key; *priv_key = dh->priv_key; } + #endif } diff --git a/Destination.cpp b/Destination.cpp index c8384ff9..9df3b438 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -277,19 +277,20 @@ namespace client LogPrint (eLogInfo, "Destination: Reply token is ignored for DatabaseStore"); offset += 36; } + i2p::data::IdentHash key (buf + DATABASE_STORE_KEY_OFFSET); std::shared_ptr leaseSet; if (buf[DATABASE_STORE_TYPE_OFFSET] == 1) // LeaseSet { LogPrint (eLogDebug, "Destination: Remote LeaseSet"); std::lock_guard lock(m_RemoteLeaseSetsMutex); - auto it = m_RemoteLeaseSets.find (buf + DATABASE_STORE_KEY_OFFSET); + auto it = m_RemoteLeaseSets.find (key); if (it != m_RemoteLeaseSets.end ()) { leaseSet = it->second; if (leaseSet->IsNewer (buf + offset, len - offset)) { leaseSet->Update (buf + offset, len - offset); - if (leaseSet->IsValid ()) + if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key) LogPrint (eLogDebug, "Destination: Remote LeaseSet updated"); else { @@ -304,12 +305,12 @@ namespace client else { leaseSet = std::make_shared (buf + offset, len - offset); - if (leaseSet->IsValid ()) + if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key) { if (leaseSet->GetIdentHash () != GetIdentHash ()) { LogPrint (eLogDebug, "Destination: New remote LeaseSet added"); - m_RemoteLeaseSets[buf + DATABASE_STORE_KEY_OFFSET] = leaseSet; + m_RemoteLeaseSets[key] = leaseSet; } else LogPrint (eLogDebug, "Destination: Own remote LeaseSet dropped"); @@ -324,7 +325,7 @@ namespace client else LogPrint (eLogError, "Destination: Unexpected client's DatabaseStore type ", buf[DATABASE_STORE_TYPE_OFFSET], ", dropped"); - auto it1 = m_LeaseSetRequests.find (buf + DATABASE_STORE_KEY_OFFSET); + auto it1 = m_LeaseSetRequests.find (key); if (it1 != m_LeaseSetRequests.end ()) { it1->second->requestTimeoutTimer.cancel (); diff --git a/Makefile b/Makefile index 7dcecb26..61220efd 100644 --- a/Makefile +++ b/Makefile @@ -94,7 +94,7 @@ strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB) strip $^ LATEST_TAG=$(shell git describe --tags --abbrev=0 openssl) -BRANCH=$(shell git branch --no-color | cut -c 3-) +BRANCH=$(shell git rev-parse --abbrev-ref HEAD) dist: git archive --format=tar.gz -9 --worktree-attributes \ --prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz diff --git a/SSUSession.cpp b/SSUSession.cpp index 9f855241..696d367f 100644 --- a/SSUSession.cpp +++ b/SSUSession.cpp @@ -1111,7 +1111,7 @@ namespace transport RAND_bytes ((uint8_t *)&nonce, 4); if (!nonce) nonce = 1; m_IsPeerTest = false; - m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1); + m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1, shared_from_this ()); SendPeerTest (nonce, boost::asio::ip::address(), 0, address->key, false, false); // address and port always zero for Alice } diff --git a/Transports.cpp b/Transports.cpp index 913106ae..358ca4c7 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -48,11 +48,22 @@ namespace transport { while (m_IsRunning) { - int num; - while ((num = m_QueueSize - m_Queue.size ()) > 0) + int num, total = 0; + while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 20) + { CreateDHKeysPairs (num); - std::unique_lock l(m_AcquiredMutex); - m_Acquired.wait (l); // wait for element gets aquired + total += num; + } + if (total >= 20) + { + LogPrint (eLogWarning, "Transports: ", total, " DH keys generated at the time"); + std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break + } + else + { + std::unique_lock l(m_AcquiredMutex); + m_Acquired.wait (l); // wait for element gets aquired + } } } @@ -60,7 +71,6 @@ namespace transport { if (num > 0) { - i2p::crypto::DHKeys dh; for (int i = 0; i < num; i++) { auto pair = std::make_shared (); diff --git a/TunnelEndpoint.cpp b/TunnelEndpoint.cpp index e2a0843e..455254ff 100644 --- a/TunnelEndpoint.cpp +++ b/TunnelEndpoint.cpp @@ -117,7 +117,7 @@ namespace tunnel m.nextFragmentNum = 1; auto ret = m_IncompleteMessages.insert (std::pair(msgID, m)); if (ret.second) - HandleOutOfSequenceFragment (msgID, ret.first->second); + HandleOutOfSequenceFragments (msgID, ret.first->second); else LogPrint (eLogError, "TunnelMessage: Incomplete message ", msgID, " already exists"); } @@ -168,7 +168,7 @@ namespace tunnel else { msg.nextFragmentNum++; - HandleOutOfSequenceFragment (msgID, msg); + HandleOutOfSequenceFragments (msgID, msg); } } else @@ -192,19 +192,31 @@ namespace tunnel void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr data) { - auto it = m_OutOfSequenceFragments.find (msgID); - if (it == m_OutOfSequenceFragments.end ()) - m_OutOfSequenceFragments.insert (std::pair (msgID, {fragmentNum, isLastFragment, data})); + if (!m_OutOfSequenceFragments.insert ({{msgID, fragmentNum}, {fragmentNum, isLastFragment, data}}).second) + LogPrint (eLogInfo, "TunnelMessage: duplicate out-of-sequence fragment ", fragmentNum, " of message ", msgID); } - void TunnelEndpoint::HandleOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg) + void TunnelEndpoint::HandleOutOfSequenceFragments (uint32_t msgID, TunnelMessageBlockEx& msg) { - auto it = m_OutOfSequenceFragments.find (msgID); - if (it != m_OutOfSequenceFragments.end ()) + while (ConcatNextOutOfSequenceFragment (msgID, msg)) { + if (!msg.nextFragmentNum) // message complete + { + HandleNextMessage (msg); + m_IncompleteMessages.erase (msgID); + break; + } + } + } + + bool TunnelEndpoint::ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg) + { + auto it = m_OutOfSequenceFragments.find ({msgID, msg.nextFragmentNum}); + if (it != m_OutOfSequenceFragments.end ()) + { if (it->second.fragmentNum == msg.nextFragmentNum) { - LogPrint (eLogWarning, "TunnelMessage: Out-of-sequence fragment ", (int)it->second.fragmentNum, " of message ", msgID, " found"); + LogPrint (eLogDebug, "TunnelMessage: Out-of-sequence fragment ", (int)it->second.fragmentNum, " of message ", msgID, " found"); size_t size = it->second.data->GetLength (); if (msg.data->len + size > msg.data->maxLen) { @@ -214,18 +226,19 @@ namespace tunnel msg.data = newMsg; } if (msg.data->Concat (it->second.data->GetBuffer (), size) < size) // concatenate out-of-sync fragment - LogPrint (eLogError, "Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen); + LogPrint (eLogError, "TunnelMessage: Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen); if (it->second.isLastFragment) - { // message complete - HandleNextMessage (msg); - m_IncompleteMessages.erase (msgID); - } + msg.nextFragmentNum = 0; else msg.nextFragmentNum++; m_OutOfSequenceFragments.erase (it); - } + return true; + } + else + LogPrint (eLogError, "Tunnel message: next fragment ", (int)it->second.fragmentNum, " of message ", msgID, " mismatch. ", (int)msg.nextFragmentNum, " expected"); } + return false; } void TunnelEndpoint::HandleNextMessage (const TunnelMessageBlock& msg) diff --git a/TunnelEndpoint.h b/TunnelEndpoint.h index 20b9105f..cb0056b4 100644 --- a/TunnelEndpoint.h +++ b/TunnelEndpoint.h @@ -39,12 +39,13 @@ namespace tunnel void HandleNextMessage (const TunnelMessageBlock& msg); void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr data); - void HandleOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); - + bool ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); // true if something added + void HandleOutOfSequenceFragments (uint32_t msgID, TunnelMessageBlockEx& msg); + private: std::map m_IncompleteMessages; - std::map m_OutOfSequenceFragments; + std::map, Fragment> m_OutOfSequenceFragments; // (msgID, fragment#)->fragment bool m_IsInbound; size_t m_NumReceivedBytes; }; diff --git a/Win32/installer.iss b/Win32/installer.iss index 7bfe63d9..2a7af872 100644 --- a/Win32/installer.iss +++ b/Win32/installer.iss @@ -1,9 +1,11 @@ #define I2Pd_AppName "i2pd" -#define I2Pd_ver "2.10.0" +#define I2Pd_ver "2.10.1" +#define I2Pd_Publisher "PurpleI2P" [Setup] AppName={#I2Pd_AppName} AppVersion={#I2Pd_ver} +AppPublisher={#I2Pd_Publisher} DefaultDirName={pf}\I2Pd DefaultGroupName=I2Pd UninstallDisplayIcon={app}\I2Pd.exe @@ -14,19 +16,25 @@ InternalCompressLevel=ultra64 Compression=lzma/ultra64 SolidCompression=true ArchitecturesInstallIn64BitMode=x64 +AppVerName={#I2Pd_AppName} +ExtraDiskSpaceRequired=15 +AppID={{621A23E0-3CF4-4BD6-97BC-4835EA5206A2} +AppPublisherURL=http://i2pd.website/ +AppSupportURL=https://github.com/PurpleI2P/i2pd/issues +AppUpdatesURL=https://github.com/PurpleI2P/i2pd/releases [Files] -Source: "..\i2pd_x86.exe"; DestDir: "{app}"; DestName: "i2pd.exe"; Flags: ignoreversion; Check: not IsWin64 -Source: "..\i2pd_x64.exe"; DestDir: "{app}"; DestName: "i2pd.exe"; Flags: ignoreversion; Check: IsWin64 -Source: "..\README.md"; DestDir: "{app}"; DestName: "Readme.txt"; Flags: onlyifdoesntexist -Source: "..\docs\i2pd.conf"; DestDir: "{userappdata}\i2pd"; Flags: onlyifdoesntexist -Source: "..\docs\subscriptions.txt"; DestDir: "{userappdata}\i2pd"; Flags: onlyifdoesntexist -Source: "..\docs\tunnels.conf"; DestDir: "{userappdata}\i2pd"; Flags: onlyifdoesntexist -Source: "..\contrib\*"; DestDir: "{userappdata}\i2pd"; Flags: onlyifdoesntexist recursesubdirs createallsubdirs +Source: ..\i2pd_x86.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: not IsWin64 +Source: ..\i2pd_x64.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: IsWin64 +Source: ..\README.md; DestDir: {app}; DestName: Readme.txt; Flags: onlyifdoesntexist +Source: ..\docs\i2pd.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist +Source: ..\docs\subscriptions.txt; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist +Source: ..\docs\tunnels.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist +Source: ..\contrib\certificates\*; DestDir: {userappdata}\i2pd\certificates; Flags: onlyifdoesntexist recursesubdirs createallsubdirs [Icons] -Name: "{group}\I2Pd"; Filename: "{app}\i2pd.exe" -Name: "{group}\Readme"; Filename: "{app}\Readme.txt" +Name: {group}\I2Pd; Filename: {app}\i2pd.exe +Name: {group}\Readme; Filename: {app}\Readme.txt [UninstallDelete] -Type: filesandordirs; Name: {app}\* +Type: filesandordirs; Name: {app} diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index b7e13979..afe7e118 100755 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,7 +2,7 @@ + android:versionName="2.10.1"> diff --git a/docs/usage.md b/docs/usage.md index 9480a556..a4bcbb77 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -10,6 +10,47 @@ i2pd can be used for: and many more. +## Starting, stopping and reloading configuration + +After you have built i2pd from source, just run a binary: + + ./i2pd + +To display all available options: + + ./i2pd --help + +i2pd can be controlled with signals. Process ID by default is written to file `~/.i2pd/i2pd.pid` or `/var/run/i2pd/i2pd.pid`. +You can use `kill` utility to send signals like this: + + kill -TERM $( cat /var/run/i2pd/i2pd.pid ) + +i2pd supports the following signals: + + TERM - Graceful shutdown. i2pd will wait for 10 minutes and stop. Send second TERM signal to shutdown i2pd immediately. + HUP - Reload configuration files. + + +### systemd unit + +Some binary Linux packages have a systemd control unit, so it is possible to managage i2pd with it. + +Start/stop i2pd: + + sudo systemctl start i2pd.service + sudo systemctl stop i2pd.service + +Enable/disable i2pd to be started on bootup: + + sudo systemctl enable i2pd.service + sudo systemctl disable i2pd.service + + +## Configuring i2pd + +See [configuration page](i2pd.readthedocs.io/page/configuration.html). + + ## Browsing and hosting websites ### Browse anonymous websites diff --git a/version.h b/version.h index 3814f5f4..9aadf505 100644 --- a/version.h +++ b/version.h @@ -8,7 +8,7 @@ #define I2PD_VERSION_MAJOR 2 #define I2PD_VERSION_MINOR 10 -#define I2PD_VERSION_MICRO 0 +#define I2PD_VERSION_MICRO 1 #define I2PD_VERSION_PATCH 0 #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) #define VERSION I2PD_VERSION