Compare commits

..

1 commit

Author SHA1 Message Date
Pratik B.
3a8e30320d
Merge 17399da399 into 43939cedf4 2024-10-28 14:07:21 +02:00
24 changed files with 317 additions and 246 deletions

View file

@ -240,12 +240,17 @@ namespace crypto
// x25519
X25519Keys::X25519Keys ()
{
#if OPENSSL_X25519
m_Ctx = EVP_PKEY_CTX_new_id (NID_X25519, NULL);
m_Pkey = nullptr;
#else
m_Ctx = BN_CTX_new ();
#endif
}
X25519Keys::X25519Keys (const uint8_t * priv, const uint8_t * pub)
{
#if OPENSSL_X25519
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL);
if (pub)
@ -255,16 +260,29 @@ namespace crypto
size_t len = 32;
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
}
#else
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
}
X25519Keys::~X25519Keys ()
{
#if OPENSSL_X25519
EVP_PKEY_CTX_free (m_Ctx);
if (m_Pkey) EVP_PKEY_free (m_Pkey);
#else
BN_CTX_free (m_Ctx);
#endif
}
void X25519Keys::GenerateKeys ()
{
#if OPENSSL_X25519
if (m_Pkey)
{
EVP_PKEY_free (m_Pkey);
@ -276,11 +294,16 @@ namespace crypto
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); // TODO: do we really need to re-create m_Ctx?
size_t len = 32;
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
#else
RAND_bytes (m_PrivateKey, 32);
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
#endif
}
bool X25519Keys::Agree (const uint8_t * pub, uint8_t * shared)
{
if (!pub || (pub[31] & 0x80)) return false; // not x25519 key
#if OPENSSL_X25519
EVP_PKEY_derive_init (m_Ctx);
auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub, 32);
if (!pkey) return false;
@ -288,17 +311,25 @@ namespace crypto
size_t len = 32;
EVP_PKEY_derive (m_Ctx, shared, &len);
EVP_PKEY_free (pkey);
#else
GetEd25519 ()->ScalarMul (pub, m_PrivateKey, shared, m_Ctx);
#endif
return true;
}
void X25519Keys::GetPrivateKey (uint8_t * priv) const
{
#if OPENSSL_X25519
size_t len = 32;
EVP_PKEY_get_raw_private_key (m_Pkey, priv, &len);
#else
memcpy (priv, m_PrivateKey, 32);
#endif
}
void X25519Keys::SetPrivateKey (const uint8_t * priv, bool calculatePublic)
{
#if OPENSSL_X25519
if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx);
if (m_Pkey) EVP_PKEY_free (m_Pkey);
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
@ -308,6 +339,11 @@ namespace crypto
size_t len = 32;
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
}
#else
memcpy (m_PrivateKey, priv, 32);
if (calculatePublic)
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
#endif
}
// ElGamal

View file

