Merge pull request #1384 from PurpleI2P/openssl

2.27.0
This commit is contained in:
orignal 2019-07-03 12:42:49 -04:00 committed by GitHub
commit 84de3f081f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 197 additions and 104 deletions

View File

@ -1,9 +1,19 @@
# for this file format description, # for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog # see https://github.com/olivierlacan/keep-a-changelog
## [2.27.0] - 2019-07-03
### Added
- Support of PSK and DH authentication for encrypted LeaseSet2
### Changed
- Uptime is based on monotonic timer
### Fixed
- BOB status command response
- Correct NTCP2 port if NTCP is disabled
- Flood encrypted LeaseSet2 with store hash
## [2.26.0] - 2019-06-07 ## [2.26.0] - 2019-06-07
### Added ### Added
- HTTP method "PROFIND" - HTTP method "PROPFIND"
- Detection of external ipv6 address through the SSU - Detection of external ipv6 address through the SSU
- NTCP2 publishing depends on network status - NTCP2 publishing depends on network status
### Changed ### Changed
@ -11,6 +21,7 @@
- Response to BOB's "list" command - Response to BOB's "list" command
- ipv6 address is not longer NTCP's local endpoint's address - ipv6 address is not longer NTCP's local endpoint's address
- Reseeds list - Reseeds list
- HTTP_REFERER stripping in httpproxy (#823)
### Fixed ### Fixed
- Check and handle incorrect BOB input - Check and handle incorrect BOB input
- Ignore introducers for NTCP or NTCP2 addresses - Ignore introducers for NTCP or NTCP2 addresses

View File

@ -1,5 +1,5 @@
#define I2Pd_AppName "i2pd" #define I2Pd_AppName "i2pd"
#define I2Pd_ver "2.26.0" #define I2Pd_ver "2.27.0"
#define I2Pd_Publisher "PurpleI2P" #define I2Pd_Publisher "PurpleI2P"
[Setup] [Setup]

View File

@ -29,8 +29,8 @@ android {
applicationId "org.purplei2p.i2pd" applicationId "org.purplei2p.i2pd"
targetSdkVersion 28 targetSdkVersion 28
minSdkVersion 14 minSdkVersion 14
versionCode 2260 versionCode 2270
versionName "2.26.0" versionName "2.27.0"
ndk { ndk {
abiFilters 'armeabi-v7a' abiFilters 'armeabi-v7a'
abiFilters 'x86' abiFilters 'x86'

View File

@ -1,4 +1,4 @@
version: 2.26.0.{build} version: 2.27.0.{build}
pull_requests: pull_requests:
do_not_increment_build_number: true do_not_increment_build_number: true
branches: branches:

View File

@ -1,7 +1,7 @@
%define git_hash %(git rev-parse HEAD | cut -c -7) %define git_hash %(git rev-parse HEAD | cut -c -7)
Name: i2pd-git Name: i2pd-git
Version: 2.26.0 Version: 2.27.0
Release: git%{git_hash}%{?dist} Release: git%{git_hash}%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd Conflicts: i2pd
@ -110,6 +110,9 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Wed Jul 3 2019 orignal <i2porignal@yandex.ru> - 2.27.0
- update to 2.27.0
* Fri Jun 7 2019 orignal <i2porignal@yandex.ru> - 2.26.0 * Fri Jun 7 2019 orignal <i2porignal@yandex.ru> - 2.26.0
- update to 2.26.0 - update to 2.26.0

View File

@ -1,5 +1,5 @@
Name: i2pd Name: i2pd
Version: 2.26.0 Version: 2.27.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd-git Conflicts: i2pd-git
@ -108,6 +108,9 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Wed Jul 3 2019 orignal <i2porignal@yandex.ru> - 2.27.0
- update to 2.27.0
* Fri Jun 7 2019 orignal <i2porignal@yandex.ru> - 2.26.0 * Fri Jun 7 2019 orignal <i2porignal@yandex.ru> - 2.26.0
- update to 2.26.0 - update to 2.26.0

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
i2pd (2.27.0-1) unstable; urgency=medium
* updated to version 2.27.0/0.9.41
-- orignal <orignal@i2pmail.org> Wed, 3 Jul 2019 16:00:00 +0000
i2pd (2.26.0-1) unstable; urgency=medium i2pd (2.26.0-1) unstable; urgency=medium
* updated to version 2.26.0 * updated to version 2.26.0

View File

@ -296,11 +296,20 @@ namespace crypto
#if OPENSSL_X25519 #if OPENSSL_X25519
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32); m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL);
memcpy (m_PublicKey, pub, 32); // TODO: verify against m_Pkey if (pub)
memcpy (m_PublicKey, pub, 32); // TODO: verify against m_Pkey
else
{
size_t len = 32;
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
}
#else #else
memcpy (m_PrivateKey, priv, 32);
memcpy (m_PublicKey, pub, 32);
m_Ctx = BN_CTX_new (); m_Ctx = BN_CTX_new ();
memcpy (m_PrivateKey, priv, 32);
if (pub)
memcpy (m_PublicKey, pub, 32);
else
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
#endif #endif
} }

