update config file example, add v6 status to windows daemon window, code cleanup

Signed-off-by: R4SAS <r4sas@i2pmail.org>
This commit is contained in:
R4SAS 2021-05-15 16:28:16 +03:00
parent d299cbaabd
commit c359c6e634
No known key found for this signature in database
GPG key ID: 66F6C87B98EBCFE2
11 changed files with 258 additions and 227 deletions

View file

@ -62,11 +62,11 @@ namespace config {
("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)")
("bandwidth", value<std::string>()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)")
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)")
("ntcp", bool_switch()->default_value(false), "Ignored. Always false")
("ntcp", bool_switch()->default_value(false), "Deprecated option. Always false")
("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)")
("ntcpproxy", value<std::string>()->default_value(""), "Ignored")
("ntcpproxy", value<std::string>()->default_value(""), "Deprecated option")
#ifdef _WIN32
("svcctl", value<std::string>()->default_value(""), "Ignored")
("svcctl", value<std::string>()->default_value(""), "Deprecated option")
("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)")
("close", value<std::string>()->default_value("ask"), "Action on close: minimize, exit, ask")
#endif
@ -77,9 +77,9 @@ namespace config {
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)")
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)")
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Threshold to start probabilistic backoff with ntcp sessions (default: use system limit)")
("limits.ntcphard", value<uint16_t>()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)")
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Maximum number of threads used by NTCP DH worker (default: 1)")
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Deprecated option")
("limits.ntcphard", value<uint16_t>()->default_value(0), "Deprecated option")
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Deprecated option")
;
options_description httpserver("HTTP Server options");
@ -281,7 +281,7 @@ namespace config {
options_description meshnets("Meshnet transports options");
meshnets.add_options()
("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (deafult: false)")
("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (default: false)")
("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish")
;

View file

@ -509,7 +509,7 @@ namespace client
// schedule verification
m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT));
m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer,
shared_from_this (), std::placeholders::_1));
shared_from_this (), std::placeholders::_1));
}
else
i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msgID);
@ -592,8 +592,7 @@ namespace client
// assume it successive and try to verify
m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT));
m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer,
shared_from_this (), std::placeholders::_1));
shared_from_this (), std::placeholders::_1));
}
}
}

View file