@ -31,6 +31,7 @@
#if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
# define OPENSSL_HKDF 1
# define OPENSSL_EDDSA 1
# define OPENSSL_X25519 1
# if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL
# define OPENSSL_SIPHASH 1
# endif
@ -69,8 +70,13 @@ namespace crypto
private:
uint8_t m_PublicKey[32];
#if OPENSSL_X25519
EVP_PKEY_CTX * m_Ctx;
EVP_PKEY * m_Pkey;
#else
BN_CTX * m_Ctx;
uint8_t m_PrivateKey[32];
#endif
bool m_IsElligatorIneligible = false; // true if definitely ineligible
};

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@ -457,6 +457,86 @@ namespace crypto
}
}
#if !OPENSSL_X25519
BIGNUM * Ed25519::ScalarMul (const BIGNUM * u, const BIGNUM * k, BN_CTX * ctx) const
{
BN_CTX_start (ctx);
auto x1 = BN_CTX_get (ctx); BN_copy (x1, u);
auto x2 = BN_CTX_get (ctx); BN_one (x2);
auto z2 = BN_CTX_get (ctx); BN_zero (z2);
auto x3 = BN_CTX_get (ctx); BN_copy (x3, u);
auto z3 = BN_CTX_get (ctx); BN_one (z3);
auto c121666 = BN_CTX_get (ctx); BN_set_word (c121666, 121666);
auto tmp0 = BN_CTX_get (ctx); auto tmp1 = BN_CTX_get (ctx);
unsigned int swap = 0;
auto bits = BN_num_bits (k);
while(bits)
{
--bits;
auto k_t = BN_is_bit_set(k, bits) ? 1 : 0;
swap ^= k_t;
if (swap)
{
std::swap (x2, x3);
std::swap (z2, z3);
}
swap = k_t;
BN_mod_sub(tmp0, x3, z3, q, ctx);
BN_mod_sub(tmp1, x2, z2, q, ctx);
BN_mod_add(x2, x2, z2, q, ctx);
BN_mod_add(z2, x3, z3, q, ctx);
BN_mod_mul(z3, tmp0, x2, q, ctx);
BN_mod_mul(z2, z2, tmp1, q, ctx);
BN_mod_sqr(tmp0, tmp1, q, ctx);
BN_mod_sqr(tmp1, x2, q, ctx);
BN_mod_add(x3, z3, z2, q, ctx);
BN_mod_sub(z2, z3, z2, q, ctx);
BN_mod_mul(x2, tmp1, tmp0, q, ctx);
BN_mod_sub(tmp1, tmp1, tmp0, q, ctx);
BN_mod_sqr(z2, z2, q, ctx);
BN_mod_mul(z3, tmp1, c121666, q, ctx);
BN_mod_sqr(x3, x3, q, ctx);
BN_mod_add(tmp0, tmp0, z3, q, ctx);
BN_mod_mul(z3, x1, z2, q, ctx);
BN_mod_mul(z2, tmp1, tmp0, q, ctx);
}
if (swap)
{
std::swap (x2, x3);
std::swap (z2, z3);
}
BN_mod_inverse (z2, z2, q, ctx);
BIGNUM * res = BN_new (); // not from ctx
BN_mod_mul(res, x2, z2, q, ctx);
BN_CTX_end (ctx);
return res;
}
void Ed25519::ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const
{
BIGNUM * p1 = DecodeBN<32> (p);
uint8_t k[32];
memcpy (k, e, 32);
k[0] &= 248; k[31] &= 127; k[31] |= 64;
BIGNUM * n = DecodeBN<32> (k);
BIGNUM * q1 = ScalarMul (p1, n, ctx);
EncodeBN (q1, buf, 32);
BN_free (p1); BN_free (n); BN_free (q1);
}
void Ed25519::ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const
{
BIGNUM *p1 = BN_new (); BN_set_word (p1, 9);
uint8_t k[32];
memcpy (k, e, 32);
k[0] &= 248; k[31] &= 127; k[31] |= 64;
BIGNUM * n = DecodeBN<32> (k);
BIGNUM * q1 = ScalarMul (p1, n, ctx);
EncodeBN (q1, buf, 32);
BN_free (p1); BN_free (n); BN_free (q1);
}
#endif
void Ed25519::BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded)
{
BN_CTX * ctx = BN_CTX_new ();

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@ -84,7 +84,10 @@ namespace crypto
EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const;
EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const;
void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const;
#if !OPENSSL_X25519
void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519
void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const;
#endif
void BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
void BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
@ -112,6 +115,11 @@ namespace crypto
BIGNUM * DecodeBN (const uint8_t * buf) const;
void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const;
#if !OPENSSL_X25519
// for x25519
BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const;
#endif
private:
BIGNUM * q, * l, * d, * I;

View file

@ -103,7 +103,6 @@ namespace http
bool URL::parse(std::string_view url)
{
if (url.empty ()) return false;
std::size_t pos_p = 0; /* < current parse position */
std::size_t pos_c = 0; /* < work position */
if(url.at(0) != '/' || pos_p > 0)

View file

@ -375,8 +375,6 @@ namespace transport
m_Socket.close ();
transports.PeerDisconnected (shared_from_this ());
m_Server.RemoveNTCP2Session (shared_from_this ());
if (!m_IntermediateQueue.empty ())
m_SendQueue.splice (m_SendQueue.end (), m_IntermediateQueue);
for (auto& it: m_SendQueue)
it->Drop ();
m_SendQueue.clear ();
@ -1209,7 +1207,7 @@ namespace transport
void NTCP2Session::MoveSendQueue (std::shared_ptr<NTCP2Session> other)
{
if (!other || m_SendQueue.empty ()) return;
std::list<std::shared_ptr<I2NPMessage> > msgs;
std::vector<std::shared_ptr<I2NPMessage> > msgs;
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it: m_SendQueue)
if (!it->IsExpired (ts))
@ -1218,7 +1216,7 @@ namespace transport
it->Drop ();
m_SendQueue.clear ();
if (!msgs.empty ())
other->SendI2NPMessages (msgs);
other->PostI2NPMessages (msgs);
}
size_t NTCP2Session::CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len)
@ -1299,42 +1297,20 @@ namespace transport
m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); // let termination message go
}
void NTCP2Session::SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs)
void NTCP2Session::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
{
if (m_IsTerminated || msgs.empty ())
{
msgs.clear ();
return;
}
bool empty = false;
{
std::lock_guard<std::mutex> l(m_IntermediateQueueMutex);
empty = m_IntermediateQueue.empty ();
m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs);
}
if (empty)
m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this ()));
m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this (), msgs));
}
void NTCP2Session::PostI2NPMessages ()
void NTCP2Session::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
{
if (m_IsTerminated) return;
std::list<std::shared_ptr<I2NPMessage> > msgs;
{
std::lock_guard<std::mutex> l(m_IntermediateQueueMutex);
m_IntermediateQueue.swap (msgs);
}
bool isSemiFull = m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE/2;
if (isSemiFull)
{
for (auto it: msgs)
if (it->onDrop)
it->Drop (); // drop earlier because we can handle it
else
m_SendQueue.push_back (std::move (it));
}
else
m_SendQueue.splice (m_SendQueue.end (), msgs);
for (auto it: msgs)
if (isSemiFull && it->onDrop)
it->Drop (); // drop earlier because we can handle it
else
m_SendQueue.push_back (std::move (it));
if (!m_IsSending && m_IsEstablished)
SendQueue ();
@ -1846,7 +1822,7 @@ namespace transport
LogPrint(eLogError, "NTCP2: HTTP proxy write error ", ec.message());
});
auto readbuff = std::make_shared<boost::asio::streambuf>();
boost::asio::streambuf * readbuff = new boost::asio::streambuf;
boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n",
[readbuff, timer, conn] (const boost::system::error_code & ec, std::size_t transferred)
{
@ -1866,6 +1842,7 @@ namespace transport
{
timer->cancel();
conn->ClientLogin();
delete readbuff;
return;
}
else
@ -1875,6 +1852,7 @@ namespace transport
LogPrint(eLogError, "NTCP2: HTTP proxy gave malformed response");
timer->cancel();
conn->Terminate();
delete readbuff;
}
});
break;