View File

@ -74,7 +74,7 @@ namespace crypto
public: public:
X25519Keys (); X25519Keys ();
X25519Keys (const uint8_t * priv, const uint8_t * pub); // for RouterContext X25519Keys (const uint8_t * priv, const uint8_t * pub); // if pub is null, derive from priv
~X25519Keys (); ~X25519Keys ();
void GenerateKeys (); void GenerateKeys ();

View File

@ -70,6 +70,16 @@ namespace client
it = params->find (I2CP_PARAM_LEASESET_TYPE); it = params->find (I2CP_PARAM_LEASESET_TYPE);
if (it != params->end ()) if (it != params->end ())
m_LeaseSetType = std::stoi(it->second); m_LeaseSetType = std::stoi(it->second);
it = params->find (I2CP_PARAM_LEASESET_PRIV_KEY);
if (it != params->end ())
{
m_LeaseSetPrivKey.reset (new i2p::data::Tag<32>());
if (m_LeaseSetPrivKey->FromBase64 (it->second) != 32)
{
LogPrint(eLogError, "Destination: invalid value i2cp.leaseSetPrivKey ", it->second);
m_LeaseSetPrivKey.reset (nullptr);
}
}
} }
} }
catch (std::exception & ex) catch (std::exception & ex)
@ -422,7 +432,7 @@ namespace client
auto it2 = m_LeaseSetRequests.find (key); auto it2 = m_LeaseSetRequests.find (key);
if (it2 != m_LeaseSetRequests.end () && it2->second->requestedBlindedKey) if (it2 != m_LeaseSetRequests.end () && it2->second->requestedBlindedKey)
{ {
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset, it2->second->requestedBlindedKey); auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset, it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? *m_LeaseSetPrivKey : nullptr);
if (ls2->IsValid ()) if (ls2->IsValid ())
{ {
m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key

View File

@ -55,6 +55,7 @@ namespace client
const char I2CP_PARAM_LEASESET_TYPE[] = "i2cp.leaseSetType"; const char I2CP_PARAM_LEASESET_TYPE[] = "i2cp.leaseSetType";
const int DEFAULT_LEASESET_TYPE = 1; const int DEFAULT_LEASESET_TYPE = 1;
const char I2CP_PARAM_LEASESET_ENCRYPTION_TYPE[] = "i2cp.leaseSetEncType"; const char I2CP_PARAM_LEASESET_ENCRYPTION_TYPE[] = "i2cp.leaseSetEncType";
const char I2CP_PARAM_LEASESET_PRIV_KEY[] = "i2cp.leaseSetPrivKey"; // PSK decryption key, base64
// latency // latency
const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min"; const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min";
@ -175,6 +176,7 @@ namespace client
m_PublishDelayTimer, m_CleanupTimer; m_PublishDelayTimer, m_CleanupTimer;
std::string m_Nickname; std::string m_Nickname;
int m_LeaseSetType; int m_LeaseSetType;
std::unique_ptr<i2p::data::Tag<32> > m_LeaseSetPrivKey; // non-null if presented
public: public:

View File

@ -258,12 +258,12 @@ namespace i2p
return m; return m;
} }
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet) std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (const i2p::data::IdentHash& storeHash, std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
{ {
if (!leaseSet) return nullptr; if (!leaseSet) return nullptr;
auto m = NewI2NPShortMessage (); auto m = NewI2NPShortMessage ();
uint8_t * payload = m->GetPayload (); uint8_t * payload = m->GetPayload ();
memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32); memcpy (payload + DATABASE_STORE_KEY_OFFSET, storeHash, 32);
payload[DATABASE_STORE_TYPE_OFFSET] = leaseSet->GetStoreType (); // 1 for LeaseSet payload[DATABASE_STORE_TYPE_OFFSET] = leaseSet->GetStoreType (); // 1 for LeaseSet
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0);
size_t size = DATABASE_STORE_HEADER_SIZE; size_t size = DATABASE_STORE_HEADER_SIZE;

View File

@ -247,7 +247,7 @@ namespace tunnel
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers); std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0); std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet); // for floodfill only std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (const i2p::data::IdentHash& storeHash, std::shared_ptr<const i2p::data::LeaseSet> leaseSet); // for floodfill only
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LocalLeaseSet> leaseSet, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr); std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LocalLeaseSet> leaseSet, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg); bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg);

View File