@ -342,7 +342,7 @@ namespace transport
else
LogPrint (eLogWarning, "NTCP2: Missing NTCP2 address");
}
m_NextRouterInfoResendTime = i2p::util::GetSecondsSinceEpoch () + NTCP2_ROUTERINFO_RESEND_INTERVAL +
m_NextRouterInfoResendTime = i2p::util::GetSecondsSinceEpoch () + NTCP2_ROUTERINFO_RESEND_INTERVAL +
rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
}
@ -717,7 +717,7 @@ namespace transport
m_Establisher->m_SessionRequestBuffer = new uint8_t[287]; // 287 bytes max for now
boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer, 64), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
std::placeholders::_1, std::placeholders::_2));
}
void NTCP2Session::ReceiveLength ()
@ -726,7 +726,7 @@ namespace transport
#ifdef __linux__
const int one = 1;
setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
#endif
#endif
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_NextReceivedLen, 2), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleReceivedLength, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
}
@ -780,8 +780,8 @@ namespace transport
if (IsTerminated ()) return;
#ifdef __linux__
const int one = 1;
setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
#endif
setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
#endif
boost::asio::async_read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
}
@ -1009,11 +1009,11 @@ namespace transport
LogPrint (eLogDebug, "NTCP2: Next frame sent ", bytes_transferred);
if (m_LastActivityTimestamp > m_NextRouterInfoResendTime)
{
m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL +
m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL +
rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
SendRouterInfo ();
}
else
SendRouterInfo ();
}
else
SendQueue ();
}
}
@ -1113,7 +1113,7 @@ namespace transport
SendQueue ();
else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE)
{
LogPrint (eLogWarning, "NTCP2: outgoing messages queue size to ",
LogPrint (eLogWarning, "NTCP2: outgoing messages queue size to ",
GetIdentHashBase64(), " exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE);
Terminate ();
}
@ -1279,7 +1279,7 @@ namespace transport
{
LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
return;
}
}
LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint ());
GetService ().post([this, conn]()
{
@ -1300,25 +1300,25 @@ namespace transport
// bind to local address
std::shared_ptr<boost::asio::ip::tcp::endpoint> localAddress;
if (conn->GetRemoteEndpoint ().address ().is_v6 ())
{
{
if (i2p::util::net::IsYggdrasilAddress (conn->GetRemoteEndpoint ().address ()))
localAddress = m_YggdrasilAddress;
else
else
localAddress = m_Address6;
conn->GetSocket ().open (boost::asio::ip::tcp::v6 ());
}
}
else
{
{
localAddress = m_Address4;
conn->GetSocket ().open (boost::asio::ip::tcp::v4 ());
}
}
if (localAddress)
{
boost::system::error_code ec;
conn->GetSocket ().bind (*localAddress, ec);
if (ec)
LogPrint (eLogError, "NTCP2: can't bind to ", localAddress->address ().to_string (), ": ", ec.message ());
}
LogPrint (eLogError, "NTCP2: can't bind to ", localAddress->address ().to_string (), ": ", ec.message ());
}
conn->GetSocket ().async_connect (conn->GetRemoteEndpoint (), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer));
}
else
@ -1448,8 +1448,8 @@ namespace transport
{
LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
return;
}
GetService().post([this, conn]()
}
GetService().post([this, conn]()
{
if (this->AddNTCP2Session (conn))
{
@ -1546,10 +1546,10 @@ namespace transport
if(ep.address ().is_v6 ())
req.uri = "[" + ep.address ().to_string() + "]:" + std::to_string(ep.port ());
else
req.uri = ep.address ().to_string() + ":" + std::to_string(ep.port ());
req.uri = ep.address ().to_string() + ":" + std::to_string(ep.port ());
if (!m_ProxyAuthorization.empty ())
req.AddHeader("Proxy-Authorization", m_ProxyAuthorization);
boost::asio::streambuf writebuff;
std::ostream out(&writebuff);
out << req.to_string();
@ -1627,7 +1627,7 @@ namespace transport
sz += 16;
memcpy(buff->data () + 4, addrbytes.data(), 16);
}
else
else
{
// We mustn't really fall here because all connections are made to IP addresses
LogPrint(eLogError, "NTCP2: Tried to connect to unexpected address via proxy");
@ -1666,17 +1666,17 @@ namespace transport
}
void NTCP2Server::SetLocalAddress (const boost::asio::ip::address& localAddress)
{
{
auto addr = std::make_shared<boost::asio::ip::tcp::endpoint>(boost::asio::ip::tcp::endpoint(localAddress, 0));
if (localAddress.is_v6 ())
{
{
if (i2p::util::net::IsYggdrasilAddress (localAddress))
m_YggdrasilAddress = addr;
else
else
m_Address6 = addr;
}
}
else
m_Address4 = addr;
}
}
}
}

View file