View file

@ -153,7 +153,7 @@ namespace transport
void ServerLogin (); // Bob
void SendLocalRouterInfo (bool update) override; // after handshake or by update
void SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs) override;
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
void MoveSendQueue (std::shared_ptr<NTCP2Session> other);
private:
@ -196,7 +196,7 @@ namespace transport
void SendRouterInfo ();
void SendTermination (NTCP2TerminationReason reason);
void SendTerminationAndTerminate (NTCP2TerminationReason reason);
void PostI2NPMessages ();
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
private:
@ -229,10 +229,7 @@ namespace transport
bool m_IsSending, m_IsReceiving;
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
uint64_t m_NextRouterInfoResendTime; // seconds since epoch
std::list<std::shared_ptr<I2NPMessage> > m_IntermediateQueue; // from transports
mutable std::mutex m_IntermediateQueueMutex;
uint16_t m_PaddingSizes[16];
int m_NextPaddingSize;
};

View file

@ -480,7 +480,7 @@ namespace data
void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills)
{
LogPrint(eLogInfo, "NetDB: Reseeding from floodfill ", ri.GetIdentHashBase64());
std::list<std::shared_ptr<i2p::I2NPMessage> > requests;
std::vector<std::shared_ptr<i2p::I2NPMessage> > requests;
i2p::data::IdentHash ourIdent = i2p::context.GetIdentHash();
i2p::data::IdentHash ih = ri.GetIdentHash();

View file

@ -111,6 +111,7 @@ namespace transport
SendPeerTest (7, buf + offset, len - offset);
else
LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6");
GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ());
GetServer ().RequestRemoveSession (GetConnID ());
break;
}
@ -140,6 +141,7 @@ namespace transport
}
}
}
GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ());
GetServer ().RequestRemoveSession (GetConnID ());
break;
}
@ -186,7 +188,6 @@ namespace transport
i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16);
// send
GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ());
UpdateNumSentBytes (payloadSize + 32);
}
void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, bool delayed)
@ -308,7 +309,6 @@ namespace transport
i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16);
// send
GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep);
UpdateNumSentBytes (payloadSize + 32);
}
void SSU2HolePunchSession::SendHolePunch (const uint8_t * relayResponseBlock, size_t relayResponseBlockLen)

View file

@ -293,8 +293,6 @@ namespace transport
m_SentHandshakePacket.reset (nullptr);
m_SessionConfirmedFragment.reset (nullptr);
m_PathChallenge.reset (nullptr);
if (!m_IntermediateQueue.empty ())
m_SendQueue.splice (m_SendQueue.end (), m_IntermediateQueue);
for (auto& it: m_SendQueue)
it->Drop ();
m_SendQueue.clear ();
@ -374,31 +372,14 @@ namespace transport
}
void SSU2Session::SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs)
void SSU2Session::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
{
if (m_State == eSSU2SessionStateTerminated || msgs.empty ())
{
msgs.clear ();
return;
}
bool empty = false;
{
std::lock_guard<std::mutex> l(m_IntermediateQueueMutex);
empty = m_IntermediateQueue.empty ();
m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs);
}
if (empty)
m_Server.GetService ().post (std::bind (&SSU2Session::PostI2NPMessages, shared_from_this ()));
m_Server.GetService ().post (std::bind (&SSU2Session::PostI2NPMessages, shared_from_this (), msgs));
}
void SSU2Session::PostI2NPMessages ()
void SSU2Session::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
{
if (m_State == eSSU2SessionStateTerminated) return;
std::list<std::shared_ptr<I2NPMessage> > msgs;
{
std::lock_guard<std::mutex> l(m_IntermediateQueueMutex);
m_IntermediateQueue.swap (msgs);
}
uint64_t mts = i2p::util::GetMonotonicMicroseconds ();
bool isSemiFull = false;
if (m_SendQueue.size ())
@ -412,24 +393,16 @@ namespace transport
" is semi-full (size = ", m_SendQueue.size (), ", lag = ", queueLag / 1000, ", rtt = ", (int)m_RTT, ")");
}
}
if (isSemiFull)
{
for (auto it: msgs)
{
if (it->onDrop)
it->Drop (); // drop earlier because we can handle it
else
{
it->SetEnqueueTime (mts);
m_SendQueue.push_back (std::move (it));
}
}
}
else
for (auto it: msgs)
{
for (auto& it: msgs) it->SetEnqueueTime (mts);
m_SendQueue.splice (m_SendQueue.end (), msgs);
}
if (isSemiFull && it->onDrop)
it->Drop (); // drop earlier because we can handle it
else
{
it->SetEnqueueTime (mts);
m_SendQueue.push_back (std::move (it));
}
}
if (IsEstablished ())
{
SendQueue ();
@ -442,7 +415,7 @@ namespace transport
void SSU2Session::MoveSendQueue (std::shared_ptr<SSU2Session> other)
{
if (!other || m_SendQueue.empty ()) return;
std::list<std::shared_ptr<I2NPMessage> > msgs;
std::vector<std::shared_ptr<I2NPMessage> > msgs;
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it: m_SendQueue)
if (!it->IsExpired (ts))
@ -451,7 +424,7 @@ namespace transport
it->Drop ();
m_SendQueue.clear ();
if (!msgs.empty ())
other->SendI2NPMessages (msgs);
other->PostI2NPMessages (msgs);
}
bool SSU2Session::SendQueue ()

