Compare commits

..

2 Commits

Author SHA1 Message Date
Nikita Misiura
f8cac15d0c Merge 32a70562c4 into a1794ccd22 2025-03-05 01:14:11 +03:00
self-related
32a70562c4 Fix UPnP: error 2 2024-08-19 00:07:22 +03:00
10 changed files with 73 additions and 194 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2025, The PurpleI2P Project
* Copyright (c) 2013-2024, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -15,6 +15,7 @@
// Use global placeholders from boost introduced when local_time.hpp is loaded
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <boost/property_tree/json_parser.hpp>
#include <boost/lexical_cast.hpp>
#include "FS.h"
#include "Log.h"
@@ -29,24 +30,11 @@ namespace i2p
namespace client
{
I2PControlService::I2PControlService (const std::string& address, int port):
m_IsRunning (false),
m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(address), port)),
m_SSLContext (boost::asio::ssl::context::sslv23),
m_ShutdownTimer (m_Service)
{
if (port)
m_Acceptor = std::make_unique<boost::asio::ip::tcp::acceptor>(m_Service,
boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(address), port));
else
#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
{
std::remove (address.c_str ()); // just in case
m_LocalAcceptor = std::make_unique<boost::asio::local::stream_protocol::acceptor>(m_Service,
boost::asio::local::stream_protocol::endpoint(address));
}
#else
LogPrint(eLogError, "I2PControl: Local sockets are not supported");
#endif
i2p::config::GetOption("i2pcontrol.password", m_Password);
// certificate / keys
@@ -110,7 +98,7 @@ namespace client
{
Accept ();
m_IsRunning = true;
m_Thread = std::make_unique<std::thread>(std::bind (&I2PControlService::Run, this));
m_Thread = new std::thread (std::bind (&I2PControlService::Run, this));
}
}
@@ -119,19 +107,12 @@ namespace client
if (m_IsRunning)
{
m_IsRunning = false;
if (m_Acceptor) m_Acceptor->cancel ();
#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
if (m_LocalAcceptor)
{
auto path = m_LocalAcceptor->local_endpoint().path();
m_LocalAcceptor->cancel ();
std::remove (path.c_str ());
}
#endif
m_Acceptor.cancel ();
m_Service.stop ();
if (m_Thread)
{
m_Thread->join ();
delete m_Thread;
m_Thread = nullptr;
}
}
@@ -153,60 +134,40 @@ namespace client
void I2PControlService::Accept ()
{
if (m_Acceptor)
{
auto newSocket = std::make_shared<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> > (m_Service, m_SSLContext);
m_Acceptor->async_accept (newSocket->lowest_layer(),
[this, newSocket](const boost::system::error_code& ecode)
{
HandleAccepted (ecode, newSocket);
});
}
#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
else if (m_LocalAcceptor)
{
auto newSocket = std::make_shared<boost::asio::ssl::stream<boost::asio::local::stream_protocol::socket> > (m_Service, m_SSLContext);
m_LocalAcceptor->async_accept (newSocket->lowest_layer(),
[this, newSocket](const boost::system::error_code& ecode)
{
HandleAccepted (ecode, newSocket);
});
}
#endif
auto newSocket = std::make_shared<ssl_socket> (m_Service, m_SSLContext);
m_Acceptor.async_accept (newSocket->lowest_layer(), std::bind (&I2PControlService::HandleAccept, this,
std::placeholders::_1, newSocket));
}
template<typename ssl_socket>
void I2PControlService::HandleAccepted (const boost::system::error_code& ecode,
std::shared_ptr<ssl_socket> newSocket)
void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket)
{
if (ecode != boost::asio::error::operation_aborted)
Accept ();
if (ecode)
{
if (ecode) {
LogPrint (eLogError, "I2PControl: Accept error: ", ecode.message ());
return;
}
LogPrint (eLogDebug, "I2PControl: New request from ", newSocket->lowest_layer ().remote_endpoint ());
Handshake (newSocket);
}
template<typename ssl_socket>
LogPrint (eLogDebug, "I2PControl: New request from ", socket->lowest_layer ().remote_endpoint ());
Handshake (socket);
}
void I2PControlService::Handshake (std::shared_ptr<ssl_socket> socket)
{
socket->async_handshake(boost::asio::ssl::stream_base::server,
[this, socket](const boost::system::error_code& ecode)
{
if (ecode)
{
LogPrint (eLogError, "I2PControl: Handshake error: ", ecode.message ());
return;
}
ReadRequest (socket);
});
std::bind( &I2PControlService::HandleHandshake, this, std::placeholders::_1, socket));
}
void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket)
{
if (ecode) {
LogPrint (eLogError, "I2PControl: Handshake error: ", ecode.message ());
return;
}
//std::this_thread::sleep_for (std::chrono::milliseconds(5));
ReadRequest (socket);
}
template<typename ssl_socket>
void I2PControlService::ReadRequest (std::shared_ptr<ssl_socket> socket)
{
auto request = std::make_shared<I2PControlBuffer>();
@@ -216,13 +177,10 @@ namespace client
#else
boost::asio::buffer (request->data (), request->size ()),
#endif
[this, socket, request](const boost::system::error_code& ecode, size_t bytes_transferred)
{
HandleRequestReceived (ecode, bytes_transferred, socket, request);
});
std::bind(&I2PControlService::HandleRequestReceived, this,
std::placeholders::_1, std::placeholders::_2, socket, request));
}
template<typename ssl_socket>
void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode,
size_t bytes_transferred, std::shared_ptr<ssl_socket> socket,
std::shared_ptr<I2PControlBuffer> buf)
@@ -300,7 +258,6 @@ namespace client
}
}
template<typename ssl_socket>
void I2PControlService::SendResponse (std::shared_ptr<ssl_socket> socket,
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml)
{
@@ -310,7 +267,7 @@ namespace client
std::ostringstream header;
header << "HTTP/1.1 200 OK\r\n";
header << "Connection: close\r\n";
header << "Content-Length: " << std::to_string(len) << "\r\n";
header << "Content-Length: " << boost::lexical_cast<std::string>(len) << "\r\n";
header << "Content-Type: application/json\r\n";
header << "Date: ";
std::time_t t = std::time (nullptr);
@@ -323,11 +280,16 @@ namespace client
memcpy (buf->data () + offset, response.str ().c_str (), len);
boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), offset + len),
boost::asio::transfer_all (),
[socket, buf](const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (ecode)
LogPrint (eLogError, "I2PControl: Write error: ", ecode.message ());
});
std::bind(&I2PControlService::HandleResponseSent, this,
std::placeholders::_1, std::placeholders::_2, socket, buf));
}
void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf)
{
if (ecode) {
LogPrint (eLogError, "I2PControl: Write error: ", ecode.message ());
}
}
// handlers

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2025, The PurpleI2P Project
* Copyright (c) 2013-2024, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -35,6 +35,8 @@ namespace client
class I2PControlService: public I2PControlHandlers
{
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
public:
I2PControlService (const std::string& address, int port);
@@ -47,18 +49,16 @@ namespace client
void Run ();
void Accept ();
template<typename ssl_socket>
void HandleAccepted (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> newSocket);
template<typename ssl_socket>
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket);
void Handshake (std::shared_ptr<ssl_socket> socket);
template<typename ssl_socket>
void HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket);
void ReadRequest (std::shared_ptr<ssl_socket> socket);
template<typename ssl_socket>
void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred,
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf);
template<typename ssl_socket>
void SendResponse (std::shared_ptr<ssl_socket> socket,
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml);
void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf);
void CreateCertificate (const char *crt_path, const char *key_path);
@@ -86,13 +86,10 @@ namespace client
std::string m_Password;
bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread;
std::thread * m_Thread;
boost::asio::io_context m_Service;
std::unique_ptr<boost::asio::ip::tcp::acceptor> m_Acceptor;
#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
std::unique_ptr<boost::asio::local::stream_protocol::acceptor> m_LocalAcceptor;
#endif
boost::asio::ip::tcp::acceptor m_Acceptor;
boost::asio::ssl::context m_SSLContext;
boost::asio::deadline_timer m_ShutdownTimer;
std::set<std::string> m_Tokens;