@ -28,7 +28,7 @@ namespace i2p
RouterContext::RouterContext ():
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown),
m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown),
m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID)
{
}
@ -44,12 +44,12 @@ namespace i2p
m_TunnelDecryptor = m_Keys.CreateDecryptor (nullptr);
UpdateRouterInfo ();
if (IsECIES ())
{
{
auto initState = new i2p::crypto::NoiseSymmetricState ();
i2p::crypto::InitNoiseNState (*initState, GetIdentity ()->GetEncryptionPublicKey ());
m_InitialNoiseState.reset (initState);
m_InitialNoiseState.reset (initState);
m_ECIESSession = std::make_shared<i2p::garlic::RouterIncomingRatchetSession>(*initState);
}
}
}
void RouterContext::CreateNewRouter ()
@ -74,21 +74,21 @@ namespace i2p
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
bool ssu; i2p::config::GetOption("ssu", ssu);
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
bool nat; i2p::config::GetOption("nat", nat);
if ((ntcp2 || ygg) && !m_NTCP2Keys)
NewNTCP2Keys ();
bool ntcp2Published = false;
NewNTCP2Keys ();
bool ntcp2Published = false;
if (ntcp2)
{
{
i2p::config::GetOption("ntcp2.published", ntcp2Published);
if (ntcp2Published)
{
std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy);
if (!ntcp2proxy.empty ()) ntcp2Published = false;
}
}
}
}
uint8_t caps = 0, addressCaps = 0;
if (ipv4)
{
@ -100,8 +100,8 @@ namespace i2p
// we have no NAT so set external address from local address
std::string address4; i2p::config::GetOption("address4", address4);
if (!address4.empty ()) host = address4;
}
}
if (ntcp2)
{
if (ntcp2Published)
@ -109,26 +109,26 @@ namespace i2p
else // add non-published NTCP2 address
{
addressCaps = i2p::data::RouterInfo::AddressCaps::eV4;
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
}
}
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
}
}
if (ssu)
{
{
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
caps |= i2p::data::RouterInfo::eReachable; // R
}
}
}
if (ipv6)
{
std::string host = "::1";
if (!i2p::config::IsDefault("host") && !ipv4) // override if v6 only
i2p::config::GetOption("host", host);
else
else
{
std::string address6; i2p::config::GetOption("address6", address6);
if (!address6.empty ()) host = address6;
}
if (ntcp2)
{
if (ntcp2Published)
@ -140,29 +140,29 @@ namespace i2p
ntcp2Host = host;
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v6::from_string (ntcp2Host), port);
}
else
{
else
{
if (!ipv4) // no other ntcp2 addresses yet
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
}
}
}
}
if (ssu)
{
{
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
caps |= i2p::data::RouterInfo::eReachable; // R
}
}
}
if (ygg)
{
auto yggaddr = i2p::util::net::GetYggdrasilAddress ();
if (!yggaddr.is_unspecified ())
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, yggaddr, port);
}
}
if (addressCaps)
routerInfo.SetUnreachableAddressesTransportCaps (addressCaps);
routerInfo.SetCaps (caps); // caps + L
routerInfo.SetCaps (caps); // caps + L
routerInfo.SetProperty ("netId", std::to_string (m_NetID));
routerInfo.SetProperty ("router.version", I2P_VERSION);
routerInfo.CreateBuffer (m_Keys);
@ -213,7 +213,7 @@ namespace i2p
void RouterContext::SetStatusV6 (RouterStatus status)
{
if (status != m_StatusV6)
{
{
m_StatusV6 = status;
switch (m_StatusV6)
{
@ -226,9 +226,9 @@ namespace i2p
default:
;
}
}
}
}
}
void RouterContext::UpdatePort (int port)
{
bool updated = false;
@ -250,18 +250,18 @@ namespace i2p
bool updated = false;
for (auto& address : m_RouterInfo.GetAddresses ())
{
if (address->IsNTCP2 () && (address->port != port || address->published != publish))
if (address->IsNTCP2 () && (address->port != port || address->published != publish))
{
bool isAddr = v4 && address->IsV4 ();
if (!isAddr && (v6 || ygg))
{
{
if (i2p::util::net::IsYggdrasilAddress (address->host))
isAddr = ygg;
else
isAddr = v6 && address->IsV6 ();
}
if (isAddr)
{
{
if (!port && !address->port)
{
// select random port only if address's port is not set
@ -272,7 +272,7 @@ namespace i2p
address->published = publish;
address->ntcp2->iv = m_NTCP2Keys->iv;
updated = true;
}
}
}
}
if (updated)
@ -310,7 +310,7 @@ namespace i2p
bool updated = false;
for (auto& address : m_RouterInfo.GetAddresses ())
{
if (address->host != host && address->IsCompatible (host) &&
if (address->host != host && address->IsCompatible (host) &&
!i2p::util::net::IsYggdrasilAddress (address->host))
{
address->host = host;
@ -402,7 +402,7 @@ namespace i2p
case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1 : limit = 2048; type = extra; break;
case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2 : limit = 1000000; type = unlim; break; // 1Gbyte/s
default:
limit = 48; type = low;
limit = 48; type = low;
}
/* update caps & flags in RI */
auto caps = m_RouterInfo.GetCaps ();
@ -416,8 +416,8 @@ namespace i2p
#if (__cplusplus >= 201703L) // C++ 17 or higher
[[fallthrough]];
#endif
// no break here, extra + high means 'X'
case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break;
// no break here, extra + high means 'X'
case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break;
}
m_RouterInfo.SetCaps (caps);
UpdateRouterInfo ();
@ -467,14 +467,14 @@ namespace i2p
void RouterContext::SetUnreachable (bool v4, bool v6)
{
if (v4 || (v6 && !SupportsV4 ()))
{
{
// set caps
uint8_t caps = m_RouterInfo.GetCaps ();
caps &= ~i2p::data::RouterInfo::eReachable;
caps |= i2p::data::RouterInfo::eUnreachable;
caps &= ~i2p::data::RouterInfo::eFloodfill; // can't be floodfill
m_RouterInfo.SetCaps (caps);
}
}
uint16_t port = 0;
// delete previous introducers
auto& addresses = m_RouterInfo.GetAddresses ();
@ -497,7 +497,7 @@ namespace i2p
void RouterContext::SetReachable (bool v4, bool v6)
{
if (v4 || (v6 && !SupportsV4 ()))
{
{
// update caps
uint8_t caps = m_RouterInfo.GetCaps ();
caps &= ~i2p::data::RouterInfo::eUnreachable;
@ -505,7 +505,7 @@ namespace i2p
if (m_IsFloodfill)
caps |= i2p::data::RouterInfo::eFloodfill;
m_RouterInfo.SetCaps (caps);
}
}
uint16_t port = 0;
// delete previous introducers
auto& addresses = m_RouterInfo.GetAddresses ();
@ -526,7 +526,7 @@ namespace i2p
{
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
if (!ntcp2Port) ntcp2Port = port;
PublishNTCP2Address (ntcp2Port, true, v4, v6, false);
PublishNTCP2Address (ntcp2Port, true, v4, v6, false);
}
}
// update
@ -596,7 +596,7 @@ namespace i2p
if (supportsV4)
{
bool foundSSU = false, foundNTCP2 = false;
std::string host = "127.0.0.1";
std::string host = "127.0.0.1";
uint16_t port = 0;
auto& addresses = m_RouterInfo.GetAddresses ();
for (auto& addr: addresses)
@ -626,26 +626,26 @@ namespace i2p
{
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
if (ntcp2Published)
{
{
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
if (!ntcp2Port) ntcp2Port = port;
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (host), ntcp2Port);
}
}
else
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
}
}
}
}
m_RouterInfo.EnableV4 ();
}
}
else
m_RouterInfo.DisableV4 ();
UpdateRouterInfo ();
}
void RouterContext::SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host)
{
{
if (supportsmesh)
{
{
m_RouterInfo.EnableMesh ();
uint16_t port = 0;
i2p::config::GetOption ("ntcp2.port", port);
@ -659,16 +659,16 @@ namespace i2p
{
foundMesh = true;
break;
}
}
}
if (!foundMesh)
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, host, port);
}
}
else
m_RouterInfo.DisableMesh ();
UpdateRouterInfo ();
}
void RouterContext::UpdateNTCP2V6Address (const boost::asio::ip::address& host)
{
bool isYgg = i2p::util::net::IsYggdrasilAddress (host);
@ -742,7 +742,7 @@ namespace i2p
// rekey routers with bandwidth = L (or default) this time
bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill);
if (!isFloodfill) rekey = true;
}
}
if (rekey)
{
// update keys
@ -751,7 +751,7 @@ namespace i2p
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD);
SaveKeys ();
}
}
// read NTCP2 keys if available
std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary);
if (n2k)
@ -787,8 +787,8 @@ namespace i2p
SetReachable (true, true); // we assume reachable until we discover firewall through peer tests
// read NTCP2
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
if (ntcp2 || ygg)
{
if (!m_NTCP2Keys) NewNTCP2Keys ();
@ -821,15 +821,15 @@ namespace i2p
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len)));
}
bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len)
{
bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len)
{
auto msg = CreateI2NPMessage (typeID, payload, len);
if (!msg) return false;
i2p::HandleI2NPMessage (msg);
return true;
}
return true;
}
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{
std::unique_lock<std::mutex> l(m_GarlicMutex);
@ -847,8 +847,8 @@ namespace i2p
m_ECIESSession->HandleNextMessage (buf, len);
else
LogPrint (eLogError, "Router: Session is not set for ECIES router");
}
else
}
else
i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg);
}
@ -857,10 +857,10 @@ namespace i2p
if (i2p::data::netdb.GetPublishReplyToken () == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
i2p::data::netdb.PostI2NPMsg (msg);
else
{
{
std::unique_lock<std::mutex> l(m_GarlicMutex);
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
}
}
}
void RouterContext::CleanupDestination ()
@ -886,34 +886,34 @@ namespace i2p
{
if (!m_InitialNoiseState) return false;
// m_InitialNoiseState is h = SHA256(h || hepk)
m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState));
m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState));
m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk)
uint8_t sharedSecret[32];
if (!m_TunnelDecryptor->Decrypt (encrypted, sharedSecret, nullptr, false))
{
LogPrint (eLogWarning, "Router: Incorrect ephemeral public key");
return false;
}
m_CurrentNoiseState->MixKey (sharedSecret);
}
m_CurrentNoiseState->MixKey (sharedSecret);
encrypted += 32;
uint8_t nonce[12];
memset (nonce, 0, 12);
if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE,
if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE,
m_CurrentNoiseState->m_H, 32, m_CurrentNoiseState->m_CK + 32, nonce, data, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, false)) // decrypt
{
LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed");
return false;
}
}
m_CurrentNoiseState->MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext)
return true;
}
else
}
else
{
BN_CTX * ctx = BN_CTX_new ();
bool success = m_TunnelDecryptor->Decrypt (encrypted, data, ctx, false);
BN_CTX_free (ctx);
return success;
}
}
}
i2p::crypto::X25519Keys& RouterContext::GetStaticKeys ()