View file

@ -261,7 +261,7 @@ namespace transport
void FlushData ();
void Done () override;
void SendLocalRouterInfo (bool update) override;
void SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs) override;
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
void MoveSendQueue (std::shared_ptr<SSU2Session> other);
uint32_t GetRelayTag () const override { return m_RelayTag; };
size_t Resend (uint64_t ts); // return number of resent packets
@ -307,7 +307,7 @@ namespace transport
void Established ();
void ScheduleConnectTimer ();
void HandleConnectTimer (const boost::system::error_code& ecode);
void PostI2NPMessages ();
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
bool SendQueue (); // returns true if ack block was sent
bool SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg);
void ResendHandshakePacket ();
@ -381,8 +381,6 @@ namespace transport
std::unordered_map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
i2p::I2NPMessagesHandler m_Handler;
std::list<std::shared_ptr<I2NPMessage> > m_IntermediateQueue; // from transports
mutable std::mutex m_IntermediateQueueMutex;
bool m_IsDataReceived;
double m_RTT;
int m_MsgLocalExpirationTimeout;

View file

@ -1276,12 +1276,10 @@ namespace stream
else
m_WindowSize += (m_WindowSize - (1 - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize;
if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE;
m_WindowIncCounter--;
m_WindowIncCounter --;
UpdatePacingTime ();
}
else
break;
}
UpdatePacingTime ();
}
if (m_IsNAcked)
ResendPacket ();

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@ -59,7 +59,8 @@ namespace tunnel
auto num = m_TunnelDataMsgs.size ();
if (num > 1)
LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num);
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs); // send and clear
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs);
m_TunnelDataMsgs.clear ();
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@ -10,7 +10,7 @@
#define TRANSIT_TUNNEL_H__
#include <inttypes.h>
#include <list>
#include <vector>
#include <mutex>
#include <memory>
#include "Crypto.h"
@ -61,7 +61,7 @@ namespace tunnel
private:
size_t m_NumTransmittedBytes;
std::list<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
};
class TransitTunnelGateway: public TransitTunnel

View file

@ -144,12 +144,8 @@ namespace transport
void SetLastActivityTimestamp (uint64_t ts) { m_LastActivityTimestamp = ts; };
virtual uint32_t GetRelayTag () const { return 0; };
virtual void SendLocalRouterInfo (bool update = false)
{
std::list<std::shared_ptr<I2NPMessage> > msgs{ CreateDatabaseStoreMsg () };
SendI2NPMessages (msgs);
};
virtual void SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs) = 0;
virtual void SendLocalRouterInfo (bool update = false) { SendI2NPMessages ({ CreateDatabaseStoreMsg () }); };
virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0;
virtual bool IsEstablished () const = 0;
private:

View file