@ -479,7 +479,7 @@ namespace data
} }
else else
{ {
LogPrint (eLogError, "LeaseSet2: Unexpected blinded key type ", blindedKeyType, " instread ", key->GetBlindedSigType ()); LogPrint (eLogError, "LeaseSet2: Unexpected blinded key type ", blindedKeyType, " instead ", key->GetBlindedSigType ());
return; return;
} }
// outer key // outer key
@ -506,7 +506,7 @@ namespace data
if (authDataLen > 0) if (authDataLen > 0)
{ {
memcpy (innerInput + 32, subcredential, 36); memcpy (innerInput + 32, subcredential, 36);
i2p::crypto::HKDF (outerPlainText.data () + 1, innerInput, 68, "ELS2_L2K", keys); i2p::crypto::HKDF (outerPlainText.data () + 1 + authDataLen, innerInput, 68, "ELS2_L2K", keys);
} }
else else
// no authData presented, innerInput = subcredential || publishedTimestamp // no authData presented, innerInput = subcredential || publishedTimestamp
@ -531,40 +531,75 @@ namespace data
} }
} }
// helper for ExtractClientAuthData
static inline bool GetAuthCookie (const uint8_t * authClients, int numClients, const uint8_t * okm, uint8_t * authCookie)
{
// try to find clientCookie_i for clientID_i = okm[44:51]
for (int i = 0; i < numClients; i++)
{
if (!memcmp (okm + 44, authClients + i*40, 8)) // clientID_i
{
// clientKey_i = okm[0:31]
// clientIV_i = okm[32:43]
i2p::crypto::ChaCha20 (authClients + i*40 + 8, 32, okm, okm + 32, authCookie); // clientCookie_i
return true;
}
}
return false;
}
size_t LeaseSet2::ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const size_t LeaseSet2::ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const
{ {
size_t offset = 0; size_t offset = 0;
uint8_t flag = buf[offset]; offset++; // flag uint8_t flag = buf[offset]; offset++; // flag
if (flag & 0x01) // client auth if (flag & 0x01) // client auth
{ {
if (flag & 0x02) // PSK, bit 1 is set to 1 if (!(flag & 0x0E)) // DH, bit 1-3 all zeroes
{
const uint8_t * ephemeralPublicKey = buf + offset; offset += 32; // ephemeralPublicKey
uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
if (offset > len)
{
LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in DH auth data");
return 0;
}
// calculate authCookie
if (secret)
{
i2p::crypto::X25519Keys ck (secret, nullptr); // derive cpk_i from csk_i
uint8_t authInput[100];
ck.Agree (ephemeralPublicKey, authInput); // sharedSecret is first 32 bytes of authInput
memcpy (authInput + 32, ck.GetPublicKey (), 32); // cpk_i
memcpy (authInput + 64, subcredential, 36);
uint8_t okm[64]; // 52 actual data
i2p::crypto::HKDF (ephemeralPublicKey, authInput, 100, "ELS2_XCA", okm);
if (!GetAuthCookie (authClients, numClients, okm, authCookie))
LogPrint (eLogError, "LeaseSet2: Client cookie DH not found");
}
else
LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: csk_i is not provided");
}
else if (flag & 0x02) // PSK, bit 1 is set to 1
{ {
const uint8_t * authSalt = buf + offset; offset += 32; // authSalt const uint8_t * authSalt = buf + offset; offset += 32; // authSalt
uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
if (offset > len)
{
LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in PSK auth data");
return 0;
}
// calculate authCookie // calculate authCookie
if (secret) if (secret)
{ {
uint8_t authInput[68]; uint8_t authInput[68];
memcpy (authInput, secret, 32); memcpy (authInput, secret, 32);
memcpy (authInput, subcredential, 36); memcpy (authInput + 32, subcredential, 36);
uint8_t okm[64]; // 52 actual data uint8_t okm[64]; // 52 actual data
i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm); i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm);
// try to find clientCookie_i for clientID_i = okm[44:51] if (!GetAuthCookie (authClients, numClients, okm, authCookie))
bool found = false; LogPrint (eLogError, "LeaseSet2: Client cookie PSK not found");
for (int i = 0; i < numClients; i++)
{
if (!memcmp (okm + 44, authClients + i*40, 8)) // clientID_i
{
// clientKey_i = okm[0:31]
// clientIV_i = okm[32:43]
i2p::crypto::ChaCha20 (authClients + i*40 + 8, 32, okm, okm + 32, authCookie); // clientCookie_i
found = true;
break;
}
}
if (!found)
LogPrint (eLogError, "LeaseSet2: Client cookie not found");
} }
else else
LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: psk_i is not provided"); LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: psk_i is not provided");

View File

@ -396,6 +396,10 @@ namespace transport
{ {
m_IsTerminated = true; m_IsTerminated = true;
m_IsEstablished = false; m_IsEstablished = false;
boost::system::error_code ec;
m_Socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
if (ec)
LogPrint (eLogDebug, "NTCP2: Couldn't shutdown socket: ", ec.message ());
m_Socket.close (); m_Socket.close ();
transports.PeerDisconnected (shared_from_this ()); transports.PeerDisconnected (shared_from_this ());
m_Server.RemoveNTCP2Session (shared_from_this ()); m_Server.RemoveNTCP2Session (shared_from_this ());

View File

@ -523,9 +523,10 @@ namespace data
auto total = m_RouterInfos.size (); auto total = m_RouterInfos.size ();
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL; uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch(); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
auto uptime = i2p::context.GetUptime ();
// routers don't expire if less than 90 or uptime is less than 1 hour // routers don't expire if less than 90 or uptime is less than 1 hour
bool checkForExpiration = total > NETDB_MIN_ROUTERS && ts > (i2p::context.GetStartupTime () + 600)*1000LL; // 10 minutes bool checkForExpiration = total > NETDB_MIN_ROUTERS && uptime > 600; // 10 minutes
if (checkForExpiration && ts > (i2p::context.GetStartupTime () + 3600)*1000LL) // 1 hour if (checkForExpiration && uptime > 3600) // 1 hour
expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL : expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL :
NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total; NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total;
@ -909,7 +910,7 @@ namespace data
else if (!leaseSet->IsExpired ()) // we don't send back our LeaseSets else if (!leaseSet->IsExpired ()) // we don't send back our LeaseSets
{ {
LogPrint (eLogDebug, "NetDb: requested LeaseSet ", key, " found"); LogPrint (eLogDebug, "NetDb: requested LeaseSet ", key, " found");
replyMsg = CreateDatabaseStoreMsg (leaseSet); replyMsg = CreateDatabaseStoreMsg (ident, leaseSet);
} }
} }

View File

@ -19,7 +19,7 @@ namespace i2p
RouterContext::RouterContext (): RouterContext::RouterContext ():
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
m_StartupTime (0), m_ShareRatio (100), m_Status (eRouterStatusOK), m_ShareRatio (100), m_Status (eRouterStatusOK),
m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID) m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID)
{ {
} }
@ -27,7 +27,7 @@ namespace i2p
void RouterContext::Init () void RouterContext::Init ()
{ {
srand (i2p::util::GetMillisecondsSinceEpoch () % 1000); srand (i2p::util::GetMillisecondsSinceEpoch () % 1000);
m_StartupTime = i2p::util::GetSecondsSinceEpoch (); m_StartupTime = std::chrono::steady_clock::now();
if (!Load ()) if (!Load ())
CreateNewRouter (); CreateNewRouter ();
m_Decryptor = m_Keys.CreateDecryptor (nullptr); m_Decryptor = m_Keys.CreateDecryptor (nullptr);
@ -183,17 +183,18 @@ namespace i2p
void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4only) void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4only)
{ {
if (!m_NTCP2Keys) return; if (!m_NTCP2Keys) return;
if (!port)
{
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
if (port == 9150) port = 9151; // Tor browser
}
bool updated = false; bool updated = false;
for (auto& address : m_RouterInfo.GetAddresses ()) for (auto& address : m_RouterInfo.GetAddresses ())
{ {
if (address->IsNTCP2 () && (address->port != port || address->ntcp2->isPublished != publish) && (!v4only || address->host.is_v4 ())) if (address->IsNTCP2 () && (address->port != port || address->ntcp2->isPublished != publish) && (!v4only || address->host.is_v4 ()))
{ {
address->port = port; if (!port && !address->port)
{
// select random port only if address's port is not set
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
if (port == 9150) port = 9151; // Tor browser
}
if (port) address->port = port;
address->cost = publish ? 3 : 14; address->cost = publish ? 3 : 14;
address->ntcp2->isPublished = publish; address->ntcp2->isPublished = publish;
address->ntcp2->iv = m_NTCP2Keys->iv; address->ntcp2->iv = m_NTCP2Keys->iv;
@ -715,7 +716,7 @@ namespace i2p
uint32_t RouterContext::GetUptime () const uint32_t RouterContext::GetUptime () const
{ {
return i2p::util::GetSecondsSinceEpoch () - m_StartupTime; return std::chrono::duration_cast<std::chrono::seconds> (std::chrono::steady_clock::now() - m_StartupTime).count ();
} }
bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const

View File

@ -5,6 +5,7 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <chrono>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "Identity.h" #include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
@ -64,8 +65,7 @@ namespace i2p
const uint8_t * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; }; const uint8_t * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; };
i2p::crypto::X25519Keys& GetStaticKeys (); i2p::crypto::X25519Keys& GetStaticKeys ();
uint32_t GetUptime () const; uint32_t GetUptime () const; // in seconds
uint32_t GetStartupTime () const { return m_StartupTime; };
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; }; uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
uint64_t GetBandwidthLimit () const { return m_BandwidthLimit; }; uint64_t GetBandwidthLimit () const { return m_BandwidthLimit; };
uint64_t GetTransitBandwidthLimit () const { return (m_BandwidthLimit*m_ShareRatio)/100LL; }; uint64_t GetTransitBandwidthLimit () const { return (m_BandwidthLimit*m_ShareRatio)/100LL; };
@ -137,7 +137,7 @@ namespace i2p
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor; std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor;
uint64_t m_LastUpdateTime; // in seconds uint64_t m_LastUpdateTime; // in seconds
bool m_AcceptsTunnels, m_IsFloodfill; bool m_AcceptsTunnels, m_IsFloodfill;
uint64_t m_StartupTime; // in seconds since epoch std::chrono::time_point<std::chrono::steady_clock> m_StartupTime;
uint64_t m_BandwidthLimit; // allowed bandwidth uint64_t m_BandwidthLimit; // allowed bandwidth
int m_ShareRatio; int m_ShareRatio;
RouterStatus m_Status; RouterStatus m_Status;

View File

@ -71,14 +71,14 @@ public:
return std::string (str, str + l); return std::string (str, str + l);
} }
void FromBase32 (const std::string& s) size_t FromBase32 (const std::string& s)
{ {
i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz); return i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz);
} }
void FromBase64 (const std::string& s) size_t FromBase64 (const std::string& s)
{ {
i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz); return i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz);
} }
private: private:

View File

@ -562,7 +562,10 @@ namespace transport
{ {
auto addr = router->GetSSUV6Address (); auto addr = router->GetSSUV6Address ();
if (addr) if (addr)
m_SSUServer->CreateDirectSession (router, { addr->host, (uint16_t)addr->port }, false); m_SSUServer->GetServiceV6 ().post ([this, router, addr]
{
m_SSUServer->CreateDirectSession (router, { addr->host, (uint16_t)addr->port }, false);
});
} }
} }
} }

View File

@ -46,7 +46,7 @@ namespace util
{ {
auto tmp = m_Head; auto tmp = m_Head;
m_Head = static_cast<T*>(*(void * *)m_Head); // next m_Head = static_cast<T*>(*(void * *)m_Head); // next
delete tmp; ::operator delete ((void *)tmp);
} }
} }

View File

@ -7,7 +7,7 @@
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
#define I2PD_VERSION_MAJOR 2 #define I2PD_VERSION_MAJOR 2
#define I2PD_VERSION_MINOR 26 #define I2PD_VERSION_MINOR 27
#define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_MICRO 0
#define I2PD_VERSION_PATCH 0 #define I2PD_VERSION_PATCH 0
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
@ -21,7 +21,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 40 #define I2P_VERSION_MICRO 41
#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)