View file

@ -28,7 +28,7 @@ namespace transport
m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port),
m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6),
m_IntroducersUpdateTimer (m_Service), m_IntroducersUpdateTimerV6 (m_Service),
m_IntroducersUpdateTimer (m_Service), m_IntroducersUpdateTimerV6 (m_Service),
m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_Service)
{
}
@ -79,7 +79,7 @@ namespace transport
if (context.SupportsV4 ())
{
OpenSocket ();
m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this));
m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this));
m_ReceiversService.post (std::bind (&SSUServer::Receive, this));
ScheduleTermination ();
ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers
@ -125,7 +125,7 @@ namespace transport
m_Thread->join ();
delete m_Thread;
m_Thread = nullptr;
}
}
}
void SSUServer::Run ()
@ -198,8 +198,8 @@ namespace transport
m_EndpointV6.address (localAddress);
else if (localAddress.is_v4 ())
m_Endpoint.address (localAddress);
}
}
void SSUServer::AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay)
{
m_Relays[tag] = relay;
@ -412,7 +412,7 @@ namespace transport
std::shared_ptr<SSUSession> SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const
{
auto& sessions = e.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
auto& sessions = e.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
auto it = sessions.find (e);
if (it != sessions.end ())
return it->second;
@ -439,7 +439,7 @@ namespace transport
m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, address, peerTest)); // always V4 thread
else
{
if (address->host.is_unspecified () || !address->port) return false;
if (address->host.is_unspecified () || !address->port) return false;
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
m_Service.post (std::bind (&SSUServer::CreateDirectSession, this, router, remoteEndpoint, peerTest));
}
@ -472,15 +472,15 @@ namespace transport
}
}
void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest)
{
if (router && address && address->UsesIntroducer ())
{
{
if (address->IsV4 () && !i2p::context.SupportsV4 ()) return;
if (address->IsV6 () && !i2p::context.SupportsV6 ()) return;
if (!address->host.is_unspecified () && address->port)
{
{
// we rarely come here
auto& sessions = address->host.is_v6 () ? m_SessionsV6 : m_Sessions;
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
@ -493,7 +493,7 @@ namespace transport
session->SendPeerTest ();
return;
}
}
}
// create new session
int numIntroducers = address->ssu->introducers.size ();
if (numIntroducers > 0)
@ -509,9 +509,9 @@ namespace transport
if (!intr->iPort) continue; // skip invalid introducer
if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer
boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort);
if (ep.address ().is_v4 () && address->IsV4 ()) // ipv4
if (ep.address ().is_v4 () && address->IsV4 ()) // ipv4
{
if (!introducer) introducer = intr;
if (!introducer) introducer = intr;
auto it = m_Sessions.find (ep);
if (it != m_Sessions.end ())
{
@ -519,9 +519,9 @@ namespace transport
break;
}
}
if (ep.address ().is_v6 () && address->IsV6 ()) // ipv6
if (ep.address ().is_v6 () && address->IsV6 ()) // ipv6
{
if (!introducer) introducer = intr;
if (!introducer) introducer = intr;
auto it = m_SessionsV6.find (ep);
if (it != m_SessionsV6.end ())
{
@ -546,7 +546,7 @@ namespace transport
if (introducerEndpoint.address ().is_v4 ())
m_Sessions[introducerEndpoint] = introducerSession;
else if (introducerEndpoint.address ().is_v6 ())
m_SessionsV6[introducerEndpoint] = introducerSession;
m_SessionsV6[introducerEndpoint] = introducerSession;
}
if (!address->host.is_unspecified () && address->port)
{
@ -563,7 +563,7 @@ namespace transport
"] through introducer ", introducer->iHost, ":", introducer->iPort);
session->WaitForIntroduction ();
if ((address->host.is_v4 () && i2p::context.GetStatus () == eRouterStatusFirewalled) ||
(address->host.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled))
(address->host.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled))
{
uint8_t buf[1];
Send (buf, 0, remoteEndpoint); // send HolePunch
@ -648,23 +648,23 @@ namespace transport
);
}
std::list<std::shared_ptr<SSUSession> > SSUServer::FindIntroducers (int maxNumIntroducers,
std::list<std::shared_ptr<SSUSession> > SSUServer::FindIntroducers (int maxNumIntroducers,
bool v4, std::set<i2p::data::IdentHash>& excluded)
{
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
std::list<std::shared_ptr<SSUSession> > ret;
const auto& sessions = v4 ? m_Sessions : m_SessionsV6;
for (const auto& s : sessions)
{
{
if (s.second->GetRelayTag () && s.second->GetState () == eSessionStateEstablished &&
ts < s.second->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION)
ret.push_back (s.second);
else if (s.second->GetRemoteIdentity ())
excluded.insert (s.second->GetRemoteIdentity ()->GetIdentHash ());
}
}
if ((int)ret.size () > maxNumIntroducers)
{
// shink ret randomly
// shink ret randomly
int sz = ret.size () - maxNumIntroducers;
for (int i = 0; i < sz; i++)
{
@ -672,8 +672,8 @@ namespace transport
auto it = ret.begin ();
std::advance (it, ind);
ret.erase (it);
}
}
}
}
return ret;
}
@ -683,8 +683,8 @@ namespace transport
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL/2));
m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
this, std::placeholders::_1, true));
}
}
void SSUServer::ScheduleIntroducersUpdateTimer ()
{
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL));
@ -698,22 +698,22 @@ namespace transport
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL/2));
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
this, std::placeholders::_1, false));
}
}
void SSUServer::ScheduleIntroducersUpdateTimerV6 ()
{
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL));
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
this, std::placeholders::_1, false));
}
void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4)
{
if (ecode != boost::asio::error::operation_aborted)
{
// timeout expired
if (v4)
{
{
if (i2p::context.GetStatus () == eRouterStatusTesting)
{
// we still don't know if we need introducers
@ -721,14 +721,14 @@ namespace transport
return;
}
if (i2p::context.GetStatus () != eRouterStatusFirewalled)
{
{
// we don't need introducers
m_Introducers.clear ();
return;
}
return;
}
// we are firewalled
if (!i2p::context.IsUnreachable ()) i2p::context.SetUnreachable (true, false); // v4
}
}
else
{
if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
@ -738,17 +738,17 @@ namespace transport
return;
}
if (i2p::context.GetStatusV6 () != eRouterStatusFirewalled)
{
{
// we don't need introducers
m_IntroducersV6.clear ();
return;
return;
}
// we are firewalled
auto addr = i2p::context.GetRouterInfo ().GetSSUV6Address ();
if (addr && addr->ssu && addr->ssu->introducers.empty ())
i2p::context.SetUnreachable (false, true); // v6
}
}
std::list<boost::asio::ip::udp::endpoint> newList;
size_t numIntroducers = 0;
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
@ -762,7 +762,7 @@ namespace transport
if (ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION)
session->SendKeepAlive ();
if (ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION)
{
{
newList.push_back (it);
numIntroducers++;
if (session->GetRemoteIdentity ())
@ -787,11 +787,11 @@ namespace transport
auto session = FindSession (it);
if (session)
session->SetCreationTime (session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION);
}
}
// try again
excluded.clear ();
sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4, excluded);
}
}
for (const auto& it1: sessions)
{
const auto& ep = it1->GetRemoteEndpoint ();
@ -814,27 +814,27 @@ namespace transport
if (introducers.size () < SSU_MAX_NUM_INTRODUCERS)
{
for (auto i = introducers.size (); i < SSU_MAX_NUM_INTRODUCERS; i++)
{
{
auto introducer = i2p::data::netdb.GetRandomIntroducer (v4, excluded);
if (introducer)
{
{
auto address = v4 ? introducer->GetSSUAddress (true) : introducer->GetSSUV6Address ();
if (address && !address->host.is_unspecified () && address->port)
{
boost::asio::ip::udp::endpoint ep (address->host, address->port);
if (std::find (introducers.begin (), introducers.end (), ep) == introducers.end ()) // not connected yet
{
CreateDirectSession (introducer, ep, false);
{
CreateDirectSession (introducer, ep, false);
excluded.insert (introducer->GetIdentHash ());
}
}
}
}
}
else
{
{
LogPrint (eLogDebug, "SSU: can't find more introducers");
break;
}
}
}
}
}
if (v4)
ScheduleIntroducersUpdateTimer ();

View file

@ -383,7 +383,7 @@ namespace transport
{
// tell out peer to now assign relay tag
flag = SSU_HEADER_EXTENDED_OPTIONS_INCLUDED;
*payload = 2; payload++; // 1 byte length
*payload = 2; payload++; // 1 byte length
uint16_t flags = 0; // clear EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG
htobe16buf (payload, flags);
payload += 2;