@ -25,7 +25,7 @@ namespace transport
{
template<typename Keys>
EphemeralKeysSupplier<Keys>::EphemeralKeysSupplier (int size):
m_QueueSize (size), m_IsRunning (false)
m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr)
{
}
@ -39,7 +39,7 @@ namespace transport
void EphemeralKeysSupplier<Keys>::Start ()
{
m_IsRunning = true;
m_Thread.reset (new std::thread (std::bind (&EphemeralKeysSupplier<Keys>::Run, this)));
m_Thread = new std::thread (std::bind (&EphemeralKeysSupplier<Keys>::Run, this));
}
template<typename Keys>
@ -53,7 +53,8 @@ namespace transport
if (m_Thread)
{
m_Thread->join ();
m_Thread = nullptr;
delete m_Thread;
m_Thread = 0;
}
}
@ -65,19 +66,18 @@ namespace transport
while (m_IsRunning)
{
int num, total = 0;
while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < m_QueueSize)
while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 10)
{
CreateEphemeralKeys (num);
total += num;
}
if (total > m_QueueSize)
if (total >= 10)
{
LogPrint (eLogWarning, "Transports: ", total, " ephemeral keys generated at the time");
std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break
}
else
{
m_KeysPool.CleanUpMt ();
std::unique_lock<std::mutex> l(m_AcquiredMutex);
if (!m_IsRunning) break;
m_Acquired.wait (l); // wait for element gets acquired
@ -92,7 +92,7 @@ namespace transport
{
for (int i = 0; i < num; i++)
{
auto pair = m_KeysPool.AcquireSharedMt ();
auto pair = std::make_shared<Keys> ();
pair->GenerateKeys ();
std::unique_lock<std::mutex> l(m_AcquiredMutex);
m_Queue.push (pair);
@ -114,7 +114,7 @@ namespace transport
}
}
// queue is empty, create new
auto pair = m_KeysPool.AcquireSharedMt ();
auto pair = std::make_shared<Keys> ();
pair->GenerateKeys ();
return pair;
}
@ -124,12 +124,12 @@ namespace transport
{
if (pair)
{
std::unique_lock<std::mutex> l(m_AcquiredMutex);
std::unique_lock<std::mutex>l(m_AcquiredMutex);
if ((int)m_Queue.size () < 2*m_QueueSize)
m_Queue.push (pair);
}
else
LogPrint(eLogError, "Transports: Return null keys");
LogPrint(eLogError, "Transports: Return null DHKeys");
}
void Peer::UpdateParams (std::shared_ptr<const i2p::data::RouterInfo> router)
@ -149,7 +149,7 @@ namespace transport
m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_CheckReserved(true), m_Thread (nullptr),
m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
m_UpdateBandwidthTimer (nullptr), m_SSU2Server (nullptr), m_NTCP2Server (nullptr),
m_X25519KeysPairSupplier (NUM_X25519_PRE_GENERATED_KEYS),
m_X25519KeysPairSupplier (15), // 15 pre-generated keys
m_TotalSentBytes (0), m_TotalReceivedBytes (0), m_TotalTransitTransmittedBytes (0),
m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth (0),
m_InBandwidth15s (0), m_OutBandwidth15s (0), m_TransitBandwidth15s (0),
@ -450,25 +450,15 @@ namespace transport
void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
{
if (m_IsOnline)
SendMessages (ident, { msg });
SendMessages (ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > {msg });
}
void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs)
void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs)
{
std::list<std::shared_ptr<i2p::I2NPMessage> > msgs1;
msgs.swap (msgs1);
SendMessages (ident, std::move (msgs1));
m_Service->post (std::bind (&Transports::PostMessages, this, ident, msgs));
}
void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >&& msgs)
{
m_Service->post ([this, ident, msgs = std::move(msgs)] () mutable
{
PostMessages (ident, msgs);
});
}
void Transports::PostMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs)
void Transports::PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs)
{
if (ident == i2p::context.GetRouterInfo ().GetIdentHash ())
{
@ -480,13 +470,8 @@ namespace transport
}
if(RoutesRestricted() && !IsRestrictedPeer(ident)) return;
std::shared_ptr<Peer> peer;
{
std::lock_guard<std::mutex> l(m_PeersMutex);
auto it = m_Peers.find (ident);
if (it != m_Peers.end ())
peer = it->second;
}
if (!peer)
auto it = m_Peers.find (ident);
if (it == m_Peers.end ())
{
// check if not banned
if (i2p::data::IsRouterBanned (ident)) return; // don't create peer to unreachable router
@ -496,10 +481,10 @@ namespace transport
{
auto r = netdb.FindRouter (ident);
if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return; // router found but non-reachable
peer = std::make_shared<Peer>(r, i2p::util::GetSecondsSinceEpoch ());
{
std::lock_guard<std::mutex> l(m_PeersMutex);
{
auto ts = i2p::util::GetSecondsSinceEpoch ();
peer = std::make_shared<Peer>(r, ts);
std::unique_lock<std::mutex> l(m_PeersMutex);
peer = m_Peers.emplace (ident, peer).first->second;
}
if (peer)
@ -511,6 +496,8 @@ namespace transport
}
if (!connected) return;
}
else
peer = it->second;
if (!peer) return;
if (peer->IsConnected ())
@ -525,27 +512,22 @@ namespace transport
if (i2p::data::IsRouterBanned (ident))
{
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
std::lock_guard<std::mutex> l(m_PeersMutex);
std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (ident);
return;
}
}
if (sz > MAX_NUM_DELAYED_MESSAGES/2)
{
for (auto& it1: msgs)
if (it1->onDrop)
it1->Drop (); // drop earlier because we can handle it
else
peer->delayedMessages.push_back (it1);
}
else
peer->delayedMessages.splice (peer->delayedMessages.end (), msgs);
for (auto& it1: msgs)
if (sz > MAX_NUM_DELAYED_MESSAGES/2 && it1->onDrop)
it1->Drop (); // drop earlier because we can handle it
else
peer->delayedMessages.push_back (it1);
}
else
{
LogPrint (eLogWarning, "Transports: Delayed messages queue size to ",
ident.ToBase64 (), " exceeds ", MAX_NUM_DELAYED_MESSAGES);
std::lock_guard<std::mutex> l(m_PeersMutex);
std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (ident);
}
}
@ -620,7 +602,7 @@ namespace transport
if (!i2p::context.IsLimitedConnectivity () && peer->router->IsReachableFrom (i2p::context.GetRouterInfo ()))
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed but router claimed them
peer->Done ();
std::lock_guard<std::mutex> l(m_PeersMutex);
std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (ident);
return false;
}
@ -628,7 +610,7 @@ namespace transport
{
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
peer->Done ();
std::lock_guard<std::mutex> l(m_PeersMutex);
std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (ident);
return false;
}
@ -724,29 +706,23 @@ namespace transport
void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident)
{
std::shared_ptr<Peer> peer;
auto it = m_Peers.find (ident);
if (it != m_Peers.end ())
{
std::lock_guard<std::mutex> l(m_PeersMutex);
auto it = m_Peers.find (ident);
if (it != m_Peers.end ())
if (r)
{
if (r)
peer = it->second;
else
m_Peers.erase (it);
}
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect");
it->second->SetRouter (r);
if (!it->second->IsConnected ())
ConnectToPeer (ident, it->second);
}
else
{
LogPrint (eLogWarning, "Transports: RouterInfo not found, failed to send messages");
std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (it);
}
}
if (peer && !peer->router && r)
{
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect");
peer->SetRouter (r);
if (!peer->IsConnected ())
ConnectToPeer (ident, peer);
}
else if (!r)
LogPrint (eLogInfo, "Transports: RouterInfo not found, failed to send messages");
}
void Transports::DetectExternalIP ()
@ -889,7 +865,7 @@ namespace transport
if (it->second->delayedMessages.size () > 0)
{
// check if first message is our DatabaseStore (publishing)
auto firstMsg = peer->delayedMessages.front ();
auto firstMsg = peer->delayedMessages[0];
if (firstMsg && firstMsg->GetTypeID () == eI2NPDatabaseStore &&
i2p::data::IdentHash(firstMsg->GetPayload () + DATABASE_STORE_KEY_OFFSET) == i2p::context.GetIdentHash ())
sendDatabaseStore = false; // we have it in the list already
@ -899,7 +875,8 @@ namespace transport
else
session->SetTerminationTimeout (10); // most likely it's publishing, no follow-up messages expected, set timeout to 10 seconds
peer->sessions.push_back (session);
session->SendI2NPMessages (peer->delayedMessages); // send and clear
session->SendI2NPMessages (peer->delayedMessages);
peer->delayedMessages.clear ();
}
else // incoming connection or peer test
{
@ -910,17 +887,14 @@ namespace transport
return;
}
if (!session->IsOutgoing ()) // incoming
{
std::list<std::shared_ptr<I2NPMessage> > msgs{ CreateDatabaseStoreMsg () };
session->SendI2NPMessages (msgs); // send DatabaseStore
}
session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore
auto r = i2p::data::netdb.FindRouter (ident); // router should be in netdb after SessionConfirmed
if (r) r->GetProfile ()->Connected ();
auto ts = i2p::util::GetSecondsSinceEpoch ();
auto peer = std::make_shared<Peer>(r, ts);
peer->sessions.push_back (session);
peer->router = nullptr;
std::lock_guard<std::mutex> l(m_PeersMutex);
std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.emplace (ident, peer);
}
});
@ -949,7 +923,7 @@ namespace transport
}
else
{
std::lock_guard<std::mutex> l(m_PeersMutex);
std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (it);
}
}
@ -959,13 +933,9 @@ namespace transport
bool Transports::IsConnected (const i2p::data::IdentHash& ident) const
{
std::lock_guard<std::mutex> l(m_PeersMutex);
#if __cplusplus >= 202002L // C++20
return m_Peers.contains (ident);
#else
std::unique_lock<std::mutex> l(m_PeersMutex);
auto it = m_Peers.find (ident);
return it != m_Peers.end ();
#endif
}
void Transports::HandlePeerCleanupTimer (const boost::system::error_code& ecode)
@ -989,7 +959,7 @@ namespace transport
auto profile = i2p::data::GetRouterProfile (it->first);
if (profile) profile->Unreachable ();
} */
std::lock_guard<std::mutex> l(m_PeersMutex);
std::unique_lock<std::mutex> l(m_PeersMutex);
it = m_Peers.erase (it);
}
else
@ -1039,7 +1009,7 @@ namespace transport
{
uint16_t inds[3];
RAND_bytes ((uint8_t *)inds, sizeof (inds));
std::lock_guard<std::mutex> l(m_PeersMutex);
std::unique_lock<std::mutex> l(m_PeersMutex);
auto count = m_Peers.size ();
if(count == 0) return nullptr;
inds[0] %= count;

View file

@ -26,7 +26,6 @@
#include "RouterInfo.h"
#include "I2NPProtocol.h"
#include "Identity.h"
#include "util.h"
namespace i2p
{
@ -54,10 +53,9 @@ namespace transport
const int m_QueueSize;
std::queue<std::shared_ptr<Keys> > m_Queue;
i2p::util::MemoryPoolMt<Keys> m_KeysPool;
bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread;
std::thread * m_Thread;
std::condition_variable m_Acquired;
std::mutex m_AcquiredMutex;
};
@ -73,7 +71,7 @@ namespace transport
std::shared_ptr<const i2p::data::RouterInfo> router;
std::list<std::shared_ptr<TransportSession> > sessions;
uint64_t creationTime, nextRouterInfoUpdateTime, lastSelectionTime;
std::list<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
std::vector<i2p::data::RouterInfo::SupportedTransports> priority;
bool isHighBandwidth, isEligible;
@ -110,8 +108,7 @@ namespace transport
const int PEER_TEST_DELAY_INTERVAL_VARIANCE = 30; // in milliseconds
const int MAX_NUM_DELAYED_MESSAGES = 150;
const int CHECK_PROFILE_NUM_DELAYED_MESSAGES = 15; // check profile after
const int NUM_X25519_PRE_GENERATED_KEYS = 25; // pre-generated x25519 keys pairs
const int TRAFFIC_SAMPLE_COUNT = 301; // seconds
struct TrafficSample
@ -144,8 +141,7 @@ namespace transport
void ReuseX25519KeysPair (std::shared_ptr<i2p::crypto::X25519Keys> pair);
void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg);
void SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs);
void SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >&& msgs);
void SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs);
void PeerConnected (std::shared_ptr<TransportSession> session);
void PeerDisconnected (std::shared_ptr<TransportSession> session);
@ -189,7 +185,7 @@ namespace transport
void Run ();
void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident);
void PostMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs);
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
bool ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr<Peer> peer);
void SetPriority (std::shared_ptr<Peer> peer) const;
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);