View File

@@ -122,7 +122,7 @@ namespace transport
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
#endif
m_upnpUrlsInitialized=err!=0;
if (err == UPNP_IGD_VALID_CONNECTED)
if (err == UPNP_IGD_VALID_CONNECTED || err == UPNP_IGD_VALID_NOT_CONNECTED)
{
#if (MINIUPNPC_API_VERSION < 18)
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);

View File

@@ -399,8 +399,12 @@ namespace data
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetEncryptor>(key);
break;
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
return std::make_shared<i2p::crypto::ECIESP256Encryptor>(key);
break;
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
return std::make_shared<i2p::crypto::ECIESGOSTR3410Encryptor>(key);
break;
default:
LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)keyType);
};
@@ -669,8 +673,12 @@ namespace data
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key);
break;
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
return std::make_shared<i2p::crypto::ECIESP256Decryptor>(key);
break;
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
return std::make_shared<i2p::crypto::ECIESGOSTR3410Decryptor>(key);
break;
default:
LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType);
};
@@ -745,8 +753,12 @@ namespace data
i2p::crypto::GenerateElGamalKeyPair(priv, pub);
break;
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
i2p::crypto::CreateECIESP256RandomKeys (priv, pub);
break;
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
i2p::crypto::CreateECIESGOSTR3410RandomKeys (priv, pub);
break;
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD:
i2p::crypto::CreateECIESX25519AEADRatchetRandomKeys (priv, pub);
break;