View File

@ -341,17 +341,17 @@ namespace client
SendReplyOK(); SendReplyOK();
} }
void BOBCommandSession::SendData (const char * data) void BOBCommandSession::SendRaw (const char * data)
{ {
std::ostream os(&m_SendBuffer); std::ostream os(&m_SendBuffer);
os << "DATA " << data << std::endl; os << data << std::endl;
} }
void BOBCommandSession::BuildStatusLine(bool currentTunnel, BOBDestination *dest, std::string &out) void BOBCommandSession::BuildStatusLine(bool currentTunnel, BOBDestination *dest, std::string &out)
{ {
// helper lambdas // helper lambdas
const auto isset = [](const std::string &str) { return str.empty() ? "not_set" : str; }; // for inhost, outhost const auto issetStr = [](const std::string &str) { return str.empty() ? "not_set" : str; }; // for inhost, outhost
const auto issetNum = [&isset](const int p) { return isset(p == 0 ? "" : std::to_string(p)); }; // for inport, outport const auto issetNum = [&issetStr](const int p) { return issetStr(p == 0 ? "" : std::to_string(p)); }; // for inport, outport
const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; }; const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; };
const auto destReady = [](const BOBDestination * const dest) { return dest->GetLocalDestination()->IsReady(); }; const auto destReady = [](const BOBDestination * const dest) { return dest->GetLocalDestination()->IsReady(); };
const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str
@ -359,8 +359,8 @@ namespace client
// tunnel info // tunnel info
const std::string nickname = currentTunnel ? m_Nickname : dest->GetNickname(); const std::string nickname = currentTunnel ? m_Nickname : dest->GetNickname();
const bool quiet = currentTunnel ? m_IsQuiet : dest->GetQuiet(); const bool quiet = currentTunnel ? m_IsQuiet : dest->GetQuiet();
const std::string inhost = isset(currentTunnel ? m_InHost : dest->GetInHost()); const std::string inhost = issetStr(currentTunnel ? m_InHost : dest->GetInHost());
const std::string outhost = isset(currentTunnel ? m_OutHost : dest->GetOutHost()); const std::string outhost = issetStr(currentTunnel ? m_OutHost : dest->GetOutHost());
const std::string inport = issetNum(currentTunnel ? m_InPort : dest->GetInPort()); const std::string inport = issetNum(currentTunnel ? m_InPort : dest->GetInPort());
const std::string outport = issetNum(currentTunnel ? m_OutPort : dest->GetOutPort()); const std::string outport = issetNum(currentTunnel ? m_OutPort : dest->GetOutPort());
const bool keys = destExists(dest); // key must exist when destination is created const bool keys = destExists(dest); // key must exist when destination is created
@ -370,7 +370,8 @@ namespace client
// build line // build line
std::stringstream ss; std::stringstream ss;
ss << "NICKNAME: " << nickname << " " << "STARTING: " << bool_str(starting) << " " ss << "DATA "
<< "NICKNAME: " << nickname << " " << "STARTING: " << bool_str(starting) << " "
<< "RUNNING: " << bool_str(running) << " " << "STOPPING: " << bool_str(stopping) << " " << "RUNNING: " << bool_str(running) << " " << "STOPPING: " << bool_str(stopping) << " "
<< "KEYS: " << bool_str(keys) << " " << "QUIET: " << bool_str(quiet) << " " << "KEYS: " << bool_str(keys) << " " << "QUIET: " << bool_str(quiet) << " "
<< "INPORT: " << inport << " " << "INHOST: " << inhost << " " << "INPORT: " << inport << " " << "INHOST: " << inhost << " "
@ -654,16 +655,16 @@ namespace client
for (const auto& it: destinations) for (const auto& it: destinations)
{ {
BuildStatusLine(false, it.second, statusLine); BuildStatusLine(false, it.second, statusLine);
SendData (statusLine.c_str()); SendRaw(statusLine.c_str());
if(m_Nickname.compare(it.second->GetNickname()) == 0) if(m_Nickname.compare(it.second->GetNickname()) == 0)
sentCurrent = true; sentCurrent = true;
} }
if(!sentCurrent && !m_Nickname.empty()) if(!sentCurrent && !m_Nickname.empty())
{ {
// add the current tunnel to the list // add the current tunnel to the list.
// this is for the incomplete tunnel which has not been started yet.
BuildStatusLine(true, m_CurrentDestination, statusLine); BuildStatusLine(true, m_CurrentDestination, statusLine);
LogPrint(eLogError, statusLine); SendRaw(statusLine.c_str());
SendData(statusLine.c_str());
} }
SendReplyOK ("Listing done"); SendReplyOK ("Listing done");
} }
@ -690,21 +691,23 @@ namespace client
void BOBCommandSession::StatusCommandHandler (const char * operand, size_t len) void BOBCommandSession::StatusCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: status ", operand); LogPrint (eLogDebug, "BOB: status ", operand);
const std::string name = operand;
std::string statusLine; std::string statusLine;
if (m_Nickname == operand)
// always prefer destination
auto ptr = m_Owner.FindDestination(name);
if(ptr != nullptr)
{ {
// check current tunnel // tunnel destination exists
BuildStatusLine(true, nullptr, statusLine); BuildStatusLine(false, ptr, statusLine);
SendReplyOK(statusLine.c_str()); SendReplyOK(statusLine.c_str());
} }
else else
{ {
// check other if(m_Nickname == name && !name.empty())
std::string name = operand;
auto ptr = m_Owner.FindDestination(name);
if(ptr != nullptr)
{ {
BuildStatusLine(false, ptr, statusLine); // tunnel is incomplete / has not been started yet
BuildStatusLine(true, nullptr, statusLine);
SendReplyOK(statusLine.c_str()); SendReplyOK(statusLine.c_str());
} }
else else

View File

@ -213,7 +213,7 @@ namespace client
void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void SendReplyOK (const char * msg = nullptr); void SendReplyOK (const char * msg = nullptr);
void SendReplyError (const char * msg); void SendReplyError (const char * msg);
void SendData (const char * data); void SendRaw (const char * data);
void BuildStatusLine(bool currentTunnel, BOBDestination *destination, std::string &out); void BuildStatusLine(bool currentTunnel, BOBDestination *destination, std::string &out);

View File

@ -395,6 +395,8 @@ namespace client
options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE); options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE);
std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, ""); std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "");
if (encType.length () > 0) options[I2CP_PARAM_LEASESET_ENCRYPTION_TYPE] = encType; if (encType.length () > 0) options[I2CP_PARAM_LEASESET_ENCRYPTION_TYPE] = encType;
std::string privKey = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_PRIV_KEY, "");
if (privKey.length () > 0) options[I2CP_PARAM_LEASESET_PRIV_KEY] = privKey;
} }
void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const