View file

@ -221,7 +221,7 @@ namespace tunnel
void TunnelGateway::SendBuffer ()
{
m_Buffer.CompleteCurrentTunnelDataMessage ();
std::list<std::shared_ptr<I2NPMessage> > newTunnelMsgs;
std::vector<std::shared_ptr<I2NPMessage> > newTunnelMsgs;
const auto& tunnelDataMsgs = m_Buffer.GetTunnelDataMsgs ();
for (auto& tunnelMsg : tunnelDataMsgs)
{
@ -234,7 +234,7 @@ namespace tunnel
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
}
m_Buffer.ClearTunnelDataMsgs ();
i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), std::move (newTunnelMsgs));
i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), newTunnelMsgs);
}
}
}

View file

@ -305,7 +305,7 @@ namespace client
identHash = hash;
}
AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false),
AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_IsDownloading (false),
m_NumRetries (0), m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr),
m_IsEnabled (true)
{
@ -344,28 +344,20 @@ namespace client
delete m_SubscriptionsUpdateTimer;
m_SubscriptionsUpdateTimer = nullptr;
}
bool isDownloading = m_Downloading.valid ();
if (isDownloading)
if (m_IsDownloading)
{
if (m_Downloading.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
isDownloading = false;
else
{
LogPrint (eLogInfo, "Addressbook: Subscriptions are downloading, abort");
for (int i = 0; i < 30; i++)
LogPrint (eLogInfo, "Addressbook: Subscriptions are downloading, abort");
for (int i = 0; i < 30; i++)
{
if (!m_IsDownloading)
{
if (m_Downloading.wait_for(std::chrono::seconds(1)) == std::future_status::ready) // wait for 1 seconds
{
isDownloading = false;
LogPrint (eLogInfo, "Addressbook: Subscriptions download complete");
break;
}
LogPrint (eLogInfo, "Addressbook: Subscriptions download complete");
break;
}
}
if (!isDownloading)
m_Downloading.get ();
else
LogPrint (eLogError, "Addressbook: Subscription download timeout");
std::this_thread::sleep_for (std::chrono::seconds (1)); // wait for 1 seconds
}
LogPrint (eLogError, "Addressbook: Subscription download timeout");
m_IsDownloading = false;
}
if (m_Storage)
{
@ -590,15 +582,16 @@ namespace client
}
else
{
LogPrint (eLogInfo, "Addressbook: Loading subscriptions from config");
LogPrint (eLogInfo, "Addressbook: Loading subscriptions from config file");
// using config file items
std::string subscriptionURLs; i2p::config::GetOption("addressbook.subscriptions", subscriptionURLs);
std::vector<std::string> subsList;
boost::split(subsList, subscriptionURLs, boost::is_any_of(","), boost::token_compress_on);
for (const auto& s: subsList)
if (!s.empty ())
m_Subscriptions.push_back (std::make_shared<AddressBookSubscription> (*this, s));
{
m_Subscriptions.push_back (std::make_shared<AddressBookSubscription> (*this, s));
}
LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded");
}
}
@ -652,6 +645,7 @@ namespace client
void AddressBook::DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified)
{
m_IsDownloading = false;
m_NumRetries++;
int nextUpdateTimeout = m_NumRetries*CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT;
if (m_NumRetries > CONTINIOUS_SUBSCRIPTION_MAX_NUM_RETRIES || nextUpdateTimeout > CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT)
@ -706,13 +700,7 @@ namespace client
LogPrint(eLogWarning, "Addressbook: Missing local destination, skip subscription update");
return;
}
bool isDownloading = m_Downloading.valid ();
if (isDownloading && m_Downloading.wait_for(std::chrono::seconds(0)) == std::future_status::ready) // still active?
{
m_Downloading.get ();
isDownloading = false;
}
if (!isDownloading && dest->IsReady ())
if (!m_IsDownloading && dest->IsReady ())
{
if (!m_IsLoaded)
{
@ -721,15 +709,17 @@ namespace client
std::string defaultSubURL; i2p::config::GetOption("addressbook.defaulturl", defaultSubURL);
if (!m_DefaultSubscription)
m_DefaultSubscription = std::make_shared<AddressBookSubscription>(*this, defaultSubURL);
m_Downloading = std::async (std::launch::async,
std::bind (&AddressBookSubscription::CheckUpdates, m_DefaultSubscription));
m_IsDownloading = true;
std::thread load_hosts(std::bind (&AddressBookSubscription::CheckUpdates, m_DefaultSubscription));
load_hosts.detach(); // TODO: use join
}
else if (!m_Subscriptions.empty ())
{
// pick random subscription
auto ind = rand () % m_Subscriptions.size();
m_Downloading = std::async (std::launch::async,
std::bind (&AddressBookSubscription::CheckUpdates, m_Subscriptions[ind]));
m_IsDownloading = true;
std::thread load_hosts(std::bind (&AddressBookSubscription::CheckUpdates, m_Subscriptions[ind]));
load_hosts.detach(); // TODO: use join
}
}
else
@ -833,7 +823,7 @@ namespace client
}
}
AddressBookSubscription::AddressBookSubscription (AddressBook& book, std::string_view link):
AddressBookSubscription::AddressBookSubscription (AddressBook& book, const std::string& link):
m_Book (book), m_Link (link)
{
}