View File

@@ -64,7 +64,9 @@ namespace data
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 1;
const uint16_t CRYPTO_KEY_TYPE_ECIES_X25519_AEAD = 4;
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST = 65280; // TODO: remove later
const uint16_t CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC = 65281; // TODO: use GOST R 34.11 instead SHA256 and GOST 28147-89 instead AES
const uint16_t SIGNING_KEY_TYPE_DSA_SHA1 = 0;
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA256_P256 = 1;
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA384_P384 = 2;
@@ -73,7 +75,7 @@ namespace data
const uint16_t SIGNING_KEY_TYPE_RSA_SHA384_3072 = 5;
const uint16_t SIGNING_KEY_TYPE_RSA_SHA512_4096 = 6;
const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 = 7;
const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519ph = 8; // since openssl 3.0.0
const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519ph = 8; // not implemented
const uint16_t SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256 = 9;
const uint16_t SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512 = 10; // approved by FSB
const uint16_t SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519 = 11; // for LeaseSet2 only

View File

@@ -310,7 +310,7 @@ namespace data
{
if (it->second->IsUpdated () && ts > it->second->GetLastPersistTime () + PEER_PROFILE_PERSIST_INTERVAL)
{
tmp.push_back (*it);
tmp.push_back (std::make_pair (it->first, it->second));
it->second->SetLastPersistTime (ts);
it->second->SetUpdated (false);
}

View File

@@ -41,7 +41,7 @@ namespace data
const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE = 2400; // in seconds (40 minutes)
const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 330; // in seconds (5.5 minutes)
const int PEER_PROFILE_MAX_DECLINED_INTERVAL = 4400; // in second (1.5 hours)
const int PEER_PROFILE_PERSIST_INTERVAL = 1320; // in seconds (22 minutes)
const int PEER_PROFILE_PERSIST_INTERVAL = 3300; // in seconds (55 minutes)
const int PEER_PROFILE_UNREACHABLE_INTERVAL = 480; // in seconds (8 minutes)
const int PEER_PROFILE_USEFUL_THRESHOLD = 3;
const int PEER_PROFILE_ALWAYS_DECLINING_NUM = 5; // num declines in row to consider always declined

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2025, The PurpleI2P Project
* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -149,56 +149,5 @@ namespace crypto
LogPrint (eLogError, "EdDSA signing key is not set");
}
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x030000000)
static const OSSL_PARAM EDDSA25519phParams[] =
{
OSSL_PARAM_utf8_string ("instance", (char *)"Ed25519ph", 9),
OSSL_PARAM_END
};
bool EDDSA25519phVerifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
auto pkey = GetPkey ();
if (pkey)
{
uint8_t digest[64];
SHA512 (buf, len, digest);
EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
EVP_DigestVerifyInit_ex (ctx, NULL, NULL, NULL, NULL, pkey, EDDSA25519phParams);
auto ret = EVP_DigestVerify (ctx, signature, 64, digest, 64);
EVP_MD_CTX_destroy (ctx);
return ret;
}
else
LogPrint (eLogError, "EdDSA verification key is not set");
return false;
}
EDDSA25519phSigner::EDDSA25519phSigner (const uint8_t * signingPrivateKey):
EDDSA25519Signer (signingPrivateKey)
{
}
void EDDSA25519phSigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const
{
auto pkey = GetPkey ();
if (pkey)
{
uint8_t digest[64];
SHA512 (buf, len, digest);
EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
size_t l = 64;
uint8_t sig[64];
EVP_DigestSignInit_ex (ctx, NULL, NULL, NULL, NULL, pkey, EDDSA25519phParams);
if (!EVP_DigestSign (ctx, sig, &l, digest, 64))
LogPrint (eLogError, "EdDSA signing failed");
memcpy (signature, sig, 64);
EVP_MD_CTX_destroy (ctx);
}
else
LogPrint (eLogError, "EdDSA signing key is not set");
}
#endif
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2025, The PurpleI2P Project
* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -303,28 +303,14 @@ namespace crypto
private:
#if OPENSSL_EDDSA
#if OPENSSL_EDDSA
EVP_PKEY * m_Pkey;
protected:
EVP_PKEY * GetPkey () const { return m_Pkey; };
#else
EDDSAPoint m_PublicKey;
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
#endif
};
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
class EDDSA25519phVerifier: public EDDSA25519Verifier
{
public:
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
};
#endif
class EDDSA25519SignerCompat: public Signer
{
public:
@@ -353,10 +339,6 @@ namespace crypto
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
protected:
EVP_PKEY * GetPkey () const { return m_Pkey; };
private:
EVP_PKEY * m_Pkey;
@@ -368,18 +350,6 @@ namespace crypto
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
class EDDSA25519phSigner: public EDDSA25519Signer
{
public:
EDDSA25519phSigner (const uint8_t * signingPrivateKey);
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
};
#endif
inline void CreateEDDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
#if OPENSSL_EDDSA

View File

@@ -680,21 +680,8 @@ namespace transport
auto directTransports = compatibleTransports & peer->router->GetPublishedTransports ();
peer->numAttempts = 0;
peer->priority.clear ();
std::shared_ptr<RouterProfile> profile;
if (peer->router->HasProfile ()) profile = peer->router->GetProfile (); // only if in memory
bool ssu2 = false; // NTCP2 by default
bool isReal = profile ? profile->IsReal () : true;
if (isReal)
{
ssu2 = m_Rng () & 1; // 1/2
if (ssu2 && !profile)
{
profile = peer->router->GetProfile (); // load profile if necessary
isReal = profile->IsReal ();
if (!isReal) ssu2 = false; // try NTCP2 if router is not confirmed real
}
}
bool isReal = peer->router->GetProfile ()->IsReal ();
bool ssu2 = isReal ? (m_Rng () & 1) : false; // try NTCP2 if router is not confirmed real
const auto& priority = ssu2 ? ssu2Priority : ntcp2Priority;
if (directTransports)
{