View File

@ -35,6 +35,7 @@
<translation type="qt" /> <translation type="qt" />
<releases> <releases>
<release version="2.27.0" date="2019-07-03" />
<release version="2.26.0" date="2019-06-07" /> <release version="2.26.0" date="2019-06-07" />
<release version="2.25.0" date="2019-05-09" /> <release version="2.25.0" date="2019-05-09" />
<release version="2.24.0" date="2019-03-21" /> <release version="2.24.0" date="2019-03-21" />

View File

@ -4,19 +4,22 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = i2pd_qt TARGET = i2pd_qt
TEMPLATE = app TEMPLATE = app
QMAKE_CXXFLAGS *= -std=c++11 -ggdb QMAKE_CXXFLAGS *= -std=c++11 -Wno-unused-parameter -Wno-maybe-uninitialized
DEFINES += USE_UPNP DEFINES += USE_UPNP
SOURCES += DaemonQT.cpp mainwindow.cpp \ SOURCES += DaemonQT.cpp mainwindow.cpp \
../../libi2pd/api.cpp \ ../../libi2pd/api.cpp \
../../libi2pd/Base.cpp \ ../../libi2pd/Base.cpp \
../../libi2pd/Blinding.cpp \
../../libi2pd/BloomFilter.cpp \ ../../libi2pd/BloomFilter.cpp \
../../libi2pd/ChaCha20.cpp \
../../libi2pd/Config.cpp \ ../../libi2pd/Config.cpp \
../../libi2pd/CPU.cpp \ ../../libi2pd/CPU.cpp \
../../libi2pd/Crypto.cpp \ ../../libi2pd/Crypto.cpp \
../../libi2pd/CryptoKey.cpp \ ../../libi2pd/CryptoKey.cpp \
../../libi2pd/Datagram.cpp \ ../../libi2pd/Datagram.cpp \
../../libi2pd/Destination.cpp \ ../../libi2pd/Destination.cpp \
../../libi2pd/Ed25519.cpp \
../../libi2pd/Event.cpp \ ../../libi2pd/Event.cpp \
../../libi2pd/Family.cpp \ ../../libi2pd/Family.cpp \
../../libi2pd/FS.cpp \ ../../libi2pd/FS.cpp \
@ -31,7 +34,9 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
../../libi2pd/Log.cpp \ ../../libi2pd/Log.cpp \
../../libi2pd/NetDb.cpp \ ../../libi2pd/NetDb.cpp \
../../libi2pd/NetDbRequests.cpp \ ../../libi2pd/NetDbRequests.cpp \
../../libi2pd/NTCP2.cpp \
../../libi2pd/NTCPSession.cpp \ ../../libi2pd/NTCPSession.cpp \
../../libi2pd/Poly1305.cpp \
../../libi2pd/Profiling.cpp \ ../../libi2pd/Profiling.cpp \
../../libi2pd/Reseed.cpp \ ../../libi2pd/Reseed.cpp \
../../libi2pd/RouterContext.cpp \ ../../libi2pd/RouterContext.cpp \
@ -49,9 +54,6 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
../../libi2pd/TunnelGateway.cpp \ ../../libi2pd/TunnelGateway.cpp \
../../libi2pd/TunnelPool.cpp \ ../../libi2pd/TunnelPool.cpp \
../../libi2pd/util.cpp \ ../../libi2pd/util.cpp \
../../libi2pd/Ed25519.cpp \
../../libi2pd/Chacha20.cpp \
../../libi2pd/Poly1305.cpp \
../../libi2pd_client/AddressBook.cpp \ ../../libi2pd_client/AddressBook.cpp \
../../libi2pd_client/BOB.cpp \ ../../libi2pd_client/BOB.cpp \
../../libi2pd_client/ClientContext.cpp \ ../../libi2pd_client/ClientContext.cpp \
@ -64,42 +66,37 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
../../libi2pd_client/SOCKS.cpp \ ../../libi2pd_client/SOCKS.cpp \
../../libi2pd_client/Websocket.cpp \ ../../libi2pd_client/Websocket.cpp \
../../libi2pd_client/WebSocks.cpp \ ../../libi2pd_client/WebSocks.cpp \
../../daemon/Daemon.cpp \
../../daemon/HTTPServer.cpp \
../../daemon/I2PControl.cpp \
../../daemon/i2pd.cpp \
../../daemon/UPnP.cpp \
ClientTunnelPane.cpp \ ClientTunnelPane.cpp \
MainWindowItems.cpp \ MainWindowItems.cpp \
ServerTunnelPane.cpp \ ServerTunnelPane.cpp \
SignatureTypeComboboxFactory.cpp \ SignatureTypeComboboxFactory.cpp \
TunnelConfig.cpp \ TunnelConfig.cpp \
TunnelPane.cpp \ TunnelPane.cpp \
../../daemon/Daemon.cpp \
../../daemon/HTTPServer.cpp \
../../daemon/i2pd.cpp \
../../daemon/I2PControl.cpp \
../../daemon/UnixDaemon.cpp \
../../daemon/UPnP.cpp \
textbrowsertweaked1.cpp \ textbrowsertweaked1.cpp \
pagewithbackbutton.cpp \ pagewithbackbutton.cpp \
widgetlock.cpp \ widgetlock.cpp \
widgetlockregistry.cpp \ widgetlockregistry.cpp \
logviewermanager.cpp \ logviewermanager.cpp
../../libi2pd/NTCP2.cpp
#qt creator does not handle this well
#SOURCES += $$files(../../libi2pd/*.cpp)
#SOURCES += $$files(../../libi2pd_client/*.cpp)
#SOURCES += $$files(../../daemon/*.cpp)
#SOURCES += $$files(./*.cpp)
SOURCES -= ../../daemon/UnixDaemon.cpp
HEADERS += DaemonQT.h mainwindow.h \ HEADERS += DaemonQT.h mainwindow.h \
../../libi2pd/api.h \ ../../libi2pd/api.h \
../../libi2pd/Base.h \ ../../libi2pd/Base.h \
../../libi2pd/Blinding.h \
../../libi2pd/BloomFilter.h \ ../../libi2pd/BloomFilter.h \
../../libi2pd/ChaCha20.h \
../../libi2pd/Config.h \ ../../libi2pd/Config.h \
../../libi2pd/CPU.h \
../../libi2pd/Crypto.h \ ../../libi2pd/Crypto.h \
../../libi2pd/CryptoKey.h \ ../../libi2pd/CryptoKey.h \
../../libi2pd/CryptoWorker.h \
../../libi2pd/Datagram.h \ ../../libi2pd/Datagram.h \
../../libi2pd/Destination.h \ ../../libi2pd/Destination.h \
../../libi2pd/Ed25519.h \
../../libi2pd/Event.h \ ../../libi2pd/Event.h \
../../libi2pd/Family.h \ ../../libi2pd/Family.h \
../../libi2pd/FS.h \ ../../libi2pd/FS.h \
@ -115,13 +112,16 @@ HEADERS += DaemonQT.h mainwindow.h \
../../libi2pd/Log.h \ ../../libi2pd/Log.h \
../../libi2pd/NetDb.hpp \ ../../libi2pd/NetDb.hpp \
../../libi2pd/NetDbRequests.h \ ../../libi2pd/NetDbRequests.h \
../../libi2pd/NTCP2.h \
../../libi2pd/NTCPSession.h \ ../../libi2pd/NTCPSession.h \
../../libi2pd/Poly1305.h \
../../libi2pd/Profiling.h \ ../../libi2pd/Profiling.h \
../../libi2pd/Queue.h \ ../../libi2pd/Queue.h \
../../libi2pd/Reseed.h \ ../../libi2pd/Reseed.h \
../../libi2pd/RouterContext.h \ ../../libi2pd/RouterContext.h \
../../libi2pd/RouterInfo.h \ ../../libi2pd/RouterInfo.h \
../../libi2pd/Signature.h \ ../../libi2pd/Signature.h \
../../libi2pd/Siphash.h \
../../libi2pd/SSU.h \ ../../libi2pd/SSU.h \
../../libi2pd/SSUData.h \ ../../libi2pd/SSUData.h \
../../libi2pd/SSUSession.h \ ../../libi2pd/SSUSession.h \
@ -151,6 +151,10 @@ HEADERS += DaemonQT.h mainwindow.h \
../../libi2pd_client/SOCKS.h \ ../../libi2pd_client/SOCKS.h \
../../libi2pd_client/Websocket.h \ ../../libi2pd_client/Websocket.h \
../../libi2pd_client/WebSocks.h \ ../../libi2pd_client/WebSocks.h \
../../daemon/Daemon.h \
../../daemon/HTTPServer.h \
../../daemon/I2PControl.h \
../../daemon/UPnP.h \
ClientTunnelPane.h \ ClientTunnelPane.h \
MainWindowItems.h \ MainWindowItems.h \
ServerTunnelPane.h \ ServerTunnelPane.h \
@ -158,16 +162,11 @@ HEADERS += DaemonQT.h mainwindow.h \
TunnelConfig.h \ TunnelConfig.h \
TunnelPane.h \ TunnelPane.h \
TunnelsPageUpdateListener.h \ TunnelsPageUpdateListener.h \
../../daemon/Daemon.h \
../../daemon/HTTPServer.h \
../../daemon/I2PControl.h \
../../daemon/UPnP.h \
textbrowsertweaked1.h \ textbrowsertweaked1.h \
pagewithbackbutton.h \ pagewithbackbutton.h \
widgetlock.h \ widgetlock.h \
widgetlockregistry.h \ widgetlockregistry.h \
i2pd.rc \ i2pd.rc \
i2pd.rc \
logviewermanager.h logviewermanager.h
INCLUDEPATH += ../../libi2pd INCLUDEPATH += ../../libi2pd