View file

@ -11,12 +11,10 @@
#include <string.h>
#include <string>
#include <string_view>
#include <map>
#include <vector>
#include <iostream>
#include <mutex>
#include <future>
#include <memory>
#include <boost/asio.hpp>
#include "Base.h"
@ -126,8 +124,7 @@ namespace client
std::mutex m_LookupsMutex;
std::map<uint32_t, std::string> m_Lookups; // nonce -> address
AddressBookStorage * m_Storage;
volatile bool m_IsLoaded;
std::future<void> m_Downloading;
volatile bool m_IsLoaded, m_IsDownloading;
int m_NumRetries;
std::vector<std::shared_ptr<AddressBookSubscription> > m_Subscriptions;
std::shared_ptr<AddressBookSubscription> m_DefaultSubscription; // in case if we don't know any addresses yet
@ -139,7 +136,7 @@ namespace client
{
public:
AddressBookSubscription (AddressBook& book, std::string_view link);
AddressBookSubscription (AddressBook& book, const std::string& link);
void CheckUpdates ();
private:

View file

@ -203,7 +203,7 @@ namespace client
std::vector<std::shared_ptr<DatagramSessionInfo> > sessions;
std::lock_guard<std::mutex> lock (m_SessionsMutex);
for (const auto &it: m_Sessions)
for (auto it: m_Sessions)
{
auto s = it.second;
if (!s->m_Destination) continue;

View file

@ -49,6 +49,10 @@ set(test-gost-sig_SRCS
test-gost-sig.cpp
)
set(test-x25519_SRCS
test-x25519.cpp
)
set(test-aeadchacha20poly1305_SRCS
test-aeadchacha20poly1305.cpp
)
@ -73,6 +77,7 @@ add_executable(test-http-url ${test-http-url_SRCS})
add_executable(test-base-64 ${test-base-64_SRCS})
add_executable(test-gost ${test-gost_SRCS})
add_executable(test-gost-sig ${test-gost-sig_SRCS})
add_executable(test-x25519 ${test-x25519_SRCS})
add_executable(test-aeadchacha20poly1305 ${test-aeadchacha20poly1305_SRCS})
add_executable(test-blinding ${test-blinding_SRCS})
add_executable(test-elligator ${test-elligator_SRCS})
@ -97,6 +102,7 @@ target_link_libraries(test-http-url ${LIBS})
target_link_libraries(test-base-64 ${LIBS})
target_link_libraries(test-gost ${LIBS})
target_link_libraries(test-gost-sig ${LIBS})
target_link_libraries(test-x25519 ${LIBS})
target_link_libraries(test-aeadchacha20poly1305 ${LIBS})
target_link_libraries(test-blinding ${LIBS})
target_link_libraries(test-elligator ${LIBS})
@ -110,6 +116,7 @@ add_test(test-http-url ${TEST_PATH}/test-http-url)
add_test(test-base-64 ${TEST_PATH}/test-base-64)
add_test(test-gost ${TEST_PATH}/test-gost)
add_test(test-gost-sig ${TEST_PATH}/test-gost-sig)
add_test(test-x25519 ${TEST_PATH}/test-x25519)
add_test(test-aeadchacha20poly1305 ${TEST_PATH}/test-aeadchacha20poly1305)
add_test(test-blinding ${TEST_PATH}/test-blinding)
add_test(test-elligator ${TEST_PATH}/test-elligator)

View file

@ -7,7 +7,7 @@ LIBI2PD = ../libi2pd.a
TESTS = \
test-http-merge_chunked test-http-req test-http-res test-http-url test-http-url_decode \
test-gost test-gost-sig test-base-64 test-aeadchacha20poly1305 test-blinding \
test-gost test-gost-sig test-base-64 test-x25519 test-aeadchacha20poly1305 test-blinding \
test-elligator test-eddsa
ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
@ -44,6 +44,9 @@ test-gost: test-gost.cpp $(LIBI2PD)
test-gost-sig: test-gost-sig.cpp $(LIBI2PD)
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
test-x25519: test-x25519.cpp $(LIBI2PD)
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
test-aeadchacha20poly1305: test-aeadchacha20poly1305.cpp $(LIBI2PD)
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)

38
tests/test-x25519.cpp Normal file
View file

@ -0,0 +1,38 @@
#include <cassert>
#include <inttypes.h>
#include <string.h>
#include "Ed25519.h"
const uint8_t k[32] =
{
0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15,
0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc,
0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4
};
const uint8_t u[32] =
{
0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1,
0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3,
0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c
};
uint8_t p[32] =
{
0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea,
0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c,
0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52
};
int main ()
{
#if !OPENSSL_X25519
// we test it for openssl < 1.1.0
uint8_t buf[32];
BN_CTX * ctx = BN_CTX_new ();
i2p::crypto::GetEd25519 ()->ScalarMul (u, k, buf, ctx);
BN_CTX_free (ctx);
assert(memcmp (buf, p, 32) == 0);
#endif
}