[-]
[+]
|
Changed |
_service:tar_git:i2pd.spec
|
|
[-]
[+]
|
Changed |
_service
^
|
@@ -2,7 +2,7 @@
<service name="tar_git">
<param name="url">https://github.com/nephros/i2pd</param>
<param name="branch"></param>
- <param name="revision">2.43.0+git1</param>
+ <param name="revision">2.50.2+git3</param>
<param name="token"/>
<param name="debian">N</param>
<param name="dumb">N</param>
|
|
Deleted |
_service:tar_git:i2pd-2.43.0+git1.tar.gz/upstream/Win32/mask.bmp
^
|
[-]
[+]
|
Deleted |
_service:tar_git:i2pd-2.43.0+git1.tar.gz/upstream/debian/patches/01-fix-1210.patch
^
|
@@ -1,27 +0,0 @@
-Description: fix #1210
- Disables two options, which not presented in old systemd versions
-Author: r4sas <r4sas@i2pmail.org>
-
-Bug: https://github.com/PurpleI2P/i2pd/issues/1210
-Reviewed-By: r4sas <r4sas@i2pmail.org>
-Last-Update: 2020-05-25
-
-Index: i2pd/contrib/i2pd.service
-===================================================================
---- i2pd.orig/contrib/i2pd.service
-+++ i2pd/contrib/i2pd.service
-@@ -6,10 +6,10 @@ After=network.target
- [Service]
- User=i2pd
- Group=i2pd
--RuntimeDirectory=i2pd
--RuntimeDirectoryMode=0700
--LogsDirectory=i2pd
--LogsDirectoryMode=0700
-+#RuntimeDirectory=i2pd
-+#RuntimeDirectoryMode=0700
-+#LogsDirectory=i2pd
-+#LogsDirectoryMode=0700
- Type=forking
- ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
- ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
[-]
[+]
|
Deleted |
_service:tar_git:i2pd-2.43.0+git1.tar.gz/upstream/libi2pd/BloomFilter.cpp
^
|
@@ -1,77 +0,0 @@
-/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
-*
-* This file is part of Purple i2pd project and licensed under BSD3
-*
-* See full license text in LICENSE file at top of project tree
-*/
-
-#include "BloomFilter.h"
-#include "I2PEndian.h"
-#include <array>
-#include <openssl/sha.h>
-
-namespace i2p
-{
-namespace util
-{
-
- /** @brief decaying bloom filter implementation */
- class DecayingBloomFilter : public IBloomFilter
- {
- public:
-
- DecayingBloomFilter(const std::size_t size)
- {
- m_Size = size;
- m_Data = new uint8_t[size];
- }
-
- /** @brief implements IBloomFilter::~IBloomFilter */
- ~DecayingBloomFilter()
- {
- delete [] m_Data;
- }
-
- /** @brief implements IBloomFilter::Add */
- bool Add(const uint8_t * data, std::size_t len)
- {
- std::size_t idx;
- uint8_t mask;
- Get(data, len, idx, mask);
- if(m_Data[idx] & mask) return false; // filter hit
- m_Data[idx] |= mask;
- return true;
- }
-
- /** @brief implements IBloomFilter::Decay */
- void Decay()
- {
- // reset bloom filter buffer
- memset(m_Data, 0, m_Size);
- }
-
- private:
- /** @brief get bit index for for data */
- void Get(const uint8_t * data, std::size_t len, std::size_t & idx, uint8_t & bm)
- {
- bm = 1;
- uint8_t digest[32];
- // TODO: use blake2 because it's faster
- SHA256(data, len, digest);
- uint64_t i = buf64toh(digest);
- idx = i % m_Size;
- bm <<= (i % 8);
- }
-
- uint8_t * m_Data;
- std::size_t m_Size;
- };
-
-
- BloomFilterPtr BloomFilter(std::size_t capacity)
- {
- return std::make_shared<DecayingBloomFilter>(capacity);
- }
-}
-}
|
[-]
[+]
|
Deleted |
_service:tar_git:i2pd-2.43.0+git1.tar.gz/upstream/libi2pd/BloomFilter.h
^
|
@@ -1,39 +0,0 @@
-/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
-*
-* This file is part of Purple i2pd project and licensed under BSD3
-*
-* See full license text in LICENSE file at top of project tree
-*/
-
-#ifndef BLOOM_FILTER_H_
-#define BLOOM_FILTER_H_
-#include <memory>
-#include <cstdint>
-
-namespace i2p
-{
-namespace util
-{
-
- /** @brief interface for bloom filter */
- struct IBloomFilter
- {
-
- /** @brief destructor */
- virtual ~IBloomFilter() {};
- /** @brief add entry to bloom filter, return false if filter hit otherwise return true */
- virtual bool Add(const uint8_t * data, std::size_t len) = 0;
- /** @brief optionally decay old entries */
- virtual void Decay() = 0;
- };
-
- typedef std::shared_ptr<IBloomFilter> BloomFilterPtr;
-
- /** @brief create bloom filter */
- BloomFilterPtr BloomFilter(std::size_t capacity = 1024 * 8);
-
-}
-}
-
-#endif
|
[-]
[+]
|
Deleted |
_service:tar_git:i2pd-2.43.0+git1.tar.gz/upstream/libi2pd/SSU.cpp
^
|
@@ -1,996 +0,0 @@
-/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
-*
-* This file is part of Purple i2pd project and licensed under BSD3
-*
-* See full license text in LICENSE file at top of project tree
-*/
-
-#include <string.h>
-#include "Log.h"
-#include "Timestamp.h"
-#include "RouterContext.h"
-#include "NetDb.hpp"
-#include "Config.h"
-#include "util.h"
-#include "SSU.h"
-
-#if defined(__linux__) && !defined(_NETINET_IN_H)
- #include <linux/in6.h>
-#endif
-
-#ifdef _WIN32
-#include <boost/winapi/error_codes.hpp>
-#endif
-
-namespace i2p
-{
-namespace transport
-{
- SSUServer::SSUServer (int port):
- m_IsRunning(false), m_Thread (nullptr),
- m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr), m_Work (m_Service),
- 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_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_Service),
- m_IsSyncClockFromPeers (true)
- {
- }
-
- SSUServer::~SSUServer ()
- {
- }
-
- void SSUServer::OpenSocket ()
- {
- try
- {
- m_Socket.open (boost::asio::ip::udp::v4());
- m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE));
- m_Socket.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
- m_Socket.bind (m_Endpoint);
- LogPrint (eLogInfo, "SSU: Start listening v4 port ", m_Endpoint.port());
- }
- catch ( std::exception & ex )
- {
- LogPrint (eLogError, "SSU: Failed to bind to v4 port ", m_Endpoint.port(), ": ", ex.what());
- ThrowFatal ("Unable to start IPv4 SSU transport at port ", m_Endpoint.port(), ": ", ex.what ());
- }
- }
-
- void SSUServer::OpenSocketV6 ()
- {
- try
- {
- m_SocketV6.open (boost::asio::ip::udp::v6());
- m_SocketV6.set_option (boost::asio::ip::v6_only (true));
- m_SocketV6.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE));
- m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
-#if defined(__linux__) && !defined(_NETINET_IN_H)
- if (m_EndpointV6.address() == boost::asio::ip::address().from_string("::")) // only if not binded to address
- {
- // Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others
-#if (BOOST_VERSION >= 105500)
- typedef boost::asio::detail::socket_option::integer<BOOST_ASIO_OS_DEF(IPPROTO_IPV6), IPV6_ADDR_PREFERENCES> ipv6PreferAddr;
-#else
- typedef boost::asio::detail::socket_option::integer<IPPROTO_IPV6, IPV6_ADDR_PREFERENCES> ipv6PreferAddr;
-#endif
- m_SocketV6.set_option (ipv6PreferAddr(IPV6_PREFER_SRC_PUBLIC | IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_NONCGA));
- }
-#endif
- m_SocketV6.bind (m_EndpointV6);
- LogPrint (eLogInfo, "SSU: Start listening v6 port ", m_EndpointV6.port());
- }
- catch ( std::exception & ex )
- {
- LogPrint (eLogError, "SSU: Failed to bind to v6 port ", m_EndpointV6.port(), ": ", ex.what());
- ThrowFatal ("Unable to start IPv6 SSU transport at port ", m_Endpoint.port(), ": ", ex.what ());
- }
- }
-
- void SSUServer::Start ()
- {
- i2p::config::GetOption("nettime.frompeers", m_IsSyncClockFromPeers);
- m_IsRunning = true;
- m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
- if (context.SupportsV4 ())
- {
- OpenSocket ();
- 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
- }
- if (context.SupportsV6 ())
- {
- OpenSocketV6 ();
- m_ReceiversThreadV6 = new std::thread (std::bind (&SSUServer::RunReceiversV6, this));
- m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this));
- ScheduleTerminationV6 ();
- ScheduleIntroducersUpdateTimerV6 (); // wait for 30 seconds and decide if we need introducers
- }
- SchedulePeerTestsCleanupTimer ();
- }
-
- void SSUServer::Stop ()
- {
- DeleteAllSessions ();
- m_IsRunning = false;
- m_TerminationTimer.cancel ();
- m_TerminationTimerV6.cancel ();
- m_IntroducersUpdateTimer.cancel ();
- m_IntroducersUpdateTimerV6.cancel ();
- m_Service.stop ();
- m_Socket.close ();
- m_SocketV6.close ();
- m_ReceiversService.stop ();
- m_ReceiversServiceV6.stop ();
- if (m_ReceiversThread)
- {
- m_ReceiversThread->join ();
- delete m_ReceiversThread;
- m_ReceiversThread = nullptr;
- }
- if (m_ReceiversThreadV6)
- {
- m_ReceiversThreadV6->join ();
- delete m_ReceiversThreadV6;
- m_ReceiversThreadV6 = nullptr;
- }
- if (m_Thread)
- {
- m_Thread->join ();
- delete m_Thread;
- m_Thread = nullptr;
- }
- }
-
- void SSUServer::Run ()
- {
- i2p::util::SetThreadName("SSU");
-
- while (m_IsRunning)
- {
- try
- {
- m_Service.run ();
- }
- catch (std::exception& ex)
- {
- LogPrint (eLogError, "SSU: Server runtime exception: ", ex.what ());
- }
- }
- }
-
- void SSUServer::RunReceivers ()
- {
- i2p::util::SetThreadName("SSUv4");
-
- while (m_IsRunning)
- {
- try
- {
- m_ReceiversService.run ();
- }
- catch (std::exception& ex)
- {
- LogPrint (eLogError, "SSU: Receivers runtime exception: ", ex.what ());
- if (m_IsRunning)
- {
- // restart socket
- m_Socket.close ();
- OpenSocket ();
- Receive ();
- }
- }
- }
- }
-
- void SSUServer::RunReceiversV6 ()
- {
- i2p::util::SetThreadName("SSUv6");
-
- while (m_IsRunning)
- {
- try
- {
- m_ReceiversServiceV6.run ();
- }
- catch (std::exception& ex)
- {
- LogPrint (eLogError, "SSU: v6 receivers runtime exception: ", ex.what ());
- if (m_IsRunning)
- {
- m_SocketV6.close ();
- OpenSocketV6 ();
- ReceiveV6 ();
- }
- }
- }
- }
-
- void SSUServer::SetLocalAddress (const boost::asio::ip::address& localAddress)
- {
- if (localAddress.is_v6 ())
- 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.emplace (tag, relay);
- }
-
- void SSUServer::RemoveRelay (uint32_t tag)
- {
- m_Relays.erase (tag);
- }
-
- std::shared_ptr<SSUSession> SSUServer::FindRelaySession (uint32_t tag)
- {
- auto it = m_Relays.find (tag);
- if (it != m_Relays.end ())
- {
- if (it->second->GetState () == eSessionStateEstablished)
- return it->second;
- else
- m_Relays.erase (it);
- }
- return nullptr;
- }
-
- void SSUServer::Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to)
- {
- boost::system::error_code ec;
- if (to.protocol () == boost::asio::ip::udp::v4())
- m_Socket.send_to (boost::asio::buffer (buf, len), to, 0, ec);
- else
- m_SocketV6.send_to (boost::asio::buffer (buf, len), to, 0, ec);
-
- if (ec)
- {
- LogPrint (eLogError, "SSU: Send exception: ", ec.message (), " while trying to send data to ", to.address (), ":", to.port (), " (length: ", len, ")");
- }
- }
-
- void SSUServer::Receive ()
- {
- SSUPacket * packet = m_PacketsPool.AcquireMt ();
- m_Socket.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from,
- std::bind (&SSUServer::HandleReceivedFrom, this, std::placeholders::_1, std::placeholders::_2, packet));
- }
-
- void SSUServer::ReceiveV6 ()
- {
- SSUPacket * packet = m_PacketsPool.AcquireMt ();
- m_SocketV6.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V6), packet->from,
- std::bind (&SSUServer::HandleReceivedFromV6, this, std::placeholders::_1, std::placeholders::_2, packet));
- }
-
- void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
- {
- if (!ecode
- || ecode == boost::asio::error::connection_refused
- || ecode == boost::asio::error::connection_reset
- || ecode == boost::asio::error::network_unreachable
- || ecode == boost::asio::error::host_unreachable
-#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO
- || ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
- || ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
- || ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
-#endif
- )
- // just try continue reading when received ICMP response otherwise socket can crash,
- // but better to find out which host were sent it and mark that router as unreachable
- {
- packet->len = bytes_transferred;
- std::vector<SSUPacket *> packets;
- packets.push_back (packet);
-
- boost::system::error_code ec;
- size_t moreBytes = m_Socket.available(ec);
- if (!ec)
- {
- while (moreBytes && packets.size () < 25)
- {
- packet = m_PacketsPool.AcquireMt ();
- packet->len = m_Socket.receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from, 0, ec);
- if (!ec)
- {
- packets.push_back (packet);
- moreBytes = m_Socket.available(ec);
- if (ec) break;
- }
- else
- {
- LogPrint (eLogError, "SSU: receive_from error: code ", ec.value(), ": ", ec.message ());
- m_PacketsPool.ReleaseMt (packet);
- break;
- }
- }
- }
-
- m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_Sessions));
- Receive ();
- }
- else
- {
- m_PacketsPool.ReleaseMt (packet);
- if (ecode != boost::asio::error::operation_aborted)
- {
- LogPrint (eLogError, "SSU: Receive error: code ", ecode.value(), ": ", ecode.message ());
- m_Socket.close ();
- OpenSocket ();
- Receive ();
- }
- }
- }
-
- void SSUServer::HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
- {
- if (!ecode
- || ecode == boost::asio::error::connection_refused
- || ecode == boost::asio::error::connection_reset
- || ecode == boost::asio::error::network_unreachable
- || ecode == boost::asio::error::host_unreachable
-#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO
- || ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
- || ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
- || ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
-#endif
- )
- // just try continue reading when received ICMP response otherwise socket can crash,
- // but better to find out which host were sent it and mark that router as unreachable
- {
- packet->len = bytes_transferred;
- std::vector<SSUPacket *> packets;
- packets.push_back (packet);
-
- boost::system::error_code ec;
- size_t moreBytes = m_SocketV6.available (ec);
- if (!ec)
- {
- while (moreBytes && packets.size () < 25)
- {
- packet = m_PacketsPool.AcquireMt ();
- packet->len = m_SocketV6.receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V6), packet->from, 0, ec);
- if (!ec)
- {
- packets.push_back (packet);
- moreBytes = m_SocketV6.available(ec);
- if (ec) break;
- }
- else
- {
- LogPrint (eLogError, "SSU: v6 receive_from error: code ", ec.value(), ": ", ec.message ());
- m_PacketsPool.ReleaseMt (packet);;
- break;
- }
- }
- }
-
- m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_SessionsV6));
- ReceiveV6 ();
- }
- else
- {
- m_PacketsPool.ReleaseMt (packet);
- if (ecode != boost::asio::error::operation_aborted)
- {
- LogPrint (eLogError, "SSU: v6 receive error: code ", ecode.value(), ": ", ecode.message ());
- m_SocketV6.close ();
- OpenSocketV6 ();
- ReceiveV6 ();
- }
- }
- }
-
- void SSUServer::HandleReceivedPackets (std::vector<SSUPacket *> packets,
- std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > * sessions)
- {
- if (!m_IsRunning) return;
- std::shared_ptr<SSUSession> session;
- for (auto& packet: packets)
- {
- try
- {
- if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous
- {
- if (session)
- {
- session->FlushData ();
- session = nullptr;
- }
- auto it = sessions->find (packet->from);
- if (it != sessions->end ())
- session = it->second;
- if (!session && packet->len > 0)
- {
- session = std::make_shared<SSUSession> (*this, packet->from);
- session->WaitForConnect ();
- (*sessions)[packet->from] = session;
- LogPrint (eLogDebug, "SSU: New session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created");
- }
- }
- if (session)
- session->ProcessNextMessage (packet->buf, packet->len, packet->from);
- }
- catch (std::exception& ex)
- {
- LogPrint (eLogError, "SSU: HandleReceivedPackets ", ex.what ());
- if (session) session->FlushData ();
- session = nullptr;
- }
- }
- m_PacketsPool.ReleaseMt (packets);
- if (session) session->FlushData ();
- }
-
- 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 it = sessions.find (e);
- if (it != sessions.end ())
- return it->second;
- else
- return nullptr;
- }
-
- bool SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest, bool v4only)
- {
- auto address = router->GetSSUAddress (v4only || !context.SupportsV6 ());
- if (address)
- return CreateSession (router, address, peerTest);
- else
- LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
- return false;
- }
-
- bool SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
- std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest)
- {
- if (router && address)
- {
- if (address->UsesIntroducer ())
- m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, address, peerTest)); // always V4 thread
- else
- {
- 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));
- }
- }
- else
- return false;
- return true;
- }
-
- void SSUServer::CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest)
- {
- auto& sessions = remoteEndpoint.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
- auto it = sessions.find (remoteEndpoint);
- if (it != sessions.end ())
- {
- auto session = it->second;
- if (peerTest && session->GetState () == eSessionStateEstablished)
- session->SendPeerTest ();
- }
- else
- {
- // otherwise create new session
- auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
- sessions[remoteEndpoint] = session;
-
- // connect
- LogPrint (eLogDebug, "SSU: Creating new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ",
- remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ());
- session->Connect ();
- }
- }
-
- 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);
- auto it = sessions.find (remoteEndpoint);
- // check if session is presented already
- if (it != sessions.end ())
- {
- auto session = it->second;
- if (peerTest && session->GetState () == eSessionStateEstablished)
- session->SendPeerTest ();
- return;
- }
- }
- // create new session
- int numIntroducers = address->ssu->introducers.size ();
- if (numIntroducers > 0)
- {
- uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
- std::shared_ptr<SSUSession> introducerSession;
- const i2p::data::RouterInfo::Introducer * introducer = nullptr;
- // we might have a session to introducer already
- auto offset = rand ();
- for (int i = 0; i < numIntroducers; i++)
- {
- auto intr = &(address->ssu->introducers[(offset + i)%numIntroducers]);
- 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 (!introducer) introducer = intr;
- auto it = m_Sessions.find (ep);
- if (it != m_Sessions.end ())
- {
- introducerSession = it->second;
- break;
- }
- }
- if (ep.address ().is_v6 () && address->IsV6 ()) // ipv6
- {
- if (!introducer) introducer = intr;
- auto it = m_SessionsV6.find (ep);
- if (it != m_SessionsV6.end ())
- {
- introducerSession = it->second;
- break;
- }
- }
- }
- if (!introducer)
- {
- LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no compatibe non-expired introducers presented");
- return;
- }
-
- if (introducerSession) // session found
- LogPrint (eLogWarning, "SSU: Session to introducer already exists");
- else // create new
- {
- LogPrint (eLogDebug, "SSU: Creating new session to introducer ", introducer->iHost);
- boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
- introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
- if (introducerEndpoint.address ().is_v4 ())
- m_Sessions[introducerEndpoint] = introducerSession;
- else if (introducerEndpoint.address ().is_v6 ())
- m_SessionsV6[introducerEndpoint] = introducerSession;
- }
- if (!address->host.is_unspecified () && address->port)
- {
- // create session
- boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
- auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
- if (address->host.is_v4 ())
- m_Sessions[remoteEndpoint] = session;
- else if (address->host.is_v6 ())
- m_SessionsV6[remoteEndpoint] = session;
-
- // introduce
- LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()),
- "] 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))
- {
- uint8_t buf[1];
- Send (buf, 0, remoteEndpoint); // send HolePunch
- }
- }
- introducerSession->Introduce (*introducer, router);
- }
- else
- LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no introducers present");
- }
- }
-
- void SSUServer::DeleteSession (std::shared_ptr<SSUSession> session)
- {
- if (session)
- {
- session->Close ();
- auto& ep = session->GetRemoteEndpoint ();
- if (ep.address ().is_v6 ())
- m_SessionsV6.erase (ep);
- else
- m_Sessions.erase (ep);
- }
- }
-
- void SSUServer::DeleteAllSessions ()
- {
- for (auto& it: m_Sessions)
- it.second->Close ();
- m_Sessions.clear ();
-
- for (auto& it: m_SessionsV6)
- it.second->Close ();
- m_SessionsV6.clear ();
- }
-
- template<typename Filter>
- std::shared_ptr<SSUSession> SSUServer::GetRandomV4Session (Filter filter) // v4 only
- {
- std::vector<std::shared_ptr<SSUSession> > filteredSessions;
- for (const auto& s :m_Sessions)
- if (filter (s.second)) filteredSessions.push_back (s.second);
- if (filteredSessions.size () > 0)
- {
- auto ind = rand () % filteredSessions.size ();
- return filteredSessions[ind];
- }
- return nullptr;
- }
-
- std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded) // v4 only
- {
- return GetRandomV4Session (
- [excluded](std::shared_ptr<SSUSession> session)->bool
- {
- return session->GetState () == eSessionStateEstablished && session != excluded;
- }
- );
- }
-
- template<typename Filter>
- std::shared_ptr<SSUSession> SSUServer::GetRandomV6Session (Filter filter) // v6 only
- {
- std::vector<std::shared_ptr<SSUSession> > filteredSessions;
- for (const auto& s :m_SessionsV6)
- if (filter (s.second)) filteredSessions.push_back (s.second);
- if (filteredSessions.size () > 0)
- {
- auto ind = rand () % filteredSessions.size ();
- return filteredSessions[ind];
- }
- return nullptr;
- }
-
- std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded) // v6 only
- {
- return GetRandomV6Session (
- [excluded](std::shared_ptr<SSUSession> session)->bool
- {
- return session->GetState () == eSessionStateEstablished && session != excluded;
- }
- );
- }
-
- 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
- int sz = ret.size () - maxNumIntroducers;
- for (int i = 0; i < sz; i++)
- {
- auto ind = rand () % ret.size ();
- auto it = ret.begin ();
- std::advance (it, ind);
- ret.erase (it);
- }
- }
- return ret;
- }
-
- void SSUServer::RescheduleIntroducersUpdateTimer ()
- {
- m_IntroducersUpdateTimer.cancel ();
- 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));
- m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
- this, std::placeholders::_1, true));
- }
-
- void SSUServer::RescheduleIntroducersUpdateTimerV6 ()
- {
- m_IntroducersUpdateTimerV6.cancel ();
- 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
- ScheduleIntroducersUpdateTimer ();
- return;
- }
- if (i2p::context.GetStatus () != eRouterStatusFirewalled)
- {
- // we don't need introducers
- m_Introducers.clear ();
- return;
- }
- // we are firewalled
- if (!i2p::context.IsUnreachable ()) i2p::context.SetUnreachable (true, false); // v4
- }
- else
- {
- if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
- {
- // we still don't know if we need introducers
- ScheduleIntroducersUpdateTimerV6 ();
- return;
- }
- if (i2p::context.GetStatusV6 () != eRouterStatusFirewalled)
- {
- // we don't need introducers
- m_IntroducersV6.clear ();
- 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 ();
- std::set<i2p::data::IdentHash> excluded;
- auto& introducers = v4 ? m_Introducers : m_IntroducersV6;
- for (const auto& it : introducers)
- {
- auto session = FindSession (it);
- if (session)
- {
- 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 ())
- excluded.insert (session->GetRemoteIdentity ()->GetIdentHash ());
- }
- else
- session = nullptr;
- }
- if (!session)
- i2p::context.RemoveIntroducer (it);
- }
- if (numIntroducers < SSU_MAX_NUM_INTRODUCERS)
- {
- // create new
- auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4, excluded); // try to find if duplicates
- if (sessions.empty () && !introducers.empty ())
- {
- // bump creation time for previous introducers if no new sessions found
- LogPrint (eLogDebug, "SSU: No new introducers found. Trying to reuse existing");
- for (const auto& it : introducers)
- {
- 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 ();
- i2p::data::RouterInfo::Introducer introducer;
- introducer.iHost = ep.address ();
- introducer.iPort = ep.port ();
- introducer.iTag = it1->GetRelayTag ();
- introducer.iKey = it1->GetIntroKey ();
- introducer.iExp = it1->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION;
- if (i2p::context.AddIntroducer (introducer))
- {
- newList.push_back (ep);
- if (newList.size () >= SSU_MAX_NUM_INTRODUCERS) break;
- }
- if (it1->GetRemoteIdentity ())
- excluded.insert (it1->GetRemoteIdentity ()->GetIdentHash ());
- }
- }
- introducers = newList;
- 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);
- excluded.insert (introducer->GetIdentHash ());
- }
- }
- }
- else
- {
- LogPrint (eLogDebug, "SSU: Can't find more introducers");
- break;
- }
- }
- }
- if (v4)
- ScheduleIntroducersUpdateTimer ();
- else
- ScheduleIntroducersUpdateTimerV6 ();
- }
- }
-
- void SSUServer::NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session)
- {
- m_PeerTests[nonce] = { i2p::util::GetMillisecondsSinceEpoch (), role, session };
- }
-
- PeerTestParticipant SSUServer::GetPeerTestParticipant (uint32_t nonce)
- {
- auto it = m_PeerTests.find (nonce);
- if (it != m_PeerTests.end ())
- return it->second.role;
- else
- return ePeerTestParticipantUnknown;
- }
-
- std::shared_ptr<SSUSession> SSUServer::GetPeerTestSession (uint32_t nonce)
- {
- auto it = m_PeerTests.find (nonce);
- if (it != m_PeerTests.end ())
- return it->second.session;
- else
- return nullptr;
- }
-
- void SSUServer::UpdatePeerTest (uint32_t nonce, PeerTestParticipant role)
- {
- auto it = m_PeerTests.find (nonce);
- if (it != m_PeerTests.end ())
- it->second.role = role;
- }
-
- void SSUServer::RemovePeerTest (uint32_t nonce)
- {
- m_PeerTests.erase (nonce);
- }
-
- void SSUServer::SchedulePeerTestsCleanupTimer ()
- {
- m_PeerTestsCleanupTimer.expires_from_now (boost::posix_time::seconds(SSU_PEER_TEST_TIMEOUT));
- m_PeerTestsCleanupTimer.async_wait (std::bind (&SSUServer::HandlePeerTestsCleanupTimer,
- this, std::placeholders::_1));
- }
-
- void SSUServer::HandlePeerTestsCleanupTimer (const boost::system::error_code& ecode)
- {
- if (ecode != boost::asio::error::operation_aborted)
- {
- int numDeleted = 0;
- uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
- for (auto it = m_PeerTests.begin (); it != m_PeerTests.end ();)
- {
- if (ts > it->second.creationTime + SSU_PEER_TEST_TIMEOUT*1000LL)
- {
- numDeleted++;
- it = m_PeerTests.erase (it);
- }
- else
- ++it;
- }
- if (numDeleted > 0)
- LogPrint (eLogDebug, "SSU: ", numDeleted, " peer tests have been expired");
- // some cleaups. TODO: use separate timer
- m_FragmentsPool.CleanUp ();
- m_IncompleteMessagesPool.CleanUp ();
- m_SentMessagesPool.CleanUp ();
-
- SchedulePeerTestsCleanupTimer ();
- }
- }
-
- void SSUServer::ScheduleTermination ()
- {
- uint64_t timeout = SSU_TERMINATION_CHECK_TIMEOUT + (rand () % SSU_TERMINATION_CHECK_TIMEOUT)/5;
- m_TerminationTimer.expires_from_now (boost::posix_time::seconds(timeout));
- m_TerminationTimer.async_wait (std::bind (&SSUServer::HandleTerminationTimer,
- this, std::placeholders::_1));
- }
-
- void SSUServer::HandleTerminationTimer (const boost::system::error_code& ecode)
- {
- if (ecode != boost::asio::error::operation_aborted)
- {
- auto ts = i2p::util::GetSecondsSinceEpoch ();
- for (auto& it: m_Sessions)
- if (it.second->IsTerminationTimeoutExpired (ts))
- {
- auto session = it.second;
- if (it.first != session->GetRemoteEndpoint ())
- LogPrint (eLogWarning, "SSU: Remote endpoint ", session->GetRemoteEndpoint (), " doesn't match key ", it.first, " adjusted");
- m_Service.post ([session]
- {
- LogPrint (eLogWarning, "SSU: No activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
- session->Failed ();
- });
- }
- else
- it.second->CleanUp (ts);
- ScheduleTermination ();
- }
- }
-
- void SSUServer::ScheduleTerminationV6 ()
- {
- uint64_t timeout = SSU_TERMINATION_CHECK_TIMEOUT + (rand () % SSU_TERMINATION_CHECK_TIMEOUT)/5;
- m_TerminationTimerV6.expires_from_now (boost::posix_time::seconds(timeout));
- m_TerminationTimerV6.async_wait (std::bind (&SSUServer::HandleTerminationTimerV6,
- this, std::placeholders::_1));
- }
-
- void SSUServer::HandleTerminationTimerV6 (const boost::system::error_code& ecode)
- {
- if (ecode != boost::asio::error::operation_aborted)
- {
- auto ts = i2p::util::GetSecondsSinceEpoch ();
- for (auto& it: m_SessionsV6)
- if (it.second->IsTerminationTimeoutExpired (ts))
- {
- auto session = it.second;
- if (it.first != session->GetRemoteEndpoint ())
- LogPrint (eLogWarning, "SSU: Remote endpoint ", session->GetRemoteEndpoint (), " doesn't match key ", it.first);
- m_Service.post ([session]
- {
- LogPrint (eLogWarning, "SSU: No activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
- session->Failed ();
- });
- }
- else
- it.second->CleanUp (ts);
- ScheduleTerminationV6 ();
- }
- }
-}
-}
|
[-]
[+]
|
Deleted |
_service:tar_git:i2pd-2.43.0+git1.tar.gz/upstream/libi2pd/SSU.h
^
|
@@ -1,159 +0,0 @@
-/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
-*
-* This file is part of Purple i2pd project and licensed under BSD3
-*
-* See full license text in LICENSE file at top of project tree
-*/
-
-#ifndef SSU_H__
-#define SSU_H__
-
-#include <inttypes.h>
-#include <string.h>
-#include <map>
-#include <list>
-#include <set>
-#include <thread>
-#include <mutex>
-#include <boost/asio.hpp>
-#include "Crypto.h"
-#include "util.h"
-#include "I2PEndian.h"
-#include "Identity.h"
-#include "RouterInfo.h"
-#include "I2NPProtocol.h"
-#include "SSUSession.h"
-
-namespace i2p
-{
-namespace transport
-{
- const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
- const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds
- const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
- const int SSU_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes
- const int SSU_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
- const size_t SSU_MAX_NUM_INTRODUCERS = 3;
- const size_t SSU_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
- const size_t SSU_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
-
- struct SSUPacket
- {
- i2p::crypto::AESAlignedBuffer<SSU_MTU_V6 + 18> buf; // max MTU + iv + size
- boost::asio::ip::udp::endpoint from;
- size_t len;
- };
-
- class SSUServer
- {
- public:
-
- SSUServer (int port);
- ~SSUServer ();
- void Start ();
- void Stop ();
- bool CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false, bool v4only = false);
- bool CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
- std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
- void CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest);
- std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const;
- std::shared_ptr<SSUSession> GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded);
- std::shared_ptr<SSUSession> GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded);
- void DeleteSession (std::shared_ptr<SSUSession> session);
- void DeleteAllSessions ();
-
- boost::asio::io_service& GetService () { return m_Service; };
- i2p::util::MemoryPool<Fragment>& GetFragmentsPool () { return m_FragmentsPool; };
- i2p::util::MemoryPool<IncompleteMessage>& GetIncompleteMessagesPool () { return m_IncompleteMessagesPool; };
- i2p::util::MemoryPool<SentMessage>& GetSentMessagesPool () { return m_SentMessagesPool; };
-
- uint16_t GetPort () const { return m_Endpoint.port (); };
- bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
- void SetLocalAddress (const boost::asio::ip::address& localAddress);
-
- void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
- void AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay);
- void RemoveRelay (uint32_t tag);
- std::shared_ptr<SSUSession> FindRelaySession (uint32_t tag);
- void RescheduleIntroducersUpdateTimer ();
- void RescheduleIntroducersUpdateTimerV6 ();
-
- void NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session = nullptr);
- PeerTestParticipant GetPeerTestParticipant (uint32_t nonce);
- std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce);
- void UpdatePeerTest (uint32_t nonce, PeerTestParticipant role);
- void RemovePeerTest (uint32_t nonce);
-
- private:
-
- void OpenSocket ();
- void OpenSocketV6 ();
- void Run ();
- void RunReceivers ();
- void RunReceiversV6 ();
- void Receive ();
- void ReceiveV6 ();
- void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
- void HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
- void HandleReceivedPackets (std::vector<SSUPacket *> packets,
- std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions);
-
- void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
- std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
- template<typename Filter>
- std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter);
- template<typename Filter>
- std::shared_ptr<SSUSession> GetRandomV6Session (Filter filter);
-
- std::list<std::shared_ptr<SSUSession> > FindIntroducers (int maxNumIntroducers, bool v4, std::set<i2p::data::IdentHash>& excluded);
- void ScheduleIntroducersUpdateTimer ();
- void ScheduleIntroducersUpdateTimerV6 ();
- void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4);
-
- void SchedulePeerTestsCleanupTimer ();
- void HandlePeerTestsCleanupTimer (const boost::system::error_code& ecode);
-
- // timer
- void ScheduleTermination ();
- void HandleTerminationTimer (const boost::system::error_code& ecode);
- void ScheduleTerminationV6 ();
- void HandleTerminationTimerV6 (const boost::system::error_code& ecode);
-
- private:
-
- struct PeerTest
- {
- uint64_t creationTime;
- PeerTestParticipant role;
- std::shared_ptr<SSUSession> session; // for Bob to Alice
- };
-
- volatile bool m_IsRunning;
- std::thread * m_Thread, * m_ReceiversThread, * m_ReceiversThreadV6;
- boost::asio::io_service m_Service, m_ReceiversService, m_ReceiversServiceV6;
- boost::asio::io_service::work m_Work, m_ReceiversWork, m_ReceiversWorkV6;
- boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6;
- boost::asio::ip::udp::socket m_Socket, m_SocketV6;
- boost::asio::deadline_timer m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6,
- m_PeerTestsCleanupTimer, m_TerminationTimer, m_TerminationTimerV6;
- bool m_IsSyncClockFromPeers;
- std::list<boost::asio::ip::udp::endpoint> m_Introducers, m_IntroducersV6; // introducers we are connected to
- std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions, m_SessionsV6;
- std::map<uint32_t, std::shared_ptr<SSUSession> > m_Relays; // we are introducer
- std::map<uint32_t, PeerTest> m_PeerTests; // nonce -> creation time in milliseconds
-
- i2p::util::MemoryPool<Fragment> m_FragmentsPool;
- i2p::util::MemoryPool<IncompleteMessage> m_IncompleteMessagesPool;
- i2p::util::MemoryPool<SentMessage> m_SentMessagesPool;
- i2p::util::MemoryPoolMt<SSUPacket> m_PacketsPool;
-
- public:
- // for HTTP only
- const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
- const decltype(m_SessionsV6)& GetSessionsV6 () const { return m_SessionsV6; };
- };
-}
-}
-
-#endif
|
[-]
[+]
|
Deleted |
_service:tar_git:i2pd-2.43.0+git1.tar.gz/upstream/libi2pd/SSUData.cpp
^
|
@@ -1,516 +0,0 @@
-/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
-*
-* This file is part of Purple i2pd project and licensed under BSD3
-*
-* See full license text in LICENSE file at top of project tree
-*/
-
-#include <stdlib.h>
-#include "Log.h"
-#include "Timestamp.h"
-#include "NetDb.hpp"
-#include "SSU.h"
-#include "SSUData.h"
-
-namespace i2p
-{
-namespace transport
-{
- void IncompleteMessage::AttachNextFragment (const uint8_t * fragment, size_t fragmentSize)
- {
- if (msg->len + fragmentSize > msg->maxLen)
- {
- LogPrint (eLogWarning, "SSU: I2NP message size ", msg->maxLen, " is not enough");
- auto newMsg = NewI2NPMessage ();
- *newMsg = *msg;
- msg = newMsg;
- }
- if (msg->Concat (fragment, fragmentSize) < fragmentSize)
- LogPrint (eLogError, "SSU: I2NP buffer overflow ", msg->maxLen);
- nextFragmentNum++;
- }
-
- SSUData::SSUData (SSUSession& session):
- m_Session (session), m_ResendTimer (session.GetService ()),
- m_MaxPacketSize (session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE),
- m_PacketSize (m_MaxPacketSize), m_LastMessageReceivedTime (0)
- {
- }
-
- SSUData::~SSUData ()
- {
- }
-
- void SSUData::Start ()
- {
- }
-
- void SSUData::Stop ()
- {
- m_ResendTimer.cancel ();
- m_IncompleteMessages.clear ();
- m_SentMessages.clear ();
- m_ReceivedMessages.clear ();
- }
-
- void SSUData::AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter)
- {
- if (!remoteRouter) return;
- auto ssuAddress = remoteRouter->GetSSUAddress ();
- if (ssuAddress && ssuAddress->ssu->mtu)
- {
- if (m_Session.IsV6 ())
- m_PacketSize = ssuAddress->ssu->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE;
- else
- m_PacketSize = ssuAddress->ssu->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE;
- if (m_PacketSize > 0)
- {
- // make sure packet size multiple of 16
- m_PacketSize >>= 4;
- m_PacketSize <<= 4;
- if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize;
- LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize);
- }
- else
- {
- LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu);
- m_PacketSize = m_MaxPacketSize;
- }
- }
- }
-
- void SSUData::UpdatePacketSize (const i2p::data::IdentHash& remoteIdent)
- {
- auto routerInfo = i2p::data::netdb.FindRouter (remoteIdent);
- if (routerInfo)
- AdjustPacketSize (routerInfo);
- }
-
- void SSUData::ProcessSentMessageAck (uint32_t msgID)
- {
- auto it = m_SentMessages.find (msgID);
- if (it != m_SentMessages.end ())
- {
- m_SentMessages.erase (it);
- if (m_SentMessages.empty ())
- m_ResendTimer.cancel ();
- }
- }
-
- void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag)
- {
- if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED)
- {
- // explicit ACKs
- uint8_t numAcks =*buf;
- buf++;
- for (int i = 0; i < numAcks; i++)
- ProcessSentMessageAck (bufbe32toh (buf+i*4));
- buf += numAcks*4;
- }
- if (flag & DATA_FLAG_ACK_BITFIELDS_INCLUDED)
- {
- // explicit ACK bitfields
- uint8_t numBitfields =*buf;
- buf++;
- for (int i = 0; i < numBitfields; i++)
- {
- uint32_t msgID = bufbe32toh (buf);
- buf += 4; // msgID
- auto it = m_SentMessages.find (msgID);
- // process individual Ack bitfields
- bool isNonLast = false;
- int fragment = 0;
- do
- {
- uint8_t bitfield = *buf;
- isNonLast = bitfield & 0x80;
- bitfield &= 0x7F; // clear MSB
- if (bitfield && it != m_SentMessages.end ())
- {
- int numSentFragments = it->second->fragments.size ();
- // process bits
- uint8_t mask = 0x01;
- for (int j = 0; j < 7; j++)
- {
- if (bitfield & mask)
- {
- if (fragment < numSentFragments)
- it->second->fragments[fragment] = nullptr;
- }
- fragment++;
- mask <<= 1;
- }
- }
- buf++;
- }
- while (isNonLast);
- }
- }
- }
-
- void SSUData::ProcessFragments (uint8_t * buf)
- {
- uint8_t numFragments = *buf; // number of fragments
- buf++;
- for (int i = 0; i < numFragments; i++)
- {
- uint32_t msgID = bufbe32toh (buf); // message ID
- buf += 4;
- uint8_t frag[4] = {0};
- memcpy (frag + 1, buf, 3);
- buf += 3;
- uint32_t fragmentInfo = bufbe32toh (frag); // fragment info
- uint16_t fragmentSize = fragmentInfo & 0x3FFF; // bits 0 - 13
- bool isLast = fragmentInfo & 0x010000; // bit 16
- uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
- if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE)
- {
- LogPrint (eLogError, "SSU: Fragment size ", fragmentSize, " exceeds max SSU packet size");
- return;
- }
-
- // find message with msgID
- auto it = m_IncompleteMessages.find (msgID);
- if (it == m_IncompleteMessages.end ())
- {
- // create new message
- auto msg = NewI2NPShortMessage ();
- msg->len -= I2NP_SHORT_HEADER_SIZE;
- it = m_IncompleteMessages.insert (std::make_pair (msgID,
- m_Session.GetServer ().GetIncompleteMessagesPool ().AcquireShared (std::move (msg)))).first;
- }
- auto& incompleteMessage = it->second;
- // mark fragment as received
- if (fragmentNum < 64)
- incompleteMessage->receivedFragmentsBits |= (uint64_t(0x01) << fragmentNum);
- else
- LogPrint (eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64");
-
- // handle current fragment
- if (fragmentNum == incompleteMessage->nextFragmentNum)
- {
- // expected fragment
- incompleteMessage->AttachNextFragment (buf, fragmentSize);
- if (!isLast && !incompleteMessage->savedFragments.empty ())
- {
- // try saved fragments
- for (auto it1 = incompleteMessage->savedFragments.begin (); it1 != incompleteMessage->savedFragments.end ();)
- {
- auto& savedFragment = *it1;
- if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum)
- {
- incompleteMessage->AttachNextFragment (savedFragment->buf, savedFragment->len);
- isLast = savedFragment->isLast;
- incompleteMessage->savedFragments.erase (it1++);
- }
- else
- break;
- }
- if (isLast)
- LogPrint (eLogDebug, "SSU: Message ", msgID, " complete");
- }
- }
- else
- {
- if (fragmentNum < incompleteMessage->nextFragmentNum)
- // duplicate fragment
- LogPrint (eLogWarning, "SSU: Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ", ignored");
- else
- {
- // missing fragment
- LogPrint (eLogWarning, "SSU: Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
- auto savedFragment = m_Session.GetServer ().GetFragmentsPool ().AcquireShared (fragmentNum, buf, fragmentSize, isLast);
- if (incompleteMessage->savedFragments.insert (savedFragment).second)
- incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
- else
- LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
- }
- isLast = false;
- }
-
- if (isLast)
- {
- // delete incomplete message
- auto msg = incompleteMessage->msg;
- incompleteMessage->msg = nullptr;
- m_IncompleteMessages.erase (msgID);
- // process message
- SendMsgAck (msgID);
- msg->FromSSU (msgID);
- if (m_Session.GetState () == eSessionStateEstablished)
- {
- if (!m_ReceivedMessages.count (msgID))
- {
- m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch ();
- m_ReceivedMessages.emplace (msgID, m_LastMessageReceivedTime);
- if (!msg->IsExpired ())
- {
- m_Handler.PutNextMessage (std::move (msg));
- }
- else
- LogPrint (eLogDebug, "SSU: message expired");
- }
- else
- LogPrint (eLogWarning, "SSU: Message ", msgID, " already received");
- }
- else
- {
- // we expect DeliveryStatus
- if (msg->GetTypeID () == eI2NPDeliveryStatus)
- {
- LogPrint (eLogDebug, "SSU: session established");
- m_Session.Established ();
- }
- else
- LogPrint (eLogError, "SSU: unexpected message ", (int)msg->GetTypeID ());
- }
- }
- else
- SendFragmentAck (msgID, incompleteMessage->receivedFragmentsBits);
- buf += fragmentSize;
- }
- }
-
- void SSUData::FlushReceivedMessage ()
- {
- m_Handler.Flush ();
- }
-
- void SSUData::ProcessMessage (uint8_t * buf, size_t len)
- {
- //uint8_t * start = buf;
- uint8_t flag = *buf;
- buf++;
- LogPrint (eLogDebug, "SSU: Process data, flags=", (int)flag, ", len=", len);
- // process acks if presented
- if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED))
- ProcessAcks (buf, flag);
- // extended data if presented
- if (flag & DATA_FLAG_EXTENDED_DATA_INCLUDED)
- {
- uint8_t extendedDataSize = *buf;
- buf++; // size
- LogPrint (eLogDebug, "SSU: extended data of ", extendedDataSize, " bytes present");
- buf += extendedDataSize;
- }
- // process data
- ProcessFragments (buf);
- }
-
- void SSUData::Send (std::shared_ptr<i2p::I2NPMessage> msg)
- {
- uint32_t msgID = msg->ToSSU ();
- if (m_SentMessages.find (msgID) != m_SentMessages.end())
- {
- LogPrint (eLogWarning, "SSU: message ", msgID, " already sent");
- return;
- }
- if (m_SentMessages.empty ()) // schedule resend at first message only
- ScheduleResend ();
-
- auto ret = m_SentMessages.emplace (msgID, m_Session.GetServer ().GetSentMessagesPool ().AcquireShared ());
- auto& sentMessage = ret.first->second;
- if (ret.second)
- {
- sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL;
- sentMessage->numResends = 0;
- }
- auto& fragments = sentMessage->fragments;
- size_t payloadSize = m_PacketSize - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
- size_t len = msg->GetLength ();
- uint8_t * msgBuf = msg->GetSSUHeader ();
-
- uint32_t fragmentNum = 0;
- while (len > 0 && fragmentNum <= 127)
- {
- auto fragment = m_Session.GetServer ().GetFragmentsPool ().AcquireShared ();
- fragment->fragmentNum = fragmentNum;
- uint8_t * payload = fragment->buf + sizeof (SSUHeader);
- *payload = DATA_FLAG_WANT_REPLY; // for compatibility
- payload++;
- *payload = 1; // always 1 message fragment per message
- payload++;
- htobe32buf (payload, msgID);
- payload += 4;
- bool isLast = (len <= payloadSize) || fragmentNum == 127; // 127 fragments max
- size_t size = isLast ? len : payloadSize;
- uint32_t fragmentInfo = (fragmentNum << 17);
- if (isLast)
- fragmentInfo |= 0x010000;
-
- fragmentInfo |= size;
- fragmentInfo = htobe32 (fragmentInfo);
- memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3);
- payload += 3;
- memcpy (payload, msgBuf, size);
-
- size += payload - fragment->buf;
- uint8_t rem = size & 0x0F;
- if (rem) // make sure 16 bytes boundary
- {
- auto padding = 16 - rem;
- memset (fragment->buf + size, 0, padding);
- size += padding;
- }
- fragment->len = size;
- fragments.push_back (fragment);
-
- // encrypt message with session key
- uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
- m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, fragment->buf, size, buf);
- try
- {
- m_Session.Send (buf, size);
- }
- catch (boost::system::system_error& ec)
- {
- LogPrint (eLogWarning, "SSU: Can't send data fragment ", ec.what ());
- }
- if (!isLast)
- {
- len -= payloadSize;
- msgBuf += payloadSize;
- }
- else
- len = 0;
- fragmentNum++;
- }
- }
-
- void SSUData::SendMsgAck (uint32_t msgID)
- {
- uint8_t buf[48 + 18] = {0}; // actual length is 44 = 37 + 7 but pad it to multiple of 16
- uint8_t * payload = buf + sizeof (SSUHeader);
- *payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag
- payload++;
- *payload = 1; // number of ACKs
- payload++;
- htobe32buf (payload, msgID); // msgID
- payload += 4;
- *payload = 0; // number of fragments
-
- // encrypt message with session key
- m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
- m_Session.Send (buf, 48);
- }
-
- void SSUData::SendFragmentAck (uint32_t msgID, uint64_t bits)
- {
- if (!bits) return;
- uint8_t buf[64 + 18] = {0};
- uint8_t * payload = buf + sizeof (SSUHeader);
- *payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag
- payload++;
- *payload = 1; // number of ACK bitfields
- payload++;
- // one ack
- *(uint32_t *)(payload) = htobe32 (msgID); // msgID
- payload += 4;
- size_t len = 0;
- while (bits)
- {
- *payload = (bits & 0x7F); // next 7 bits
- bits >>= 7;
- if (bits) *payload &= 0x80; // 0x80 means non-last
- payload++; len++;
- }
- *payload = 0; // number of fragments
- len = (len <= 4) ? 48 : 64; // 48 = 37 + 7 + 4
- // encrypt message with session key
- m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len);
- m_Session.Send (buf, len);
- }
-
- void SSUData::ScheduleResend()
- {
- m_ResendTimer.cancel ();
- m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL));
- auto s = m_Session.shared_from_this();
- m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode)
- { s->m_Data.HandleResendTimer (ecode); });
- }
-
- void SSUData::HandleResendTimer (const boost::system::error_code& ecode)
- {
- if (ecode != boost::asio::error::operation_aborted)
- {
- uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
- uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
- int numResent = 0;
- for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
- {
- if (ts >= it->second->nextResendTime)
- {
- if (it->second->numResends < MAX_NUM_RESENDS)
- {
- for (auto& f: it->second->fragments)
- if (f)
- {
- try
- {
- m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, f->buf, f->len, buf);
- m_Session.Send (buf, f->len); // resend
- numResent++;
- }
- catch (boost::system::system_error& ec)
- {
- LogPrint (eLogWarning, "SSU: Can't resend message ", it->first, " data fragment: ", ec.what ());
- }
- }
-
- it->second->numResends++;
- it->second->nextResendTime += it->second->numResends*RESEND_INTERVAL;
- ++it;
- }
- else
- {
- LogPrint (eLogInfo, "SSU: message ", it->first, " has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
- it = m_SentMessages.erase (it);
- }
- }
- else
- ++it;
- }
- if (m_SentMessages.empty ()) return; // nothing to resend
- if (numResent < MAX_OUTGOING_WINDOW_SIZE)
- ScheduleResend ();
- else
- {
- LogPrint (eLogError, "SSU: resend window exceeds max size. Session terminated");
- m_Session.Close ();
- }
- }
- }
-
- void SSUData::CleanUp (uint64_t ts)
- {
- for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();)
- {
- if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT)
- {
- LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
- it = m_IncompleteMessages.erase (it);
- }
- else
- ++it;
- }
-
- if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES || ts > m_LastMessageReceivedTime + DECAY_INTERVAL)
- // decay
- m_ReceivedMessages.clear ();
- else
- {
- // delete old received messages
- for (auto it = m_ReceivedMessages.begin (); it != m_ReceivedMessages.end ();)
- {
- if (ts > it->second + RECEIVED_MESSAGES_CLEANUP_TIMEOUT)
- it = m_ReceivedMessages.erase (it);
- else
- ++it;
- }
- }
- }
-}
-}
|
[-]
[+]
|
Deleted |
_service:tar_git:i2pd-2.43.0+git1.tar.gz/upstream/libi2pd/SSUData.h
^
|
@@ -1,131 +0,0 @@
-/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
-*
-* This file is part of Purple i2pd project and licensed under BSD3
-*
-* See full license text in LICENSE file at top of project tree
-*/
-
-#ifndef SSU_DATA_H__
-#define SSU_DATA_H__
-
-#include <inttypes.h>
-#include <string.h>
-#include <vector>
-#include <map>
-#include <unordered_map>
-#include <memory>
-#include <boost/asio.hpp>
-#include "I2NPProtocol.h"
-#include "Identity.h"
-#include "RouterInfo.h"
-#include "TransportSession.h"
-
-namespace i2p
-{
-namespace transport
-{
- const size_t SSU_MTU_V4 = 1484;
- const size_t SSU_MTU_V6 = 1488;
- const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456
- const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1440
- const int RESEND_INTERVAL = 3; // in seconds
- const int MAX_NUM_RESENDS = 5;
- const int DECAY_INTERVAL = 20; // in seconds
- const int INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
- const int RECEIVED_MESSAGES_CLEANUP_TIMEOUT = 40; // in seconds
- const unsigned int MAX_NUM_RECEIVED_MESSAGES = 1000; // how many msgID we store for duplicates check
- const int MAX_OUTGOING_WINDOW_SIZE = 200; // how many unacked message we can store
- // data flags
- const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
- const uint8_t DATA_FLAG_WANT_REPLY = 0x04;
- const uint8_t DATA_FLAG_REQUEST_PREVIOUS_ACKS = 0x08;
- const uint8_t DATA_FLAG_EXPLICIT_CONGESTION_NOTIFICATION = 0x10;
- const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
- const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
-
- struct Fragment
- {
- int fragmentNum;
- size_t len;
- bool isLast;
- uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest
-
- Fragment () = default;
- Fragment (int n, const uint8_t * b, int l, bool last):
- fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); };
- };
-
- struct FragmentCmp
- {
- bool operator() (const std::shared_ptr<Fragment>& f1, const std::shared_ptr<Fragment>& f2) const
- {
- return f1->fragmentNum < f2->fragmentNum;
- };
- };
-
- struct IncompleteMessage
- {
- std::shared_ptr<I2NPMessage> msg;
- int nextFragmentNum;
- uint32_t lastFragmentInsertTime; // in seconds
- uint64_t receivedFragmentsBits;
- std::set<std::shared_ptr<Fragment>, FragmentCmp> savedFragments;
-
- IncompleteMessage (std::shared_ptr<I2NPMessage>&& m): msg (m), nextFragmentNum (0),
- lastFragmentInsertTime (0), receivedFragmentsBits (0) {};
- void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
- };
-
- struct SentMessage
- {
- std::vector<std::shared_ptr<Fragment> > fragments;
- uint32_t nextResendTime; // in seconds
- int numResends;
- };
-
- class SSUSession;
- class SSUData
- {
- public:
-
- SSUData (SSUSession& session);
- ~SSUData ();
-
- void Start ();
- void Stop ();
- void CleanUp (uint64_t ts);
-
- void ProcessMessage (uint8_t * buf, size_t len);
- void FlushReceivedMessage ();
- void Send (std::shared_ptr<i2p::I2NPMessage> msg);
-
- void AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter);
- void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent);
-
- private:
-
- void SendMsgAck (uint32_t msgID);
- void SendFragmentAck (uint32_t msgID, uint64_t bits);
- void ProcessAcks (uint8_t *& buf, uint8_t flag);
- void ProcessFragments (uint8_t * buf);
- void ProcessSentMessageAck (uint32_t msgID);
-
- void ScheduleResend ();
- void HandleResendTimer (const boost::system::error_code& ecode);
-
- private:
-
- SSUSession& m_Session;
- std::map<uint32_t, std::shared_ptr<IncompleteMessage> > m_IncompleteMessages;
- std::map<uint32_t, std::shared_ptr<SentMessage> > m_SentMessages;
- std::unordered_map<uint32_t, uint64_t> m_ReceivedMessages; // msgID -> timestamp in seconds
- boost::asio::deadline_timer m_ResendTimer;
- int m_MaxPacketSize, m_PacketSize;
- i2p::I2NPMessagesHandler m_Handler;
- uint32_t m_LastMessageReceivedTime; // in second
- };
-}
-}
-
-#endif
|
[-]
[+]
|
Deleted |
_service:tar_git:i2pd-2.43.0+git1.tar.gz/upstream/libi2pd/SSUSession.cpp
^
|
@@ -1,1318 +0,0 @@
-/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
-*
-* This file is part of Purple i2pd project and licensed under BSD3
-*
-* See full license text in LICENSE file at top of project tree
-*/
-
-#include "version.h"
-#include "Crypto.h"
-#include "Log.h"
-#include "Timestamp.h"
-#include "RouterContext.h"
-#include "Transports.h"
-#include "NetDb.hpp"
-#include "SSU.h"
-#include "SSUSession.h"
-
-namespace i2p
-{
-namespace transport
-{
- SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
- std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest ):
- TransportSession (router, SSU_TERMINATION_TIMEOUT),
- m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_ConnectTimer (GetService ()),
- m_IsPeerTest (peerTest),m_State (eSessionStateUnknown), m_IsSessionKey (false),
- m_RelayTag (0), m_SentRelayTag (0), m_Data (*this), m_IsDataReceived (false)
- {
- if (router)
- {
- // we are client
- auto address = IsV6 () ? router->GetSSUV6Address () : router->GetSSUAddress (true);
- if (address) m_IntroKey = address->i;
- m_Data.AdjustPacketSize (router); // mtu
- }
- else
- {
- // we are server
- auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () :
- i2p::context.GetRouterInfo ().GetSSUAddress (true);
- if (address) m_IntroKey = address->i;
- }
- }
-
- SSUSession::~SSUSession ()
- {
- }
-
- boost::asio::io_service& SSUSession::GetService ()
- {
- return m_Server.GetService ();
- }
-
- void SSUSession::CreateAESandMacKey (const uint8_t * pubKey)
- {
- uint8_t sharedKey[256];
- m_DHKeysPair->Agree (pubKey, sharedKey);
-
- uint8_t * sessionKey = m_SessionKey, * macKey = m_MacKey;
- if (sharedKey[0] & 0x80)
- {
- sessionKey[0] = 0;
- memcpy (sessionKey + 1, sharedKey, 31);
- memcpy (macKey, sharedKey + 31, 32);
- }
- else if (sharedKey[0])
- {
- memcpy (sessionKey, sharedKey, 32);
- memcpy (macKey, sharedKey + 32, 32);
- }
- else
- {
- // find first non-zero byte
- uint8_t * nonZero = sharedKey + 1;
- while (!*nonZero)
- {
- nonZero++;
- if (nonZero - sharedKey > 32)
- {
- LogPrint (eLogWarning, "SSU: First 32 bytes of shared key is all zeros. Ignored");
- return;
- }
- }
-
- memcpy (sessionKey, nonZero, 32);
- SHA256(nonZero, 64 - (nonZero - sharedKey), macKey);
- }
- m_IsSessionKey = true;
- m_SessionKeyEncryption.SetKey (m_SessionKey);
- m_SessionKeyDecryption.SetKey (m_SessionKey);
- }
-
- void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
- {
- m_NumReceivedBytes += len;
- i2p::transport::transports.UpdateReceivedBytes (len);
- if (m_State == eSessionStateIntroduced)
- {
- // HolePunch received
- LogPrint (eLogDebug, "SSU: HolePunch of ", len, " bytes received");
- m_State = eSessionStateUnknown;
- Connect ();
- }
- else
- {
- if (!len) return; // ignore zero-length packets
- if (m_State == eSessionStateEstablished)
- m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
-
- if (m_IsSessionKey && Validate (buf, len, m_MacKey)) // try session key first
- DecryptSessionKey (buf, len);
- else
- {
- if (m_State == eSessionStateEstablished) Reset (); // new session key required
- // try intro key depending on side
- if (Validate (buf, len, m_IntroKey))
- Decrypt (buf, len, m_IntroKey);
- else
- {
- // try own intro key
- auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () :
- i2p::context.GetRouterInfo ().GetSSUAddress (true);
- if (!address)
- {
- LogPrint (eLogInfo, "SSU: SSU is not supported");
- return;
- }
- if (Validate (buf, len, address->i))
- Decrypt (buf, len, address->i);
- else
- {
- LogPrint (eLogWarning, "SSU: MAC verification failed ", len, " bytes from ", senderEndpoint);
- m_Server.DeleteSession (shared_from_this ());
- return;
- }
- }
- }
- // successfully decrypted
- ProcessMessage (buf, len, senderEndpoint);
- }
- }
-
- size_t SSUSession::GetSSUHeaderSize (const uint8_t * buf) const
- {
- size_t s = sizeof (SSUHeader);
- if (((const SSUHeader *)buf)->IsExtendedOptions ())
- s += buf[s] + 1; // byte right after header is extended options length
- return s;
- }
-
- void SSUSession::ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
- {
- len -= (len & 0x0F); // %16, delete extra padding
- if (len <= sizeof (SSUHeader)) return; // drop empty message
- //TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved
- auto headerSize = GetSSUHeaderSize (buf);
- if (headerSize >= len)
- {
- LogPrint (eLogError, "SSU: SSU header size ", headerSize, " exceeds packet length ", len);
- return;
- }
- SSUHeader * header = (SSUHeader *)buf;
- switch (header->GetPayloadType ())
- {
- case PAYLOAD_TYPE_DATA:
- ProcessData (buf + headerSize, len - headerSize);
- break;
- case PAYLOAD_TYPE_SESSION_REQUEST:
- ProcessSessionRequest (buf, len); // buf with header
- break;
- case PAYLOAD_TYPE_SESSION_CREATED:
- ProcessSessionCreated (buf, len); // buf with header
- break;
- case PAYLOAD_TYPE_SESSION_CONFIRMED:
- ProcessSessionConfirmed (buf, len); // buf with header
- break;
- case PAYLOAD_TYPE_PEER_TEST:
- LogPrint (eLogDebug, "SSU: Peer test received");
- ProcessPeerTest (buf + headerSize, len - headerSize, senderEndpoint);
- break;
- case PAYLOAD_TYPE_SESSION_DESTROYED:
- {
- LogPrint (eLogDebug, "SSU: Session destroy received");
- m_Server.DeleteSession (shared_from_this ());
- break;
- }
- case PAYLOAD_TYPE_RELAY_RESPONSE:
- ProcessRelayResponse (buf + headerSize, len - headerSize);
- if (m_State != eSessionStateEstablished)
- m_Server.DeleteSession (shared_from_this ());
- break;
- case PAYLOAD_TYPE_RELAY_REQUEST:
- LogPrint (eLogDebug, "SSU: Relay request received");
- ProcessRelayRequest (buf + headerSize, len - headerSize, senderEndpoint);
- break;
- case PAYLOAD_TYPE_RELAY_INTRO:
- LogPrint (eLogDebug, "SSU: Relay intro received");
- ProcessRelayIntro (buf + headerSize, len - headerSize);
- break;
- default:
- LogPrint (eLogWarning, "SSU: Unexpected payload type ", (int)header->GetPayloadType ());
- }
- }
-
- void SSUSession::ProcessSessionRequest (const uint8_t * buf, size_t len)
- {
- LogPrint (eLogDebug, "SSU message: Session request");
- bool sendRelayTag = true;
- auto headerSize = sizeof (SSUHeader);
- if (((SSUHeader *)buf)->IsExtendedOptions ())
- {
- uint8_t extendedOptionsLen = buf[headerSize];
- headerSize++;
- if (extendedOptionsLen >= 2) // options are presented
- {
- uint16_t flags = bufbe16toh (buf + headerSize);
- sendRelayTag = flags & EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG;
- }
- headerSize += extendedOptionsLen;
- }
- if (headerSize >= len)
- {
- LogPrint (eLogError, "SSU message: Session request header size ", headerSize, " exceeds packet length ", len);
- return;
- }
- if (!m_DHKeysPair)
- {
- auto pair = std::make_shared<i2p::crypto::DHKeys> ();
- pair->GenerateKeys ();
- m_DHKeysPair = pair;
- }
- CreateAESandMacKey (buf + headerSize);
- SendSessionCreated (buf + headerSize, sendRelayTag);
- }
-
- void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len)
- {
- if (!IsOutgoing () || !m_DHKeysPair)
- {
- LogPrint (eLogWarning, "SSU: Unsolicited session created message");
- return;
- }
-
- LogPrint (eLogDebug, "SSU message: session created");
- m_ConnectTimer.cancel (); // connect timer
- SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time
- auto headerSize = GetSSUHeaderSize (buf);
- if (headerSize >= len)
- {
- LogPrint (eLogError, "SSU message: Session created header size ", headerSize, " exceeds packet length ", len);
- return;
- }
- uint8_t * payload = buf + headerSize;
- uint8_t * y = payload;
- CreateAESandMacKey (y);
- s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x
- s.Insert (y, 256); // y
- payload += 256;
- boost::asio::ip::address ourIP;
- uint16_t ourPort = 0;
- auto addressAndPortLen = ExtractIPAddressAndPort (payload, len, ourIP, ourPort);
- if (!addressAndPortLen) return;
- uint8_t * ourAddressAndPort = payload + 1;
- payload += addressAndPortLen;
- addressAndPortLen--; // -1 byte address size
- s.Insert (ourAddressAndPort, addressAndPortLen); // address + port
- if (m_RemoteEndpoint.address ().is_v4 ())
- s.Insert (m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data (), 4); // remote IP v4
- else
- s.Insert (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), 16); // remote IP v6
- s.Insert<uint16_t> (htobe16 (m_RemoteEndpoint.port ())); // remote port
- s.Insert (payload, 8); // relayTag and signed on time
- m_RelayTag = bufbe32toh (payload);
- payload += 4; // relayTag
- uint32_t signedOnTime = bufbe32toh(payload);
- payload += 4; // signed on time
- // decrypt signature
- size_t signatureLen = m_RemoteIdentity->GetSignatureLen ();
- size_t paddingSize = signatureLen & 0x0F; // %16
- if (paddingSize > 0) signatureLen += (16 - paddingSize);
- //TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved
- m_SessionKeyDecryption.SetIV (((SSUHeader *)buf)->iv);
- m_SessionKeyDecryption.Decrypt (payload, signatureLen, payload); // TODO: non-const payload
- // verify signature
- if (s.Verify (m_RemoteIdentity, payload))
- {
- if (ourIP.is_v4 () && i2p::context.GetStatus () == eRouterStatusTesting)
- {
- auto ts = i2p::util::GetSecondsSinceEpoch ();
- int offset = (int)ts - signedOnTime;
- if (m_Server.IsSyncClockFromPeers ())
- {
- if (std::abs (offset) > SSU_CLOCK_THRESHOLD)
- {
- LogPrint (eLogWarning, "SSU: Clock adjusted by ", -offset, " seconds");
- i2p::util::AdjustTimeOffset (-offset);
- }
- }
- else if (std::abs (offset) > SSU_CLOCK_SKEW)
- {
- LogPrint (eLogError, "SSU: Clock skew detected ", offset, ". Check your clock");
- i2p::context.SetError (eRouterErrorClockSkew);
- }
- }
- LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort);
- if (!i2p::util::net::IsInReservedRange (ourIP))
- {
- i2p::context.UpdateAddress (ourIP);
- SendSessionConfirmed (y, ourAddressAndPort, addressAndPortLen);
- }
- else
- {
- LogPrint (eLogError, "SSU: External address ", ourIP.to_string (), " is in reserved range");
- Failed ();
- }
- }
- else
- {
- LogPrint (eLogError, "SSU: Message 'created' signature verification failed");
- Failed ();
- }
- }
-
- void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len)
- {
- LogPrint (eLogDebug, "SSU: Session confirmed received");
- m_ConnectTimer.cancel ();
- auto headerSize = GetSSUHeaderSize (buf);
- if (headerSize >= len)
- {
- LogPrint (eLogError, "SSU: Session confirmed header size ", headerSize, " exceeds packet length ", len);
- return;
- }
- const uint8_t * payload = buf + headerSize;
- payload++; // identity fragment info
- uint16_t identitySize = bufbe16toh (payload);
- if (identitySize + headerSize + 7 > len) // 7 = fragment info + fragment size + signed on time
- {
- LogPrint (eLogError, "SSU: Session confirmed identity size ", identitySize, " exceeds packet length ", len);
- return;
- }
- payload += 2; // size of identity fragment
- auto identity = std::make_shared<i2p::data::IdentityEx> (payload, identitySize);
- auto existing = i2p::data::netdb.FindRouter (identity->GetIdentHash ()); // check if exists already
- SetRemoteIdentity (existing ? existing->GetRouterIdentity () : identity);
- m_Data.UpdatePacketSize (m_RemoteIdentity->GetIdentHash ());
- payload += identitySize; // identity
- auto ts = i2p::util::GetSecondsSinceEpoch ();
- uint32_t signedOnTime = bufbe32toh(payload);
- if (signedOnTime < ts - SSU_CLOCK_SKEW || signedOnTime > ts + SSU_CLOCK_SKEW)
- {
- LogPrint (eLogError, "SSU: Message 'confirmed' time difference ", (int)ts - signedOnTime, " exceeds clock skew");
- Failed ();
- return;
- }
- if (m_SignedData)
- m_SignedData->Insert (payload, 4); // insert Alice's signed on time
- payload += 4; // signed-on time
- size_t fullSize = (payload - buf) + m_RemoteIdentity->GetSignatureLen ();
- size_t paddingSize = fullSize & 0x0F; // %16
- if (paddingSize > 0) paddingSize = 16 - paddingSize;
- payload += paddingSize;
- if (fullSize + paddingSize > len)
- {
- LogPrint (eLogError, "SSU: Session confirmed message is too short ", len);
- return;
- }
- // verify signature
- if (m_SignedData && m_SignedData->Verify (m_RemoteIdentity, payload))
- {
- m_Data.Send (CreateDeliveryStatusMsg (0));
- Established ();
- }
- else
- {
- LogPrint (eLogError, "SSU: Message 'confirmed' signature verification failed");
- Failed ();
- }
- }
-
- void SSUSession::SendSessionRequest ()
- {
- uint8_t buf[320 + 18] = {0}; // 304 bytes for ipv4, 320 for ipv6
- uint8_t * payload = buf + sizeof (SSUHeader);
- uint8_t flag = 0;
- // fill extended options, 3 bytes extended options don't change message size
- bool isV4 = m_RemoteEndpoint.address ().is_v4 ();
- if ((isV4 && i2p::context.GetStatus () == eRouterStatusOK) ||
- (!isV4 && i2p::context.GetStatusV6 () == eRouterStatusOK)) // we don't need relays
- {
- // tell out peer to now assign relay tag
- flag = SSU_HEADER_EXTENDED_OPTIONS_INCLUDED;
- *payload = 2; payload++; // 1 byte length
- uint16_t flags = 0; // clear EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG
- htobe16buf (payload, flags);
- payload += 2;
- }
- // fill payload
- memcpy (payload, m_DHKeysPair->GetPublicKey (), 256); // x
- if (isV4)
- {
- payload[256] = 4;
- memcpy (payload + 257, m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data(), 4);
- }
- else
- {
- payload[256] = 16;
- memcpy (payload + 257, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16);
- }
- // encrypt and send
- uint8_t iv[16];
- RAND_bytes (iv, 16); // random iv
- FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, isV4 ? 304 : 320, m_IntroKey, iv, m_IntroKey, flag);
- m_Server.Send (buf, isV4 ? 304 : 320, m_RemoteEndpoint);
- }
-
- void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce)
- {
- auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () :
- i2p::context.GetRouterInfo ().GetSSUAddress (true);
- if (!address)
- {
- LogPrint (eLogInfo, "SSU: SSU is not supported");
- return;
- }
-
- uint8_t buf[96 + 18] = {0};
- uint8_t * payload = buf + sizeof (SSUHeader);
- htobe32buf (payload, introducer.iTag);
- payload += 4;
- *payload = 0; // no address
- payload++;
- htobuf16(payload, 0); // port = 0
- payload += 2;
- *payload = 0; // challenge
- payload++;
- memcpy (payload, (const uint8_t *)address->i, 32);
- payload += 32;
- htobe32buf (payload, nonce); // nonce
-
- uint8_t iv[16];
- RAND_bytes (iv, 16); // random iv
- if (m_State == eSessionStateEstablished)
- FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, m_SessionKey, iv, m_MacKey);
- else
- FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey);
- m_Server.Send (buf, 96, m_RemoteEndpoint);
- LogPrint (eLogDebug, "SSU: Relay request sent");
- }
-
- void SSUSession::SendSessionCreated (const uint8_t * x, bool sendRelayTag)
- {
- auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () :
- i2p::context.GetRouterInfo ().GetSSUAddress (true); //v4 only
- if (!address)
- {
- LogPrint (eLogInfo, "SSU: SSU is not supported");
- return;
- }
- SignedData s; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time
- s.Insert (x, 256); // x
-
- uint8_t buf[384 + 18] = {0};
- uint8_t * payload = buf + sizeof (SSUHeader);
- memcpy (payload, m_DHKeysPair->GetPublicKey (), 256);
- s.Insert (payload, 256); // y
- payload += 256;
- if (m_RemoteEndpoint.address ().is_v4 ())
- {
- // ipv4
- *payload = 4;
- payload++;
- memcpy (payload, m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data(), 4);
- s.Insert (payload, 4); // remote endpoint IP V4
- payload += 4;
- }
- else
- {
- // ipv6
- *payload = 16;
- payload++;
- memcpy (payload, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16);
- s.Insert (payload, 16); // remote endpoint IP V6
- payload += 16;
- }
- htobe16buf (payload, m_RemoteEndpoint.port ());
- s.Insert (payload, 2); // remote port
- payload += 2;
- if (address->host.is_v4 ())
- s.Insert (address->host.to_v4 ().to_bytes ().data (), 4); // our IP V4
- else
- s.Insert (address->host.to_v6 ().to_bytes ().data (), 16); // our IP V6
- s.Insert<uint16_t> (htobe16 (address->port)); // our port
- if (sendRelayTag && i2p::context.GetRouterInfo ().IsIntroducer (!IsV6 ()))
- {
- RAND_bytes((uint8_t *)&m_SentRelayTag, 4);
- if (!m_SentRelayTag) m_SentRelayTag = 1;
- }
- htobe32buf (payload, m_SentRelayTag);
- payload += 4; // relay tag
- htobe32buf (payload, i2p::util::GetSecondsSinceEpoch ()); // signed on time
- payload += 4;
- s.Insert (payload - 8, 4); // relayTag
- // we have to store this signed data for session confirmed
- // same data but signed on time, it will Alice's there
- m_SignedData = std::unique_ptr<SignedData>(new SignedData (s));
- s.Insert (payload - 4, 4); // BOB's signed on time
- s.Sign (i2p::context.GetPrivateKeys (), payload); // DSA signature
-
- uint8_t iv[16];
- RAND_bytes (iv, 16); // random iv
- // encrypt signature and padding with newly created session key
- size_t signatureLen = i2p::context.GetIdentity ()->GetSignatureLen ();
- size_t paddingSize = signatureLen & 0x0F; // %16
- if (paddingSize > 0)
- {
- // fill random padding
- RAND_bytes(payload + signatureLen, (16 - paddingSize));
- signatureLen += (16 - paddingSize);
- }
- m_SessionKeyEncryption.SetIV (iv);
- m_SessionKeyEncryption.Encrypt (payload, signatureLen, payload);
- payload += signatureLen;
- size_t msgLen = payload - buf;
-
- // encrypt message with intro key
- FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, msgLen, m_IntroKey, iv, m_IntroKey);
- Send (buf, msgLen);
- }
-
- void SSUSession::SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, size_t ourAddressLen)
- {
- uint8_t buf[512 + 18] = {0};
- uint8_t * payload = buf + sizeof (SSUHeader);
- *payload = 1; // 1 fragment
- payload++; // info
- size_t identLen = i2p::context.GetIdentity ()->GetFullLen (); // 387+ bytes
- htobe16buf (payload, identLen);
- payload += 2; // cursize
- i2p::context.GetIdentity ()->ToBuffer (payload, identLen);
- payload += identLen;
- uint32_t signedOnTime = i2p::util::GetSecondsSinceEpoch ();
- htobe32buf (payload, signedOnTime); // signed on time
- payload += 4;
- auto signatureLen = i2p::context.GetIdentity ()->GetSignatureLen ();
- size_t paddingSize = ((payload - buf) + signatureLen)%16;
- if (paddingSize > 0) paddingSize = 16 - paddingSize;
- RAND_bytes(payload, paddingSize); // fill padding with random
- payload += paddingSize; // padding size
- // signature
- SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, our signed on time
- s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x
- s.Insert (y, 256); // y
- s.Insert (ourAddress, ourAddressLen); // our address/port as seem by party
- if (m_RemoteEndpoint.address ().is_v4 ())
- s.Insert (m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data (), 4); // remote IP V4
- else
- s.Insert (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), 16); // remote IP V6
- s.Insert<uint16_t> (htobe16 (m_RemoteEndpoint.port ())); // remote port
- s.Insert (htobe32 (m_RelayTag)); // relay tag
- s.Insert (htobe32 (signedOnTime)); // signed on time
- s.Sign (i2p::context.GetPrivateKeys (), payload); // DSA signature
- payload += signatureLen;
-
- size_t msgLen = payload - buf;
- uint8_t iv[16];
- RAND_bytes (iv, 16); // random iv
- // encrypt message with session key
- FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CONFIRMED, buf, msgLen, m_SessionKey, iv, m_MacKey);
- Send (buf, msgLen);
- }
-
- void SSUSession::ProcessRelayRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from)
- {
- uint32_t relayTag = bufbe32toh (buf);
- auto session = m_Server.FindRelaySession (relayTag);
- if (session)
- {
- buf += 4; // relay tag
- uint8_t size = *buf;
- buf++; // size
- buf += size; // address
- buf += 2; // port
- uint8_t challengeSize = *buf;
- buf++; // challenge size
- buf += challengeSize;
- const uint8_t * introKey = buf;
- buf += 32; // introkey
- uint32_t nonce = bufbe32toh (buf);
- SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint);
- SendRelayIntro (session, from);
- }
- }
-
- void SSUSession::SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from,
- const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to)
- {
- bool isV4 = to.address ().is_v4 (); // Charle's
- bool isV4A = from.address ().is_v4 (); // Alice's
- if ((isV4 && !isV4A) || (!isV4 && isV4A))
- {
- LogPrint (eLogWarning, "SSU: Charlie's IP and Alice's IP belong to different networks for relay response");
- return;
- }
- uint8_t buf[80 + 18] = {0}; // 64 for ipv4 and 80 for ipv6
- uint8_t * payload = buf + sizeof (SSUHeader);
- // Charlie
- if (isV4)
- {
- *payload = 4;
- payload++; // size
- memcpy (payload, to.address ().to_v4 ().to_bytes ().data (), 4); // Charlie's IP V4
- payload += 4; // address
- }
- else
- {
- *payload = 16;
- payload++; // size
- memcpy (payload, to.address ().to_v6 ().to_bytes ().data (), 16); // Charlie's IP V6
- payload += 16; // address
- }
- htobe16buf (payload, to.port ()); // Charlie's port
- payload += 2; // port
- // Alice
- if (isV4)
- {
- *payload = 4;
- payload++; // size
- memcpy (payload, from.address ().to_v4 ().to_bytes ().data (), 4); // Alice's IP V4
- payload += 4; // address
- }
- else
- {
- *payload = 16;
- payload++; // size
- memcpy (payload, from.address ().to_v6 ().to_bytes ().data (), 16); // Alice's IP V6
- payload += 16; // address
- }
- htobe16buf (payload, from.port ()); // Alice's port
- payload += 2; // port
- htobe32buf (payload, nonce);
-
- if (m_State == eSessionStateEstablished)
- {
- // encrypt with session key
- FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80);
- Send (buf, isV4 ? 64 : 80);
- }
- else
- {
- // ecrypt with Alice's intro key
- uint8_t iv[16];
- RAND_bytes (iv, 16); // random iv
- FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80, introKey, iv, introKey);
- m_Server.Send (buf, isV4 ? 64 : 80, from);
- }
- LogPrint (eLogDebug, "SSU: Relay response sent");
- }
-
- void SSUSession::SendRelayIntro (std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint& from)
- {
- if (!session) return;
- bool isV4 = from.address ().is_v4 (); // Alice's
- bool isV4C = session->m_RemoteEndpoint.address ().is_v4 (); // Charlie's
- if ((isV4 && !isV4C) || (!isV4 && isV4C))
- {
- LogPrint (eLogWarning, "SSU: Charlie's IP and Alice's IP belong to different networks for relay intro");
- return;
- }
- uint8_t buf[64 + 18] = {0}; // 48 for ipv4 and 64 for ipv6
- uint8_t * payload = buf + sizeof (SSUHeader);
- if (isV4)
- {
- *payload = 4;
- payload++; // size
- memcpy (payload, from.address ().to_v4 ().to_bytes ().data (), 4); // Alice's IP V4
- payload += 4; // address
- }
- else
- {
- *payload = 16;
- payload++; // size
- memcpy (payload, from.address ().to_v6 ().to_bytes ().data (), 16); // Alice's IP V6
- payload += 16; // address
- }
- htobe16buf (payload, from.port ()); // Alice's port
- payload += 2; // port
- *payload = 0; // challenge size
- uint8_t iv[16];
- RAND_bytes (iv, 16); // random iv
- FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_INTRO, buf, isV4 ? 48 : 64, session->m_SessionKey, iv, session->m_MacKey);
- m_Server.Send (buf, isV4 ? 48 : 64, session->m_RemoteEndpoint);
- LogPrint (eLogDebug, "SSU: Relay intro sent");
- }
-
- void SSUSession::ProcessRelayResponse (const uint8_t * buf, size_t len)
- {
- LogPrint (eLogDebug, "SSU message: Relay response received");
- boost::asio::ip::address remoteIP;
- uint16_t remotePort = 0;
- auto remoteSize = ExtractIPAddressAndPort (buf, len, remoteIP, remotePort);
- if (!remoteSize) return;
- buf += remoteSize; len -= remoteSize;
- boost::asio::ip::address ourIP;
- uint16_t ourPort = 0;
- auto ourSize = ExtractIPAddressAndPort (buf, len, ourIP, ourPort);
- if (!ourSize) return;
- buf += ourSize; len -= ourSize;
- LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort);
- if (!i2p::util::net::IsInReservedRange (ourIP))
- i2p::context.UpdateAddress (ourIP);
- else
- LogPrint (eLogError, "SSU: External address ", ourIP.to_string (), " is in reserved range");
- if (ourIP.is_v4 ())
- {
- if (ourPort != m_Server.GetPort ())
- {
- if (i2p::context.GetStatus () == eRouterStatusTesting)
- i2p::context.SetError (eRouterErrorSymmetricNAT);
- }
- else if (i2p::context.GetStatus () == eRouterStatusError && i2p::context.GetError () == eRouterErrorSymmetricNAT)
- i2p::context.SetStatus (eRouterStatusTesting);
- }
- uint32_t nonce = bufbe32toh (buf);
- buf += 4; // nonce
- auto it = m_RelayRequests.find (nonce);
- if (it != m_RelayRequests.end ())
- {
- // check if we are waiting for introduction
- boost::asio::ip::udp::endpoint remoteEndpoint (remoteIP, remotePort);
- if (!m_Server.FindSession (remoteEndpoint))
- {
- // we didn't have correct endpoint when sent relay request
- // now we do
- LogPrint (eLogInfo, "SSU: RelayReponse connecting to endpoint ", remoteEndpoint);
- if ((remoteIP.is_v4 () && i2p::context.GetStatus () == eRouterStatusFirewalled) ||
- (remoteIP.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled))
- m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch
- // we assume that HolePunch has been sent by this time and our SessionRequest will go through
- m_Server.CreateDirectSession (it->second.first, remoteEndpoint, false);
- }
- // delete request
- m_RelayRequests.erase (it);
- // cancel connect timer
- m_ConnectTimer.cancel ();
- }
- else
- LogPrint (eLogError, "SSU: Unsolicited RelayResponse, nonce=", nonce);
- }
-
- void SSUSession::ProcessRelayIntro (const uint8_t * buf, size_t len)
- {
- boost::asio::ip::address ip;
- uint16_t port = 0;
- ExtractIPAddressAndPort (buf, len, ip, port);
- if (!ip.is_unspecified () && port)
- // send hole punch of 0 bytes
- m_Server.Send (buf, 0, boost::asio::ip::udp::endpoint (ip, port));
- }
-
- void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len,
- const i2p::crypto::AESKey& aesKey, const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag)
- {
- if (len < sizeof (SSUHeader))
- {
- LogPrint (eLogError, "SSU: Unexpected packet length ", len);
- return;
- }
- SSUHeader * header = (SSUHeader *)buf;
- memcpy (header->iv, iv, 16);
- header->flag = flag | (payloadType << 4); // MSB is 0
- htobe32buf (header->time, i2p::util::GetSecondsSinceEpoch ());
- uint8_t * encrypted = &header->flag;
- uint16_t encryptedLen = len - (encrypted - buf);
- i2p::crypto::CBCEncryption encryption;
- encryption.SetKey (aesKey);
- encryption.SetIV (iv);
- encryption.Encrypt (encrypted, encryptedLen, encrypted);
- // assume actual buffer size is 18 (16 + 2) bytes more
- memcpy (buf + len, iv, 16);
- uint16_t netid = i2p::context.GetNetID ();
- htobe16buf (buf + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8));
- i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, header->mac);
- }
-
- void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len)
- {
- FillHeaderAndEncrypt (payloadType, buf, len, buf);
- }
-
- void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * in, size_t len, uint8_t * out)
- {
- if (len < sizeof (SSUHeader))
- {
- LogPrint (eLogError, "SSU: Unexpected packet length ", len);
- return;
- }
- SSUHeader * header = (SSUHeader *)out;
- RAND_bytes (header->iv, 16); // random iv
- m_SessionKeyEncryption.SetIV (header->iv);
- SSUHeader * inHeader = (SSUHeader *)in;
- inHeader->flag = payloadType << 4; // MSB is 0
- htobe32buf (inHeader->time, i2p::util::GetSecondsSinceEpoch ());
- uint8_t * encrypted = &header->flag, * clear = &inHeader->flag;
- uint16_t encryptedLen = len - (encrypted - out);
- m_SessionKeyEncryption.Encrypt (clear, encryptedLen, encrypted);
- // assume actual out buffer size is 18 (16 + 2) bytes more
- memcpy (out + len, header->iv, 16);
- uint16_t netid = i2p::context.GetNetID ();
- htobe16buf (out + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8));
- i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac);
- }
-
- void SSUSession::Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey)
- {
- if (len < sizeof (SSUHeader))
- {
- LogPrint (eLogError, "SSU: Unexpected packet length ", len);
- return;
- }
- SSUHeader * header = (SSUHeader *)buf;
- uint8_t * encrypted = &header->flag;
- uint16_t encryptedLen = len - (encrypted - buf);
- i2p::crypto::CBCDecryption decryption;
- decryption.SetKey (aesKey);
- decryption.SetIV (header->iv);
- decryption.Decrypt (encrypted, encryptedLen, encrypted);
- }
-
- void SSUSession::DecryptSessionKey (uint8_t * buf, size_t len)
- {
- if (len < sizeof (SSUHeader))
- {
- LogPrint (eLogError, "SSU: Unexpected packet length ", len);
- return;
- }
- SSUHeader * header = (SSUHeader *)buf;
- uint8_t * encrypted = &header->flag;
- uint16_t encryptedLen = len - (encrypted - buf);
- if (encryptedLen > 0)
- {
- m_SessionKeyDecryption.SetIV (header->iv);
- m_SessionKeyDecryption.Decrypt (encrypted, encryptedLen, encrypted);
- }
- }
-
- bool SSUSession::Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey)
- {
- if (len < sizeof (SSUHeader))
- {
- LogPrint (eLogError, "SSU: Unexpected packet length ", len);
- return false;
- }
- SSUHeader * header = (SSUHeader *)buf;
- uint8_t * encrypted = &header->flag;
- uint16_t encryptedLen = len - (encrypted - buf);
- // assume actual buffer size is 18 (16 + 2) bytes more
- memcpy (buf + len, header->iv, 16);
- uint16_t netid = i2p::context.GetNetID ();
- htobe16buf (buf + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8));
- uint8_t digest[16];
- i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, digest);
- return !memcmp (header->mac, digest, 16);
- }
-
- void SSUSession::Connect ()
- {
- if (m_State == eSessionStateUnknown)
- {
- ScheduleConnectTimer (); // set connect timer
- m_DHKeysPair = std::make_shared<i2p::crypto::DHKeys> ();
- m_DHKeysPair->GenerateKeys ();
- SendSessionRequest ();
- }
- }
-
- void SSUSession::WaitForConnect ()
- {
- if (!IsOutgoing ()) // incoming session
- ScheduleConnectTimer ();
- else
- LogPrint (eLogError, "SSU: Wait for connect for outgoing session");
- }
-
- void SSUSession::ScheduleConnectTimer ()
- {
- m_ConnectTimer.cancel ();
- m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
- m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
- shared_from_this (), std::placeholders::_1));
-}
-
- void SSUSession::HandleConnectTimer (const boost::system::error_code& ecode)
- {
- if (!ecode)
- {
- // timeout expired
- LogPrint (eLogWarning, "SSU: Session with ", m_RemoteEndpoint, " was not established after ", SSU_CONNECT_TIMEOUT, " seconds");
- Failed ();
- }
- }
-
- void SSUSession::Introduce (const i2p::data::RouterInfo::Introducer& introducer,
- std::shared_ptr<const i2p::data::RouterInfo> to)
- {
- if (m_State == eSessionStateUnknown)
- {
- // set connect timer
- m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
- m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
- shared_from_this (), std::placeholders::_1));
- }
- uint32_t nonce;
- RAND_bytes ((uint8_t *)&nonce, 4);
- auto ts = i2p::util::GetSecondsSinceEpoch ();
- m_RelayRequests.emplace (nonce, std::make_pair (to, ts));
- SendRelayRequest (introducer, nonce);
- }
-
- void SSUSession::WaitForIntroduction ()
- {
- m_State = eSessionStateIntroduced;
- // set connect timer
- m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
- m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
- shared_from_this (), std::placeholders::_1));
- }
-
- void SSUSession::Close ()
- {
- SendSessionDestroyed ();
- Reset ();
- m_State = eSessionStateClosed;
- }
-
- void SSUSession::Reset ()
- {
- m_State = eSessionStateUnknown;
- transports.PeerDisconnected (shared_from_this ());
- m_Data.Stop ();
- m_ConnectTimer.cancel ();
- if (m_SentRelayTag)
- {
- m_Server.RemoveRelay (m_SentRelayTag); // relay tag is not valid anymore
- m_SentRelayTag = 0;
- }
- m_DHKeysPair = nullptr;
- m_SignedData = nullptr;
- m_IsSessionKey = false;
- }
-
- void SSUSession::Done ()
- {
- GetService ().post (std::bind (&SSUSession::Failed, shared_from_this ()));
- }
-
- void SSUSession::Established ()
- {
- m_State = eSessionStateEstablished;
- m_DHKeysPair = nullptr;
- m_SignedData = nullptr;
- m_Data.Start ();
- transports.PeerConnected (shared_from_this ());
- if (m_IsPeerTest)
- SendPeerTest ();
- if (m_SentRelayTag)
- m_Server.AddRelay (m_SentRelayTag, shared_from_this ());
- m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
- }
-
- void SSUSession::Failed ()
- {
- if (m_State != eSessionStateFailed)
- {
- m_State = eSessionStateFailed;
- m_Server.DeleteSession (shared_from_this ());
- }
- }
-
- void SSUSession::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
- {
- GetService ().post (std::bind (&SSUSession::PostI2NPMessages, shared_from_this (), msgs));
- }
-
- void SSUSession::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
- {
- if (m_State == eSessionStateEstablished)
- {
- for (const auto& it: msgs)
- if (it)
- {
- if (it->GetLength () <= SSU_MAX_I2NP_MESSAGE_SIZE)
- m_Data.Send (it);
- else
- LogPrint (eLogError, "SSU: I2NP message of size ", it->GetLength (), " can't be sent. Dropped");
- }
- }
- }
-
- void SSUSession::ProcessData (uint8_t * buf, size_t len)
- {
- m_Data.ProcessMessage (buf, len);
- m_IsDataReceived = true;
- }
-
- void SSUSession::FlushData ()
- {
- if (m_IsDataReceived)
- {
- m_Data.FlushReceivedMessage ();
- m_IsDataReceived = false;
- }
- }
-
- void SSUSession::CleanUp (uint64_t ts)
- {
- m_Data.CleanUp (ts);
- for (auto it = m_RelayRequests.begin (); it != m_RelayRequests.end ();)
- {
- if (ts > it->second.second + SSU_CONNECT_TIMEOUT)
- it = m_RelayRequests.erase (it);
- else
- ++it;
- }
- }
-
- void SSUSession::ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
- {
- uint32_t nonce = bufbe32toh (buf); // 4 bytes
- boost::asio::ip::address addr; // Alice's address
- uint16_t port = 0; // and port
- auto size = ExtractIPAddressAndPort (buf + 4, len - 4, addr, port);
- if (port && (size != 7) && (size != 19))
- {
- LogPrint (eLogWarning, "SSU: Address of ", size - 3, " bytes not supported");
- return;
- }
- const uint8_t * introKey = buf + 4 + size;
- switch (m_Server.GetPeerTestParticipant (nonce))
- {
- // existing test
- case ePeerTestParticipantAlice1:
- {
- if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob
- {
- LogPrint (eLogDebug, "SSU: Peer test from Bob. We are Alice");
- if (IsV6 ())
- {
- if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
- {
- i2p::context.SetStatusV6 (eRouterStatusFirewalled);
- m_Server.RescheduleIntroducersUpdateTimerV6 ();
- }
- }
- else if (i2p::context.GetStatus () == eRouterStatusTesting) // still not OK
- {
- i2p::context.SetStatus (eRouterStatusFirewalled);
- m_Server.RescheduleIntroducersUpdateTimer ();
- }
- }
- else
- {
- LogPrint (eLogDebug, "SSU: First peer test from Charlie. We are Alice");
- if (m_State == eSessionStateEstablished)
- LogPrint (eLogWarning, "SSU: First peer test from Charlie through established session. We are Alice");
- if (IsV6 ())
- i2p::context.SetStatusV6 (eRouterStatusOK);
- else
- i2p::context.SetStatus (eRouterStatusOK);
- m_Server.UpdatePeerTest (nonce, ePeerTestParticipantAlice2);
- SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, true, false); // to Charlie
- }
- break;
- }
- case ePeerTestParticipantAlice2:
- {
- if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob
- LogPrint (eLogDebug, "SSU: Peer test from Bob. We are Alice");
- else
- {
- // peer test successive
- LogPrint (eLogDebug, "SSU: Second peer test from Charlie. We are Alice");
- if (IsV6 ())
- i2p::context.SetStatusV6 (eRouterStatusOK);
- else
- i2p::context.SetStatus (eRouterStatusOK);
- m_Server.RemovePeerTest (nonce);
- }
- break;
- }
- case ePeerTestParticipantBob:
- {
- LogPrint (eLogDebug, "SSU: Peer test from Charlie. We are Bob");
- auto session = m_Server.GetPeerTestSession (nonce); // session with Alice from PeerTest
- if (session && session->m_State == eSessionStateEstablished)
- {
- const auto& ep = session->GetRemoteEndpoint (); // Alice's endpoint as known to Bob
- session->SendPeerTest (nonce, ep.address (), ep.port (), introKey, false, true); // send back to Alice
- }
- m_Server.RemovePeerTest (nonce); // nonce has been used
- break;
- }
- case ePeerTestParticipantCharlie:
- {
- LogPrint (eLogDebug, "SSU: Peer test from Alice. We are Charlie");
- SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey); // to Alice with her actual address
- m_Server.RemovePeerTest (nonce); // nonce has been used
- break;
- }
- // test not found
- case ePeerTestParticipantUnknown:
- {
- if (m_State == eSessionStateEstablished)
- {
- // new test
- if (port)
- {
- LogPrint (eLogDebug, "SSU: Peer test from Bob. We are Charlie");
- Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Bob
- if (!addr.is_unspecified () && !i2p::util::net::IsInReservedRange(addr))
- {
- m_Server.NewPeerTest (nonce, ePeerTestParticipantCharlie);
- SendPeerTest (nonce, addr, port, introKey); // to Alice with her address received from Bob
- }
- }
- else
- {
- LogPrint (eLogDebug, "SSU: Peer test from Alice. We are Bob");
- auto session = senderEndpoint.address ().is_v4 () ? m_Server.GetRandomEstablishedV4Session (shared_from_this ()) : m_Server.GetRandomEstablishedV6Session (shared_from_this ()); // Charlie
- if (session)
- {
- m_Server.NewPeerTest (nonce, ePeerTestParticipantBob, shared_from_this ());
- session->SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, false); // to Charlie with Alice's actual address
- }
- }
- }
- else
- LogPrint (eLogError, "SSU: Unexpected peer test");
- }
- }
- }
-
- void SSUSession::SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port,
- const uint8_t * introKey, bool toAddress, bool sendAddress)
- // toAddress is true for Alice<->Chalie communications only
- // sendAddress is false if message comes from Alice
- {
- uint8_t buf[80 + 18] = {0};
- uint8_t iv[16];
- uint8_t * payload = buf + sizeof (SSUHeader);
- htobe32buf (payload, nonce);
- payload += 4; // nonce
- // address and port
- if (sendAddress)
- {
- if (address.is_v4 ())
- {
- *payload = 4;
- memcpy (payload + 1, address.to_v4 ().to_bytes ().data (), 4); // our IP V4
- }
- else if (address.is_v6 ())
- {
- *payload = 16;
- memcpy (payload + 1, address.to_v6 ().to_bytes ().data (), 16); // our IP V6
- }
- else
- *payload = 0;
- payload += (payload[0] + 1);
- }
- else
- {
- *payload = 0;
- payload++; //size
- }
- htobe16buf (payload, port);
- payload += 2; // port
- // intro key
- if (toAddress)
- {
- // send our intro key to address instead of its own
- auto addr = address.is_v4 () ? i2p::context.GetRouterInfo ().GetSSUAddress (true) : // ipv4
- i2p::context.GetRouterInfo ().GetSSUV6Address ();
- if (addr)
- memcpy (payload, addr->i, 32); // intro key
- else
- LogPrint (eLogInfo, "SSU: SSU is not supported. Can't send peer test");
- }
- else
- memcpy (payload, introKey, 32); // intro key
-
- // send
- RAND_bytes (iv, 16); // random iv
- if (toAddress)
- {
- // encrypt message with specified intro key
- FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80, introKey, iv, introKey);
- boost::asio::ip::udp::endpoint e (address, port);
- m_Server.Send (buf, 80, e);
- }
- else
- {
- // encrypt message with session key
- FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80);
- Send (buf, 80);
- }
- }
-
- void SSUSession::SendPeerTest ()
- {
- // we are Alice
- LogPrint (eLogDebug, "SSU: Sending peer test");
- auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () : i2p::context.GetRouterInfo ().GetSSUAddress (true);
- if (!address)
- {
- LogPrint (eLogInfo, "SSU: SSU is not supported. Can't send peer test");
- return;
- }
- uint32_t nonce;
- RAND_bytes ((uint8_t *)&nonce, 4);
- if (!nonce) nonce = 1;
- m_IsPeerTest = false;
- m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1, shared_from_this ());
- SendPeerTest (nonce, boost::asio::ip::address(), 0, address->i, false, false); // address and port always zero for Alice
- }
-
- void SSUSession::SendKeepAlive ()
- {
- if (m_State == eSessionStateEstablished)
- {
- uint8_t buf[48 + 18] = {0};
- uint8_t * payload = buf + sizeof (SSUHeader);
- *payload = 0; // flags
- payload++;
- *payload = 0; // num fragments
- // encrypt message with session key
- FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
- Send (buf, 48);
- LogPrint (eLogDebug, "SSU: keep-alive sent");
- m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
- }
- }
-
- void SSUSession::SendSessionDestroyed ()
- {
- if (m_IsSessionKey)
- {
- uint8_t buf[48 + 18] = {0};
- // encrypt message with session key
- FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48);
- try
- {
- Send (buf, 48);
- }
- catch (std::exception& ex)
- {
- LogPrint (eLogWarning, "SSU: Exception while sending session destoroyed: ", ex.what ());
- }
- LogPrint (eLogDebug, "SSU: Session destroyed sent");
- }
- }
-
- void SSUSession::Send (uint8_t type, const uint8_t * payload, size_t len)
- {
- uint8_t buf[SSU_MTU_V4 + 18] = {0};
- size_t msgSize = len + sizeof (SSUHeader);
- size_t paddingSize = msgSize & 0x0F; // %16
- if (paddingSize > 0) msgSize += (16 - paddingSize);
- if (msgSize > SSU_MTU_V4)
- {
- LogPrint (eLogWarning, "SSU: Payload size ", msgSize, " exceeds MTU");
- return;
- }
- memcpy (buf + sizeof (SSUHeader), payload, len);
- // encrypt message with session key
- FillHeaderAndEncrypt (type, buf, msgSize);
- Send (buf, msgSize);
- }
-
- void SSUSession::Send (const uint8_t * buf, size_t size)
- {
- m_NumSentBytes += size;
- i2p::transport::transports.UpdateSentBytes (size);
- m_Server.Send (buf, size, m_RemoteEndpoint);
- }
-
- size_t SSUSession::ExtractIPAddressAndPort (const uint8_t * buf, size_t len, boost::asio::ip::address& ip, uint16_t& port)
- {
- if (!len) return 0;
- uint8_t size = *buf;
- size_t s = 1 + size + 2; // size + address + port
- if (len < s)
- {
- LogPrint (eLogWarning, "SSU: Address is too short ", len);
- port = 0;
- return len;
- }
- buf++; // size
- if (size == 4)
- {
- boost::asio::ip::address_v4::bytes_type bytes;
- memcpy (bytes.data (), buf, 4);
- ip = boost::asio::ip::address_v4 (bytes);
- }
- else if (size == 16)
- {
- boost::asio::ip::address_v6::bytes_type bytes;
- memcpy (bytes.data (), buf, 16);
- ip = boost::asio::ip::address_v6 (bytes);
- }
- else
- LogPrint (eLogWarning, "SSU: Address size ", int(size), " is not supported");
- buf += size;
- port = bufbe16toh (buf);
- return s;
- }
-}
-}
|
[-]
[+]
|
Deleted |
_service:tar_git:i2pd-2.43.0+git1.tar.gz/upstream/libi2pd/SSUSession.h
^
|
@@ -1,177 +0,0 @@
-/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
-*
-* This file is part of Purple i2pd project and licensed under BSD3
-*
-* See full license text in LICENSE file at top of project tree
-*/
-
-#ifndef SSU_SESSION_H__
-#define SSU_SESSION_H__
-
-#include <inttypes.h>
-#include <set>
-#include <memory>
-#include "Crypto.h"
-#include "I2NPProtocol.h"
-#include "TransportSession.h"
-#include "SSUData.h"
-
-namespace i2p
-{
-namespace transport
-{
- const uint8_t SSU_HEADER_EXTENDED_OPTIONS_INCLUDED = 0x04;
- struct SSUHeader
- {
- uint8_t mac[16];
- uint8_t iv[16];
- uint8_t flag;
- uint8_t time[4];
-
- uint8_t GetPayloadType () const { return flag >> 4; };
- bool IsExtendedOptions () const { return flag & SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; };
- };
-
- const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
- const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
- const int SSU_CLOCK_SKEW = 60; // in seconds
- const int SSU_CLOCK_THRESHOLD = 15; // in seconds, if more we should adjust
- const size_t SSU_MAX_I2NP_MESSAGE_SIZE = 32768;
-
- // payload types (4 bits)
- const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
- const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1;
- const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2;
- const uint8_t PAYLOAD_TYPE_RELAY_REQUEST = 3;
- const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4;
- const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5;
- const uint8_t PAYLOAD_TYPE_DATA = 6;
- const uint8_t PAYLOAD_TYPE_PEER_TEST = 7;
- const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8;
-
- // extended options
- const uint16_t EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG = 0x0001;
-
- enum SessionState
- {
- eSessionStateUnknown,
- eSessionStateIntroduced,
- eSessionStateEstablished,
- eSessionStateClosed,
- eSessionStateFailed
- };
-
- enum PeerTestParticipant
- {
- ePeerTestParticipantUnknown = 0,
- ePeerTestParticipantAlice1,
- ePeerTestParticipantAlice2,
- ePeerTestParticipantBob,
- ePeerTestParticipantCharlie
- };
-
- class SSUServer;
- class SSUSession: public TransportSession, public std::enable_shared_from_this<SSUSession>
- {
- public:
-
- SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
- std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, bool peerTest = false);
- void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
- ~SSUSession ();
-
- void Connect ();
- void WaitForConnect ();
- void Introduce (const i2p::data::RouterInfo::Introducer& introducer,
- std::shared_ptr<const i2p::data::RouterInfo> to); // Alice to Charlie
- void WaitForIntroduction ();
- void Close ();
- void Done ();
- void Failed ();
- const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
- SSUServer& GetServer () { return m_Server; };
-
- bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
- void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
- void SendPeerTest (); // Alice
-
- SessionState GetState () const { return m_State; };
- size_t GetNumSentBytes () const { return m_NumSentBytes; };
- size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
-
- void SendKeepAlive ();
- uint32_t GetRelayTag () const { return m_RelayTag; };
- const i2p::data::RouterInfo::IntroKey& GetIntroKey () const { return m_IntroKey; };
-
- void FlushData ();
- void CleanUp (uint64_t ts);
-
- private:
-
- boost::asio::io_service& GetService ();
- void CreateAESandMacKey (const uint8_t * pubKey);
- size_t GetSSUHeaderSize (const uint8_t * buf) const;
- void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
- void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
- void ProcessSessionRequest (const uint8_t * buf, size_t len);
- void SendSessionRequest ();
- void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce);
- void ProcessSessionCreated (uint8_t * buf, size_t len);
- void SendSessionCreated (const uint8_t * x, bool sendRelayTag = true);
- void ProcessSessionConfirmed (const uint8_t * buf, size_t len);
- void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, size_t ourAddressLen);
- void ProcessRelayRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
- void SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from,
- const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to);
- void SendRelayIntro (std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint& from);
- void ProcessRelayResponse (const uint8_t * buf, size_t len);
- void ProcessRelayIntro (const uint8_t * buf, size_t len);
- void Established ();
- void ScheduleConnectTimer ();
- void HandleConnectTimer (const boost::system::error_code& ecode);
- void ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
- void SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port, const uint8_t * introKey, bool toAddress = true, bool sendAddress = true);
- void ProcessData (uint8_t * buf, size_t len);
- void SendSessionDestroyed ();
- void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key
- void Send (const uint8_t * buf, size_t size);
-
- void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey,
- const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag = 0);
- void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
- void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * in, size_t len, uint8_t * out); // with session key
- void Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey);
- void DecryptSessionKey (uint8_t * buf, size_t len);
- bool Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey);
-
- void Reset ();
-
- static size_t ExtractIPAddressAndPort (const uint8_t * buf, size_t len, boost::asio::ip::address& ip, uint16_t& port); // returns actual buf size
-
- private:
-
- friend class SSUData; // TODO: change in later
- SSUServer& m_Server;
- const boost::asio::ip::udp::endpoint m_RemoteEndpoint;
- boost::asio::deadline_timer m_ConnectTimer;
- bool m_IsPeerTest;
- SessionState m_State;
- bool m_IsSessionKey;
- uint32_t m_RelayTag; // received from peer
- uint32_t m_SentRelayTag; // sent by us
- i2p::crypto::CBCEncryption m_SessionKeyEncryption;
- i2p::crypto::CBCDecryption m_SessionKeyDecryption;
- i2p::crypto::AESKey m_SessionKey;
- i2p::crypto::MACKey m_MacKey;
- i2p::data::RouterInfo::IntroKey m_IntroKey;
- SSUData m_Data;
- bool m_IsDataReceived;
- std::unique_ptr<SignedData> m_SignedData; // we need it for SessionConfirmed only
- std::map<uint32_t, std::pair <std::shared_ptr<const i2p::data::RouterInfo>, uint64_t > > m_RelayRequests; // nonce->(Charlie, timestamp)
- std::shared_ptr<i2p::crypto::DHKeys> m_DHKeysPair; // X - for client and Y - for server
- };
-}
-}
-
-#endif
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/ui/jolla-settings/pages/i2p/EnableSwitch.qml
^
|
@@ -1,9 +1,6 @@
-/*
- * Copyright (c) 2022 Peter G. <sailfish@nephros.org>
- *
- * License: Apache-2.0
- *
- */
+// SPDX-FileCopyrightText: 2022 Peter G. <sailfish@nephros.org>
+//
+// SPDX-License-Identifier: Apache-2.0
import QtQuick 2.1
import Sailfish.Silica 1.0
@@ -14,15 +11,20 @@
SettingsToggle {
id: enableSwitch
- property bool activeState
+ property alias serviceState: unit.activeState
+ property bool activeState: serviceState === "active"
+ property bool inactiveState: !activeState && ((serviceState !== "inactive") && (serviceState !== "failed"))
+ property bool busyState: !activeState && ((serviceState !== "reloading") && (serviceState !== "activating") && (serviceState !== "deactivating"))
+
+ active: activeState
+ checked: activeState
+ busy: busyState
+ enabled: !busy
name: "I2P"
activeText: "I2P"
icon.source: "image://theme/icon-m-i2p"
- active: activeState
- checked: activeState
-
menu: ContextMenu {
SettingsMenuItem { onClicked: enableSwitch.goToSettings() }
MenuItem {
@@ -31,81 +33,20 @@
}
}
- onToggled: {
- if (busy) {
- return
- }
- busy = true
- systemdServiceIface.call(activeState ? "Stop" : "Start", ["replace"])
- systemdServiceIface.updateProperties()
- }
-
- Timer {
- id: checkState
- interval: 2000
- repeat: true
- onTriggered: {
- systemdServiceIface.updateProperties()
- }
- }
+ onToggled: unit.call(activeState ? "Stop" : "Start", ["replace"])
DBusInterface {
- id: systemdServiceIface
+ id: unit
bus: DBus.SystemBus
service: 'org.freedesktop.systemd1'
path: '/org/freedesktop/systemd1/unit/i2pd_2eservice'
iface: 'org.freedesktop.systemd1.Unit'
- signalsEnabled: true
- function updateProperties() {
- var activeProperty = systemdServiceIface.getProperty("ActiveState")
- console.log("ActiveState:", activeProperty)
- if (activeProperty === "active") {
- activeState = true
- checkState.stop()
- }
- else if (activeProperty === "inactive" || activeProperty === "failed") {
- activeState = false
- checkState.stop()
- }
- else {
- enableSwitch.busy = false
- checkState.start()
- }
- }
-
- onPropertiesChanged: updateProperties()
- Component.onCompleted: updateProperties()
- }
-
- DBusInterface {
- bus: DBus.SystemBus
- service: 'org.freedesktop.systemd1'
- path: '/org/freedesktop/systemd1/unit/i2pd'
- iface: 'org.freedesktop.DBus.Properties'
-
- signalsEnabled: true
- onPropertiesChanged: systemdServiceIface.updateProperties()
- Component.onCompleted: systemdServiceIface.updateProperties()
- }
+ property string activeState
+ //property string subState
+ //property string unitFileState
- /*
- DBusInterface {
- bus: DBus.SystemBus
- service: "org.freedesktop.systemd1"
- path: "/org/freedesktop/systemd1"
- iface: "org.freedesktop.systemd1.Manager"
signalsEnabled: true
-
- signal unitNew(string name)
- onUnitNew: {
- if (name == "i2pd.service") {
- systemdServiceIface.updateProperties()
- }
- }
+ propertiesEnabled: true
}
- */
-
- Component.onCompleted: systemdServiceIface.updateProperties()
-
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/ui/jolla-settings/pages/i2p/mainpage.qml
^
|
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2022-2024 Peter G. <sailfish@nephros.org>
+//
+// SPDX-License-Identifier: Apache-2.0
+
import QtQuick 2.1
import Sailfish.Silica 1.0
import com.jolla.settings 1.0
@@ -7,28 +11,24 @@
Page {
id: page
- property bool activeState
- //property bool enabledState
+ property alias serviceState: unit.activeState
+ property bool activeState: serviceState === "active"
+ property bool inactiveState: !activeState && ((serviceState !== "inactive") && (serviceState !== "failed"))
+ property bool busyState: !activeState && ((serviceState !== "reloading") && (serviceState !== "activating") && (serviceState !== "deactivating"))
+
+ property bool enabledState: ((unit.unitFileState === "enabled-runtime") || (unit.unitFileState === "enabled"))
+ property bool disabledState: (unit.unitFileState === "disabled")
+
onActiveStateChanged: {
if (activeState) { daemonInfo.refreshInfo() }
}
Timer {
- id: checkState
- interval: 2000
- repeat: true
- running: Qt.application.state == Qt.ApplicationActive
- onTriggered: {
- systemdServiceIface.updateProperties()
- }
- }
-
- Timer {
id: refreshTimer
interval: 15000
repeat: true
triggeredOnStart: true
- running: activeState && Qt.application.state == Qt.ApplicationActive
+ running: activeState && (Qt.application.state == Qt.ApplicationActive)
onTriggered: {
daemonInfo.refreshInfo()
}
@@ -36,71 +36,34 @@
DBusInterface {
// qdbus --system org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/i2pd_2eservice org.freedesktop.systemd1.Unit.ActiveState
- // valuse: "active", "reloading", "inactive", "failed", "activating", and "deactivating"
- id: systemdServiceIface
+ // values: "active", "reloading", "inactive", "failed", "activating", and "deactivating"
+ id: unit
bus: DBus.SystemBus
service: 'org.freedesktop.systemd1'
path: '/org/freedesktop/systemd1/unit/i2pd_2eservice'
iface: 'org.freedesktop.systemd1.Unit'
- signalsEnabled: true
- function updateProperties() {
- var activeProperty = systemdServiceIface.getProperty("ActiveState")
- //var enabledProperty = systemdServiceIface.getProperty("UnitFileState")
- console.debug("ActiveState:", activeProperty)
- if (activeProperty === "active") {
- activeState = true
- startstopSwitch.busy = false
- }
- else if (activeProperty === "inactive" || activeProperty === "failed") {
- activeState = false
- startstopSwitch.busy = false
- } else {
- startstopSwitch.busy = true
- }
- /*
- if (enabledProperty === "enabled") {
- enabledState = true
- } else {
- enabledState = false
- }
- */
- }
+ property string activeState
+ //property string subState
+ property string unitFileState
- onPropertiesChanged: updateProperties()
- Component.onCompleted: updateProperties()
+ signalsEnabled: true
+ propertiesEnabled: true
}
DBusInterface {
+ // qdbus --system org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/i2pd_2eservice org.freedesktop.systemd1.Unit.ActiveState
+ // values: "active", "reloading", "inactive", "failed", "activating", and "deactivating"
+ id: manager
bus: DBus.SystemBus
service: 'org.freedesktop.systemd1'
path: '/org/freedesktop/systemd1/unit/i2pd_2eservice'
- iface: 'org.freedesktop.DBus.Properties'
+ iface: 'org.freedesktop.systemd1.Manager'
signalsEnabled: true
- onPropertiesChanged: { console.log("updating properties"); systemdServiceIface.updateProperties()}
- Component.onCompleted: systemdServiceIface.updateProperties()
+ propertiesEnabled: true
}
- /*
- DBusInterface {
- id: systemdManagerIface
- bus: DBus.SystemBus
- service: "org.freedesktop.systemd1"
- path: "/org/freedesktop/systemd1"
- iface: "org.freedesktop.systemd1.Manager"
- signalsEnabled: true
-
- signal unitNew(string name)
- onUnitNew: {
- if (name == "i2pd.service") {
- console.debug("A wild unit appeared!", name);
- systemdServiceIface.updateProperties()
- }
- }
- }
- */
-
Component { id: passdialog
Dialog {
property string user
@@ -155,15 +118,13 @@
anchors.fill: parent
contentHeight: column.height
- Column {
- id: column
+ Column { id: column
width: page.width
spacing: Theme.paddingMedium
PageHeader {
title: qsTr("I2P")
- Image {
- id: banner
+ Image { id: banner
anchors.centerIn: parent
height: parent.height
sourceSize.height: height
@@ -173,8 +134,7 @@
}
}
- ListItem {
- id: enableItem
+ ListItem { id: enableItem
contentHeight: startstopSwitch.height
_backgroundColor: "transparent"
@@ -184,47 +144,39 @@
showMenuOnPressAndHold: false
menu: Component { FavoriteMenu { } }
- TextSwitch {
- id: startstopSwitch
+ TextSwitch { id: startstopSwitch
automaticCheck: false
checked: activeState
- text: "I2P Service" + " " + ( activeState ? "active" : "inactive" )
+ busy: inactiveState
+ enabled: !busy
+
+ text: "I2P Service" + " " + unit.activeState
description: activeState ? qsTr("Stopping may take some time.") : ""
- onClicked: {
- if (startstopSwitch.busy) {
- return
- }
- systemdServiceIface.call(activeState ? "Stop" : "Start", ["replace"])
- systemdServiceIface.updateProperties()
- startstopSwitch.busy = true
- }
+ onClicked: unit.call(activeState ? "Stop" : "Start", ["replace"])
}
}
- /*
TextSwitch {
- id: enableSwitch
+ id: enableSwitch
- automaticCheck: false
- checked: enabledState
- text: "Start at boot"
- onClicked: {
- enabledState ?
- systemdManagerIface.typedCall("DisableUnitFiles", [
- { "type": "as", "value": [ "i2pd.service" ]}, // array of service names
- { "type": "b", "value": "false"} // session only?
- ])
- : systemdManagerIface.typedCall("EnableUnitFiles", [
- { "type": "as", "value": [ "i2pd.service" ]}, // array of service names
- { "type": "b", "value": "false"}, // session only?
- { "type": "b", "value": "false"} // force?
- ])
-
- systemdServiceIface.updateProperties()
- }
+ automaticCheck: false
+ checked: enabledState
+ text: "Start at boot"
+ onClicked: {
+ enabledState ?
+ manager.typedCall("DisableUnitFiles", [
+ { "type": "as", "value": [ "i2pd.service" ]}, // array of service names
+ { "type": "b", "value": "false"} // session only?
+ ])
+ : manager.typedCall("EnableUnitFiles", [
+ { "type": "as", "value": [ "i2pd.service" ]}, // array of service names
+ { "type": "b", "value": "false"}, // session only?
+ { "type": "b", "value": "false"} // force?
+ ])
+ }
}
- */
+
Separator { width: parent.width; color: Theme.secondaryColor; anchors.horizontalCenter: parent.horizontalCenter }
Label { id: daemonInfo
width: parent.width - Theme.itemSizeMedium
@@ -302,6 +254,17 @@
xhr.send();
}
}
+ ButtonLayout {
+ Button {
+ text: "Console"
+ onClicked: Qt.openUrlExternally("http://jolla:@127.0.0.1:7070")
+ }
+ Button {
+ text: "Test"
+ onClicked: Qt.openUrlExternally("http://identiguy.i2p/")
+ }
+ }
}
}
}
+// vim: ft=javascript expandtab ts=4 sw=4 st=4
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/.editorconfig
^
|
@@ -0,0 +1,39 @@
+# editorconfig.org
+
+root = true
+
+[*]
+# Unix style files
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[Makefile,Makefile.*]
+indent_style = tab
+indent_size = 4
+
+[*.cmd]
+indent_style = space
+indent_size = 2
+end_of_line = crlf
+
+[*.{h,cpp}]
+indent_style = tab
+indent_size = 4
+
+[*.rc]
+indent_style = space
+indent_size = 4
+
+[*.{md,markdown}]
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = false
+
+[*.yml]
+indent_style = space
+indent_size = 2
+
+[*.patch]
+trim_trailing_whitespace = false
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/.github/workflows/build-deb.yml
^
|
@@ -0,0 +1,39 @@
+name: Build Debian packages
+
+on: [push, pull_request]
+
+jobs:
+ build:
+ name: ${{ matrix.dist }}
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ dist: ['buster', 'bullseye', 'bookworm']
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Build package
+ uses: jtdor/build-deb-action@v1
+ with:
+ docker-image: debian:${{ matrix.dist }}-slim
+ buildpackage-opts: --build=binary --no-sign
+ before-build-hook: debchange --controlmaint --local "+${{ github.sha }}~${{ matrix.dist }}" -b --distribution ${{ matrix.dist }} "CI build"
+ extra-build-deps: devscripts git
+
+ - name: Upload package
+ uses: actions/upload-artifact@v3
+ with:
+ name: i2pd_${{ matrix.dist }}
+ path: debian/artifacts/i2pd_*.deb
+
+ - name: Upload debugging symbols
+ uses: actions/upload-artifact@v3
+ with:
+ name: i2pd-dbgsym_${{ matrix.dist }}
+ path: debian/artifacts/i2pd-dbgsym_*.deb
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/.github/workflows/build-freebsd.yml
^
|
@@ -4,18 +4,29 @@
jobs:
build:
- runs-on: macos-12
+ runs-on: ubuntu-latest
name: with UPnP
+
steps:
- - uses: actions/checkout@v2
+ - name: Checkout
+ uses: actions/checkout@v3
+
- name: Test in FreeBSD
id: test
- uses: vmactions/freebsd-vm@v0.2.0
+ uses: vmactions/freebsd-vm@v1
with:
usesh: true
mem: 2048
- prepare: pkg install -y devel/cmake devel/gmake devel/boost-libs security/openssl net/miniupnpc
+ sync: rsync
+ copyback: true
+ prepare: pkg install -y devel/cmake devel/gmake devel/boost-libs security/openssl net/miniupnpc
run: |
cd build
cmake -DWITH_UPNP=ON -DCMAKE_BUILD_TYPE=Release .
gmake -j2
+
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v3
+ with:
+ name: i2pd-freebsd
+ path: build/i2pd
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/.github/workflows/build-osx.yml
^
|
@@ -6,15 +6,21 @@
build:
name: With USE_UPNP=${{ matrix.with_upnp }}
runs-on: macOS-latest
+
strategy:
fail-fast: true
matrix:
with_upnp: ['yes', 'no']
+
steps:
- - uses: actions/checkout@v2
+ - name: Checkout
+ uses: actions/checkout@v3
+
- name: install packages
run: |
+ find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
brew update
brew install boost miniupnpc openssl@1.1
+
- name: build application
run: make HOMEBREW=1 USE_UPNP=${{ matrix.with_upnp }} PREFIX=$GITHUB_WORKSPACE/output -j3
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/.github/workflows/build-windows-msvc.yml
^
|
@@ -0,0 +1,52 @@
+name: Build on Windows with MSVC
+
+on: [push, pull_request]
+
+jobs:
+ build:
+ name: Build
+ runs-on: windows-latest
+
+ strategy:
+ fail-fast: false
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Build and install zlib
+ run: |
+ powershell -Command "(Invoke-WebRequest -Uri https://raw.githubusercontent.com/r4sas/zlib.install/master/install.bat -OutFile install_zlib.bat)"
+ powershell -Command "(Get-Content install_zlib.bat) | Set-Content install_zlib.bat" # fixing line endings
+ set BUILD_TYPE=Debug
+ ./install_zlib.bat
+ set BUILD_TYPE=Release
+ ./install_zlib.bat
+ del install_zlib.bat
+
+ - name: Install Boost
+ uses: crazy-max/ghaction-chocolatey@v2
+ with:
+ args: install boost-msvc-14.3 --version=1.81.0
+
+ - name: Install OpenSSL
+ uses: crazy-max/ghaction-chocolatey@v2
+ with:
+ args: install openssl
+
+ - name: Configure
+ working-directory: build
+ run: cmake -DWITH_STATIC=ON .
+
+ - name: Build
+ working-directory: build
+ run: cmake --build . --config Debug -- -m
+
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v3
+ with:
+ name: i2pd-msvc
+ path: build/Debug/i2pd.*
+
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/.github/workflows/build-windows.yml
^
|
@@ -8,44 +8,106 @@
jobs:
build:
- name: Building using ${{ matrix.arch }} toolchain
+ name: ${{ matrix.arch }}
runs-on: windows-latest
+
strategy:
- fail-fast: true
+ fail-fast: false
matrix:
include: [
- { msystem: UCRT64, arch: ucrt-x86_64, arch_short: x64-ucrt },
- { msystem: MINGW64, arch: x86_64, arch_short: x64 },
- { msystem: MINGW32, arch: i686, arch_short: x86 }
+ { msystem: UCRT64, arch: ucrt-x86_64, arch_short: x64-ucrt, compiler: gcc },
+ { msystem: CLANG64, arch: clang-x86_64, arch_short: x64-clang, compiler: clang },
+ { msystem: MINGW64, arch: x86_64, arch_short: x64, compiler: gcc },
+ { msystem: MINGW32, arch: i686, arch_short: x86, compiler: gcc }
]
+
steps:
- - uses: actions/checkout@v2
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.msystem }}
- install: base-devel mingw-w64-${{ matrix.arch }}-gcc mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc
+ install: base-devel git mingw-w64-${{ matrix.arch }}-${{ matrix.compiler }} mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc
update: true
+
+ - name: Install additional clang packages
+ if: ${{ matrix.msystem == 'CLANG64' }}
+ run: pacman --noconfirm -S mingw-w64-${{ matrix.arch }}-gcc-compat
+
- name: Build application
run: |
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes -j3
+
- name: Upload artifacts
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: i2pd-${{ matrix.arch_short }}.exe
path: i2pd.exe
+
+ build-cmake:
+ name: CMake ${{ matrix.arch }}
+ runs-on: windows-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include: [
+ { msystem: UCRT64, arch: ucrt-x86_64, arch_short: x64-ucrt, compiler: gcc },
+ { msystem: CLANG64, arch: clang-x86_64, arch_short: x64-clang, compiler: clang },
+ { msystem: MINGW64, arch: x86_64, arch_short: x64, compiler: gcc },
+ { msystem: MINGW32, arch: i686, arch_short: x86, compiler: gcc }
+ ]
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Setup MSYS2
+ uses: msys2/setup-msys2@v2
+ with:
+ msystem: ${{ matrix.msystem }}
+ install: base-devel git mingw-w64-${{ matrix.arch }}-cmake mingw-w64-${{ matrix.arch }}-ninja mingw-w64-${{ matrix.arch }}-${{ matrix.compiler }} mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc
+ update: true
+
+ - name: Build application
+ run: |
+ cd build
+ cmake -DWITH_GIT_VERSION=ON -DWITH_STATIC=ON -DWITH_UPNP=ON -DCMAKE_BUILD_TYPE=Release .
+ cmake --build . -- -j3
+
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v3
+ with:
+ name: i2pd-cmake-${{ matrix.arch_short }}.exe
+ path: build/i2pd.exe
+
build-xp:
- name: Building for Windows XP
+ name: XP
runs-on: windows-latest
+
+ strategy:
+ fail-fast: false
+
steps:
- - uses: actions/checkout@v2
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW32
install: base-devel git mingw-w64-i686-gcc mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-miniupnpc
update: true
+
- name: Build WinXP-capable CRT packages
run: |
git clone https://github.com/msys2/MINGW-packages
@@ -64,12 +126,14 @@
pacman --noconfirm -U mingw-w64-i686-libwinpthread-git-*-any.pkg.tar.zst mingw-w64-i686-winpthreads-git-*-any.pkg.tar.zst
popd
popd
+
- name: Build application
run: |
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes USE_WINXP_FLAGS=yes -j3
+
- name: Upload artifacts
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: i2pd-xp.exe
path: i2pd.exe
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/.github/workflows/build.yml
^
|
@@ -5,84 +5,45 @@
jobs:
build-make:
name: Make with USE_UPNP=${{ matrix.with_upnp }}
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-latest
+
strategy:
fail-fast: true
matrix:
with_upnp: ['yes', 'no']
+
steps:
- - uses: actions/checkout@v2
+ - name: Checkout
+ uses: actions/checkout@v3
+
- name: install packages
run: |
- sudo add-apt-repository ppa:mhier/libboost-latest
sudo apt-get update
- sudo apt-get install build-essential libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev
+ sudo apt-get install build-essential libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev
+
- name: build application
run: make USE_UPNP=${{ matrix.with_upnp }} -j3
+
build-cmake:
name: CMake with -DWITH_UPNP=${{ matrix.with_upnp }}
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-latest
+
strategy:
fail-fast: true
matrix:
with_upnp: ['ON', 'OFF']
+
steps:
- - uses: actions/checkout@v2
+ - name: Checkout
+ uses: actions/checkout@v3
+
- name: install packages
run: |
- sudo add-apt-repository ppa:mhier/libboost-latest
sudo apt-get update
- sudo apt-get install build-essential cmake libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev
+ sudo apt-get install build-essential cmake libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev
+
- name: build application
run: |
cd build
cmake -DWITH_UPNP=${{ matrix.with_upnp }} .
make -j3
- build-deb-stretch:
- name: Build package for stretch
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- with:
- fetch-depth: 0
- - name: change debian changelog
- run: |
- sudo apt-get update
- sudo apt-get install devscripts
- debchange -v "`git describe --tags`-stretch" -b -M --distribution stretch "trunk build"
- - uses: singingwolfboy/build-dpkg-stretch@v1
- id: build
- with:
- args: --unsigned-source --unsigned-changes -b
- - uses: actions/upload-artifact@v1
- with:
- name: ${{ steps.build.outputs.filename }}
- path: ${{ steps.build.outputs.filename }}
- - uses: actions/upload-artifact@v1
- with:
- name: ${{ steps.build.outputs.filename-dbgsym }}
- path: ${{ steps.build.outputs.filename-dbgsym }}
- build-deb-buster:
- name: Build package for buster
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- with:
- fetch-depth: 0
- - name: change debian changelog
- run: |
- sudo apt-get update
- sudo apt-get install devscripts
- debchange -v "`git describe --tags`-buster" -b -M --distribution buster "trunk build"
- - uses: singingwolfboy/build-dpkg-buster@v1
- id: build
- with:
- args: --unsigned-source --unsigned-changes -b
- - uses: actions/upload-artifact@v1
- with:
- name: ${{ steps.build.outputs.filename }}
- path: ${{ steps.build.outputs.filename }}
- - uses: actions/upload-artifact@v1
- with:
- name: ${{ steps.build.outputs.filename-dbgsym }}
- path: ${{ steps.build.outputs.filename-dbgsym }}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/.github/workflows/docker.yml
^
|
@@ -4,67 +4,137 @@
push:
branches:
- openssl
+ - docker
+ paths:
+ - .github/workflows/docker.yml
+ - contrib/docker/**
+ - contrib/certificates/**
+ - daemon/**
+ - i18n/**
+ - libi2pd/**
+ - libi2pd_client/**
+ - Makefile
+ - Makefile.linux
tags:
- '*'
jobs:
- docker:
+ build:
+ name: Building container for ${{ matrix.platform }}
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
+ strategy:
+ matrix:
+ include: [
+ { platform: 'linux/amd64', archname: 'amd64' },
+ { platform: 'linux/386', archname: 'i386' },
+ { platform: 'linux/arm64', archname: 'arm64' },
+ { platform: 'linux/arm/v7', archname: 'armv7' },
+ ]
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v2
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
+ - name: Login to DockerHub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Login to GitHub Container registry
+ uses: docker/login-action@v2
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Build container for ${{ matrix.archname }}
+ uses: docker/build-push-action@v3
+ with:
+ context: ./contrib/docker
+ file: ./contrib/docker/Dockerfile
+ platforms: ${{ matrix.platform }}
+ push: true
+ tags: |
+ purplei2p/i2pd:latest-${{ matrix.archname }}
+ ghcr.io/purplei2p/i2pd:latest-${{ matrix.archname }}
+ provenance: false
+
+ push:
+ name: Pushing merged manifest
+ runs-on: ubuntu-latest
+
+ permissions:
+ packages: write
+ contents: read
+
+ needs: build
+
steps:
- - name: Checkout
- uses: actions/checkout@v2
+ - name: Checkout
+ uses: actions/checkout@v3
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v1
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v2
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v1
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
- - name: Login to DockerHub
- uses: docker/login-action@v1
- with:
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Login to GitHub Container registry
- uses: docker/login-action@v1
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Build and push trunk container
- if: ${{ !startsWith(github.ref, 'refs/tags/') }}
- uses: docker/build-push-action@v2
- with:
- context: ./contrib/docker
- file: ./contrib/docker/Dockerfile
- platforms: linux/amd64,linux/386,linux/arm64,linux/arm/v7
- push: true
- tags: |
- purplei2p/i2pd:latest
- ghcr.io/purplei2p/i2pd:latest
-
- - name: Set env
- if: ${{ startsWith(github.ref, 'refs/tags/') }}
- run: echo "RELEASE_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV
-
- - name: Build and push release container
- if: ${{ startsWith(github.ref, 'refs/tags/') }}
- uses: docker/build-push-action@v2
- with:
- context: ./contrib/docker
- file: ./contrib/docker/Dockerfile
- platforms: linux/amd64,linux/386,linux/arm64,linux/arm/v7
- push: true
- tags: |
- purplei2p/i2pd:latest
- purplei2p/i2pd:latest-release
- purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
- ghcr.io/purplei2p/i2pd:latest
- ghcr.io/purplei2p/i2pd:latest-release
- ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
+ - name: Login to DockerHub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Login to GitHub Container registry
+ uses: docker/login-action@v2
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Create and push latest manifest image to Docker Hub
+ if: ${{ !startsWith(github.ref, 'refs/tags/') }}
+ uses: Noelware/docker-manifest-action@master
+ with:
+ inputs: purplei2p/i2pd:latest
+ images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
+ push: true
+
+ - name: Create and push latest manifest image to GHCR
+ if: ${{ !startsWith(github.ref, 'refs/tags/') }}
+ uses: Noelware/docker-manifest-action@master
+ with:
+ inputs: ghcr.io/purplei2p/i2pd:latest
+ images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
+ push: true
+
+ - name: Store release version to env
+ if: ${{ startsWith(github.ref, 'refs/tags/') }}
+ run: echo "RELEASE_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV
+
+ - name: Create and push release manifest to Docker Hub
+ if: ${{ startsWith(github.ref, 'refs/tags/') }}
+ uses: Noelware/docker-manifest-action@master
+ with:
+ inputs: purplei2p/i2pd:latest,purplei2p/i2pd:latest-release,purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
+ images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
+ push: true
+
+ - name: Create and push release manifest to GHCR
+ if: ${{ startsWith(github.ref, 'refs/tags/') }}
+ uses: Noelware/docker-manifest-action@master
+ with:
+ inputs: ghcr.io/purplei2p/i2pd:latest,ghcr.io/purplei2p/i2pd:latest-release,ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
+ images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
+ push: true
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/ChangeLog
^
|
@@ -1,6 +1,213 @@
# for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog
+## [2.50.2] - 2024-01-06
+###Fixed
+- Crash with OpenSSL 3.2.0
+- False positive clock skew detection
+
+## [2.50.1] - 2023-12-23
+###Fixed
+- Support for new EdDSA usage behavior in OpenSSL 3.2.0
+
+## [2.50.0] - 2023-12-18
+### Added
+- Support of concurrent ACCEPTs on SAM 3.1
+- Haiku OS support
+- Low bandwidth and far routers can expire before 1 hour
+### Changed
+- Don't pick too active peer for first hop
+- Try peer test again if status is Unknown
+- Send peer tests with random delay
+- Reseeds list
+### Fixed
+- XSS vulnerability in addresshelper
+- Publishing NAT64 ipv6 addresses
+- Deadlock in AsyncSend callback
+
+## [2.49.0] - 2023-09-18
+### Added
+- Handle SOCK5 authorization with empty user/password
+- Drop incoming transport sessions from too old or from future routers
+- Memory pool for router profiles
+- Allow 0 hops in explicitPeers
+### Changed
+- Separate network and testing status
+- Remove AVX code
+- Improve NTCP2 transport session logging
+- Select router with ipv4 for tunnel endpoint
+- Consider all addresses non-published for U and H routers even if they have host/port
+- Don't pick completely unreachable routers for tunnels
+- Exclude SSU1 introducers from SSU2 addresses
+- Don't create paired inbound tunnel if length is different
+- Remove introducer from RouterInfo after 60 minutes
+- Reduce SSU2 keep alive interval and add keep alive interval variance
+- Don't pick too old sessions for introducer
+### Fixed
+- Version of the subnegotiation in user/password SOCKS5 response
+- Send keepalive for existing session with introducer
+- Buffer offset for EVP_EncryptFinal_ex() to include outlen
+- Termination block size processing for transport sessions
+- Crash if deleted BOB destination was shared between few BOB sessions
+- Introducers with zero tag
+- Padding for SSU2 path response
+
+## [2.48.0] - 2023-06-12
+### Added
+- Allow user/password authentication method for SOCK5 proxy
+- Publish reject all congestion cap 'G' if transit is not accepted
+- 'critical' log level
+- Print b32 on webconsole destination page
+- Webconsole button to drop a remote LeaseSet
+- limits.zombies param - minimum percentage of successfully created tunnels for routers cleanup
+- Recognize real routers if successfully connected or responded to tunnel build request
+### Changed
+- Bypass slow transport sessions for first hop selection
+- Limit AESNI inline asm to x86/x64
+- Create smaller I2NP packets if possible
+- Make router unreachable if AEAD tag verification fails in SessionCreated
+- Don't include a router to floodfills list until it's confirmed as real
+- Drop LeaseSet store request if not floodfill
+- Bypass medium congestion('D') routers for client tunnels
+- Publish encrypted RouterInfo through tunnels
+- Check if s is valid x25519 public key
+- Check if socket is open before sending data in SSU2
+### Fixed
+- Webconsole empty page if destination is not found
+- i2p.streaming.answerPings param
+- Reload tunnels
+- Address caps for unspecified ipv6 address
+- Incomplete HTTP headers in I2P tunnels
+- SSU2 socket network exceptions on Windows
+- Use of 'server' type tunnel port as inport (#1936)
+
+## [2.47.0] - 2023-03-11
+### Added
+- Congestion caps
+- SAM UDP port parameter
+- Support domain addresses for yggdrasil reseeds
+### Changed
+- DHT for floodfills instead plain list
+- Process router's messages in separate thread
+- Don't publish non-reachable router
+- Send and check target destination in first streaming SYN packet
+- Reseeds list
+### Fixed
+- Memory leak in windows network state detection
+- Reseed attempts from invalid address
+
+## [2.46.1] - 2023-02-20
+### Fixed
+- Race condition while getting router's peer profile
+- Creation of new router.info
+- Displaying LeaseSets in the webconsole
+- Crash when processing ACK request
+
+## [2.46.0] - 2023-02-15
+### Added
+- Limit number of acked SSU2 packets to 511
+- Localization to Swedish, Portuguese, Turkish, Polish
+- Periodically send Datetime block in NTCP2 and SSU2
+- Don't select random port from reserved
+- In memory table for peer profiles
+- Store if router was unreachable in it's peer profile
+- Show IPv6 addresses in square brackets in webconsole
+- Check referer when processing Addresshelper
+### Changed
+- Algorithm for tunnel creation success rate calculation
+- Drop incoming NTCP2 and SSU2 connection if published IP doesn't match actual endpoint
+- Exclude actually unreachable router from netdb for 2 hours
+- Select first hop from high bandwidth peers for client tunnels
+- Drop too long or too short LeaseSet
+- Delete router from netdb if became invalid after update
+- Terminate existing session if clock skew detected
+- Close previous UDP socket if open before reopening
+- Minimal version for floodfill is 0.9.51
+- Sort transports by endpoints in webconsole
+### Fixed
+- Deadlock during processing I2NP block with Garlic in ECIES encrypted message to router
+- Race condition with encrypted LeaseSets
+- HTTP query detection
+- Connection attempts to IPs from invalid ranges
+- Publish "0.0.0.0" in RouterInfo
+- Crash upon receiving PeerTest 7
+- Tunnels for closed SAM session socket
+- Missing NTCP2 address in RouterInfo if enabled back
+
+## [2.45.1] - 2023-01-11
+### Added
+- Full Cone NAT status error
+### Changed
+- Drop duplicated I2NP messages in SSU2
+- Set rejection code 30 if tunnel with id already exists
+- Network status is always OK if peer test msg 5 received
+### Fixed
+- UPnP crash if SSU2 or NTCP2 is disabled
+- Crash on termination for some platforms
+
+## [2.45.0] - 2023-01-03
+### Added
+- Test for Symmetric NAT with peer test msgs 6 and 7
+- Webconsole "No Descriptors" router error state
+- 1 and 15 seconds bandwidth calculation for i2pcontrol
+- Show non-zero send queue size for transports in web console
+- Compressible padding for I2P addresses
+- Localization to Czech
+- Don't accept incoming session from invalid/reserved addresses for NTCP2 and SSU2
+- Limit simultaneous tunnel build requests by 4 per pool
+### Changed
+- Removed SSU support
+- Reduced bandwidth calculation interval from 60 to 15 seconds
+- Increased default max transit tunnels number from 2500 to 5000 or 10000 for floodfill
+- Transit tunnels limit is doubled if floodfill mode is enabled
+- NTCP2 and SSU2 timestamps are rounded to seconds
+- Drop RouterInfos and LeaseSets with timestamp from future
+- Don't delete unreachable routers if tunnel creation success rate is too low
+- Refuse duplicated incoming pending NTCP2 session from same IP
+- Don't send SSU2 termination again if termination received block received
+- Handle standard network error for SSU2 without throwing an exception
+- Don't select overloaded peer for next tunnel
+- Remove "X-Requested-With" in HTTP Proxy for non-AJAX requests
+### Fixed
+- File descriptors leak
+- Random crash on AddressBook update
+- Crash if incorrect LeaseSet size
+- Spamming to log if no descriptors
+- ::1 address in RouterInfo
+- SSU2 network error handling (especially for Windows)
+- Race condition with pending outgoing SSU2 sessions
+- RTT self-reduction for long-live streams
+
+## [2.44.0] - 2022-11-20
+### Added
+- SSL connection for server I2P tunnels
+- Localization to Italian and Spanish
+- SSU2 through SOCKS5 UDP proxy
+- Reload tunnels through web console
+- SSU2 send immediate ack request flag
+- SSU2 send and verify path challenge
+- Configurable ssu2.mtu4 and ssu2.mtu6
+### Changed
+- SSU2 is enabled and SSU is disabled by default
+- Separate network status and error
+- Random selection between NTCP2 and SSU2 priority
+- Added notbob.i2p to jump services
+- Remove DoNotTrack flag from HTTP Request header
+- Skip addresshelper page if destination was not changed
+- SSU2 allow different ports from RelayReponse and HolePunch
+- SSU2 resend PeerTest msg 1 and msg 2
+- SSU2 Send Retry instead SessionCreated if clock skew detected
+### Fixed
+- Long HTTP headers for HTTP proxy and HTTP server tunnel
+- SSU2 resends and resend limits
+- Crash at startup if addressbook is disabled
+- NTCP2 ipv6 connection through SOCKS5 proxy
+- SSU2 SessionRequest with zero token
+- SSU2 MTU less than 1280
+- SSU2 port=1
+- Incorrect addresses from network interfaces
+- Definitions for Darwin PPC; do not use pthread_setname_np
+
## [2.43.0] - 2022-08-22
### Added
- Complete SSU2 implementation
@@ -411,7 +618,7 @@
### Added
- Client auth flag for b33 address
### Changed
-- Remove incoming NTCP2 session from pending list when established
+- Remove incoming NTCP2 session from pending list when established
- Handle errors for NTCP2 SessionConfrimed send
### Fixed
- Failure to start on Windows XP
@@ -715,7 +922,7 @@
### Added
- Datagram i2p tunnels
- Unique local addresses for server tunnels
-- Configurable list of reseed servers and initial addressbook
+- Configurable list of reseed servers and initial addressbook
- Configurable netid
- Initial iOS support
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/LICENSE
^
|
@@ -1,4 +1,4 @@
-Copyright (c) 2013-2020, The PurpleI2P Project
+Copyright (c) 2013-2023, The PurpleI2P Project
All rights reserved.
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Makefile
^
|
@@ -47,6 +47,10 @@
LD_DEBUG = -s
endif
+ifneq (, $(DESTDIR))
+ PREFIX = $(DESTDIR)
+endif
+
ifneq (, $(findstring darwin, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
ifeq ($(HOMEBREW),1)
@@ -54,26 +58,31 @@
else
include Makefile.osx
endif
+else ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
+ DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32Service.cpp Win32/Win32NetState.cpp
+ include Makefile.mingw
else ifneq (, $(findstring linux, $(SYS))$(findstring gnu, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
include Makefile.linux
else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
include Makefile.bsd
-else ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
- DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32Service.cpp Win32/Win32NetState.cpp
- include Makefile.mingw
+else ifneq (, $(findstring haiku, $(SYS)))
+ DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
+ include Makefile.haiku
else # not supported
$(error Not supported platform)
endif
+INCFLAGS += -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR)
+DEFINES += -DOPENSSL_SUPPRESS_DEPRECATED
+NEEDED_CXXFLAGS += -MMD -MP
+
ifeq ($(USE_GIT_VERSION),yes)
GIT_VERSION := $(shell git describe --tags)
- NEEDED_CXXFLAGS += -DGITVER=\"$(GIT_VERSION)\"
+ DEFINES += -DGITVER=$(GIT_VERSION)
endif
-NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR) -DOPENSSL_SUPPRESS_DEPRECATED
-
LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
LANG_OBJS += $(patsubst %.cpp,obj/%.o,$(LANG_SRC))
@@ -106,17 +115,17 @@
## custom FLAGS to work at build-time.
obj/%.o: %.cpp | mk_obj_dir
- $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -c -o $@ $<
+ $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(DEFINES) $(INCFLAGS) -c -o $@ $<
# '-' is 'ignore if missing' on first run
-include $(DEPS)
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG)
- $(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS)
+ $(CXX) $(DEFINES) $(LDFLAGS) -o $@ $^ $(LDLIBS)
-$(SHLIB): $(LIB_OBJS) $(SHLIB_LANG)
+$(SHLIB): $(LIB_OBJS)
ifneq ($(USE_STATIC),yes)
- $(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS) $(SHLIB_LANG)
+ $(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS)
endif
$(SHLIB_CLIENT): $(LIB_CLIENT_OBJS) $(SHLIB) $(SHLIB_LANG)
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Makefile.bsd
^
|
@@ -6,7 +6,8 @@
## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove
## -std=c++11. If you want to remove this variable please do so in a way that allows setting
## custom FLAGS to work at build-time.
-NEEDED_CXXFLAGS = -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
+NEEDED_CXXFLAGS = -std=c++11
+DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1
INCFLAGS = -I/usr/include/ -I/usr/local/include/
LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Makefile.haiku
^
|
@@ -0,0 +1,10 @@
+CXX = g++
+CXXFLAGS := -Wall -std=c++11
+INCFLAGS = -I/system/develop/headers
+DEFINES = -D_DEFAULT_SOURCE -D_GNU_SOURCE
+LDLIBS = -lbe -lbsd -lnetwork -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
+
+ifeq ($(USE_UPNP),yes)
+ DEFINES += -DUSE_UPNP
+ LDLIBS += -lminiupnpc
+endif
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Makefile.linux
^
|
@@ -20,7 +20,11 @@
else ifeq ($(shell expr match ${CXXVER} "[5-6]"),1) # gcc 5 - 6
NEEDED_CXXFLAGS += -std=c++11
LDLIBS = -latomic
-else ifeq ($(shell expr match ${CXXVER} "[1,7-9]"),1) # gcc >= 7
+else ifeq ($(shell expr match ${CXXVER} "[7-9]"),1) # gcc 7 - 9
+ NEEDED_CXXFLAGS += -std=c++17
+ LDLIBS = -latomic
+else ifeq ($(shell expr match ${CXXVER} "1[0-9]"),2) # gcc 10+
+# NEEDED_CXXFLAGS += -std=c++20
NEEDED_CXXFLAGS += -std=c++17
LDLIBS = -latomic
else # not supported
@@ -54,12 +58,13 @@
# UPNP Support (miniupnpc 1.5 and higher)
ifeq ($(USE_UPNP),yes)
- NEEDED_CXXFLAGS += -DUSE_UPNP
+ DEFINES += -DUSE_UPNP
endif
ifeq ($(USE_AESNI),yes)
ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that
- NEEDED_CXXFLAGS += -D__AES__ -maes
+ NEEDED_CXXFLAGS += -maes
+ DEFINES += -D__AES__
endif
endif
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Makefile.mingw
^
|
@@ -4,49 +4,50 @@
WINDRES = windres
CXXFLAGS := $(CXX_DEBUG) -fPIC -msse
-INCFLAGS = -I$(DAEMON_SRC_DIR) -IWin32
-LDFLAGS := ${LD_DEBUG} -static
+INCFLAGS := -I$(DAEMON_SRC_DIR) -IWin32
+LDFLAGS := ${LD_DEBUG} -static -fPIC -msse
-NEEDED_CXXFLAGS += -std=c++17 -DWIN32_LEAN_AND_MEAN
-
-# Boost libraries suffix
-BOOST_SUFFIX = -mt
+NEEDED_CXXFLAGS += -std=c++17
+DEFINES += -DWIN32_LEAN_AND_MEAN
# UPNP Support
ifeq ($(USE_UPNP),yes)
- CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB
+ DEFINES += -DUSE_UPNP -DMINIUPNP_STATICLIB
LDLIBS = -lminiupnpc
endif
LDLIBS += \
- -lboost_system$(BOOST_SUFFIX) \
- -lboost_date_time$(BOOST_SUFFIX) \
- -lboost_filesystem$(BOOST_SUFFIX) \
- -lboost_program_options$(BOOST_SUFFIX) \
- -lssl \
- -lcrypto \
- -lz \
+ $(MINGW_PREFIX)/lib/libboost_system-mt.a \
+ $(MINGW_PREFIX)/lib/libboost_date_time-mt.a \
+ $(MINGW_PREFIX)/lib/libboost_filesystem-mt.a \
+ $(MINGW_PREFIX)/lib/libboost_program_options-mt.a \
+ $(MINGW_PREFIX)/lib/libssl.a \
+ $(MINGW_PREFIX)/lib/libcrypto.a \
+ $(MINGW_PREFIX)/lib/libz.a \
-lwsock32 \
-lws2_32 \
- -lgdi32 \
-liphlpapi \
+ -lcrypt32 \
+ -lgdi32 \
-lole32 \
-luuid \
-lpthread
ifeq ($(USE_WIN32_APP), yes)
- NEEDED_CXXFLAGS += -DWIN32_APP
+ DEFINES += -DWIN32_APP
LDFLAGS += -mwindows
DAEMON_RC += Win32/Resource.rc
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
endif
ifeq ($(USE_WINXP_FLAGS), yes)
- NEEDED_CXXFLAGS += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501
+ DEFINES += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501
endif
ifeq ($(USE_AESNI),yes)
- NEEDED_CXXFLAGS += -D__AES__ -maes
+ NEEDED_CXXFLAGS += -maes
+ LDFLAGS += -maes
+ DEFINES += -D__AES__
endif
ifeq ($(USE_ASLR),yes)
@@ -54,4 +55,4 @@
endif
obj/%.o : %.rc | mk_obj_dir
- $(WINDRES) -i $< -o $@
+ $(WINDRES) $(DEFINES) $(INCFLAGS) --preprocessor-arg=-MMD --preprocessor-arg=-MP --preprocessor-arg=-MF$@.d -i $< -o $@
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Makefile.osx
^
|
@@ -1,10 +1,10 @@
CXX = clang++
-CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX
+CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11
INCFLAGS = -I/usr/local/include
+DEFINES := -DMAC_OSX
LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib
LDFLAGS += -Wl,-dead_strip
LDFLAGS += -Wl,-dead_strip_dylibs
-LDFLAGS += -Wl,-bind_at_load
ifeq ($(USE_STATIC),yes)
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
@@ -14,7 +14,7 @@
ifeq ($(USE_UPNP),yes)
LDFLAGS += -ldl
- CXXFLAGS += -DUSE_UPNP
+ DEFINES += -DUSE_UPNP
ifeq ($(USE_STATIC),yes)
LDLIBS += /usr/local/lib/libminiupnpc.a
else
@@ -22,8 +22,12 @@
endif
endif
-ifeq ($(USE_AESNI),yes)
- CXXFLAGS += -D__AES__ -maes
-else
- CXXFLAGS += -msse
+OSARCH = $(shell uname -p)
+
+ifneq ($(OSARCH),powerpc)
+ ifeq ($(USE_AESNI),yes)
+ CXXFLAGS += -D__AES__ -maes
+ else
+ CXXFLAGS += -msse
+ endif
endif
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/README.md
^
|
@@ -69,12 +69,12 @@
**Supported systems:**
-* GNU/Linux - [![Build on Ubuntu](https://github.com/PurpleI2P/i2pd/actions/workflows/build.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build.yml)
- * CentOS / Fedora / Mageia - [![Build Status](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/)
- * Alpine, ArchLinux, openSUSE, Gentoo, Debian, Ubuntu, etc.
+* GNU/Linux (Debian, Ubuntu, etc) - [![Build on Ubuntu](https://github.com/PurpleI2P/i2pd/actions/workflows/build.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build.yml)
+* CentOS, Fedora, Mageia - [![Build Status](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/)
+* Alpine, ArchLinux, openSUSE, Gentoo, etc.
* Windows - [![Build on Windows](https://github.com/PurpleI2P/i2pd/actions/workflows/build-windows.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-windows.yml)
-* Mac OS X - [![Build on OSX](https://github.com/PurpleI2P/i2pd/actions/workflows/build-osx.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-osx.yml)
-* Docker image - [![Build Status](https://img.shields.io/docker/cloud/build/purplei2p/i2pd)](https://hub.docker.com/r/purplei2p/i2pd/builds/) [![Build containers](https://github.com/PurpleI2P/i2pd/actions/workflows/docker.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/docker.yml)
+* Mac OS - [![Build on OSX](https://github.com/PurpleI2P/i2pd/actions/workflows/build-osx.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-osx.yml)
+* Docker image - [![Build containers](https://github.com/PurpleI2P/i2pd/actions/workflows/docker.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/docker.yml)
* Snap - [![i2pd](https://snapcraft.io/i2pd/badge.svg)](https://snapcraft.io/i2pd) [![i2pd](https://snapcraft.io/i2pd/trending.svg?name=0)](https://snapcraft.io/i2pd)
* FreeBSD - [![Build on FreeBSD](https://github.com/PurpleI2P/i2pd/actions/workflows/build-freebsd.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-freebsd.yml)
* Android - [![Android CI](https://github.com/PurpleI2P/i2pd-android/actions/workflows/android.yml/badge.svg)](https://github.com/PurpleI2P/i2pd-android/actions/workflows/android.yml)
@@ -99,13 +99,23 @@
Donations
---------
-BTC: 3MDoGJW9TLMTCDGrR9bLgWXfm6sjmgy86f
-LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
-ETH: 0x9e5bac70d20d1079ceaa111127f4fb3bccce379d
-DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF
-ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ
-GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG
-XMR: 497pJc7X4xqKvcLBLpSUtRgWqMMyo24u4btCos3cak6gbMkpobgSU6492ztUcUBghyeHpYeczB55s38NpuHoH5WGNSPDRMH
+**E-Mail**: ```i2porignal at yandex.com```
+
+**BTC**: ```3MDoGJW9TLMTCDGrR9bLgWXfm6sjmgy86f```
+
+**LTC**: ```LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59```
+
+**ETH**: ```0x9e5bac70d20d1079ceaa111127f4fb3bccce379d```
+
+**GST**: ```GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG```
+
+**DASH**: ```Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF```
+
+**ZEC**: ```t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ```
+
+**ANC**: ```AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z```
+
+**XMR**: ```497pJc7X4xqKvcLBLpSUtRgWqMMyo24u4btCos3cak6gbMkpobgSU6492ztUcUBghyeHpYeczB55s38NpuHoH5WGNSPDRMH```
License
-------
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Win32/DaemonWin32.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -29,7 +29,7 @@
setlocale(LC_CTYPE, "");
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
- setlocale(LC_ALL, "Russian");
+ //setlocale(LC_ALL, "Russian");
setlocale(LC_TIME, "C");
i2p::log::SetThrowFunction ([](const std::string& s)
@@ -47,7 +47,7 @@
I2PService service((PSTR)SERVICE_NAME);
if (!I2PService::Run(service))
{
- LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
+ LogPrint(eLogCritical, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
return false;
}
return false;
@@ -61,10 +61,10 @@
setlocale(LC_CTYPE, "");
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
- setlocale(LC_ALL, "Russian");
+ //setlocale(LC_ALL, "Russian");
setlocale(LC_TIME, "C");
#ifdef WIN32_APP
- if (!i2p::win32::StartWin32App ()) return false;
+ if (!i2p::win32::StartWin32App (isDaemon)) return false;
#endif
bool ret = Daemon_Singleton::start();
if (ret && i2p::log::Logger().GetLogType() == eLogFile)
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Win32/Resource.rc
^
|
@@ -1,36 +1,36 @@
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-#include "winres.h"
-#undef APSTUDIO_READONLY_SYMBOLS
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-
-#ifdef APSTUDIO_INVOKED
-1 TEXTINCLUDE
-BEGIN
- "resource.h\0"
-END
-
-2 TEXTINCLUDE
-BEGIN
- "#include ""winres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-#endif // APSTUDIO_INVOKED
-
-MAINICON ICON "mask.ico"
-#endif // English (United States) resources
-
-#ifndef APSTUDIO_INVOKED
-#include "Resource.rc2"
-#endif // not APSTUDIO_INVOKED
-
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+#endif // APSTUDIO_INVOKED
+
+MAINICON ICON "mask.ico"
+#endif // English (United States) resources
+
+#ifndef APSTUDIO_INVOKED
+#include "Resource.rc2"
+#endif // not APSTUDIO_INVOKED
+
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Win32/Resource.rc2
^
|
@@ -2,7 +2,7 @@
#error this file is not editable by Microsoft Visual C++
#endif //APSTUDIO_INVOKED
-#include "../libi2pd/version.h"
+#include "version.h"
VS_VERSION_INFO VERSIONINFO
FILEVERSION I2PD_VERSION_MAJOR,I2PD_VERSION_MINOR,I2PD_VERSION_MICRO,I2PD_VERSION_PATCH
@@ -25,7 +25,7 @@
VALUE "FileDescription", "C++ I2P daemon"
VALUE "FileVersion", I2PD_VERSION
VALUE "InternalName", CODENAME
- VALUE "LegalCopyright", "Copyright (C) 2013-2022, The PurpleI2P Project"
+ VALUE "LegalCopyright", "Copyright (C) 2013-2023, The PurpleI2P Project"
VALUE "OriginalFilename", "i2pd"
VALUE "ProductName", "Purple I2P"
VALUE "ProductVersion", I2P_VERSION
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Win32/Win32App.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -45,6 +45,7 @@
namespace win32
{
DWORD g_GracefulShutdownEndtime = 0;
+ bool g_isWinService;
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
{
@@ -144,35 +145,34 @@
s << bytes << " Bytes\n";
}
- static void ShowNetworkStatus (std::stringstream& s, RouterStatus status)
+ static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, bool testing)
{
switch (status)
{
case eRouterStatusOK: s << "OK"; break;
- case eRouterStatusTesting: s << "Test"; break;
case eRouterStatusFirewalled: s << "FW"; break;
case eRouterStatusUnknown: s << "Unk"; break;
case eRouterStatusProxy: s << "Proxy"; break;
case eRouterStatusMesh: s << "Mesh"; break;
- case eRouterStatusError:
+ default: s << "Unk";
+ };
+ if (testing)
+ s << " (Test)";
+ if (i2p::context.GetError () != eRouterErrorNone)
+ {
+ switch (i2p::context.GetError ())
{
- s << "Err";
- switch (i2p::context.GetError ())
- {
- case eRouterErrorClockSkew:
- s << " - Clock skew";
- break;
- case eRouterErrorOffline:
- s << " - Offline";
- break;
- case eRouterErrorSymmetricNAT:
- s << " - Symmetric NAT";
- break;
- default: ;
- }
+ case eRouterErrorClockSkew:
+ s << " - Clock skew";
break;
+ case eRouterErrorOffline:
+ s << " - Offline";
+ break;
+ case eRouterErrorSymmetricNAT:
+ s << " - Symmetric NAT";
+ break;
+ default: ;
}
- default: s << "Unk";
}
}
@@ -180,11 +180,11 @@
{
s << "\n";
s << "Status: ";
- ShowNetworkStatus (s, i2p::context.GetStatus ());
+ ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetTesting ());
if (i2p::context.SupportsV6 ())
{
s << " / ";
- ShowNetworkStatus (s, i2p::context.GetStatusV6 ());
+ ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetTestingV6 ());
}
s << "; ";
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
@@ -349,6 +349,9 @@
}
}
}
+#if (__cplusplus >= 201703L) // C++ 17 or higher
+ [[fallthrough]];
+#endif
}
case WM_TRAYICON:
{
@@ -418,8 +421,9 @@
return DefWindowProc( hWnd, uMsg, wParam, lParam);
}
- bool StartWin32App ()
+ bool StartWin32App (bool isWinService)
{
+ g_isWinService = isWinService;
if (FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")))
{
MessageBox(NULL, TEXT("I2Pd is running already"), TEXT("Warning"), MB_OK);
@@ -448,7 +452,9 @@
MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST);
return false;
}
- SubscribeToEvents();
+ // COM requires message loop to work, which is not implemented in service mode
+ if (!g_isWinService)
+ SubscribeToEvents();
return true;
}
@@ -468,7 +474,8 @@
HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"));
if (hWnd)
PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_EXIT, 0), 0);
- // UnSubscribeFromEvents(); // TODO: understand why unsubscribing crashes app
+ else if(!g_isWinService)
+ UnSubscribeFromEvents();
UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL));
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Win32/Win32App.h
^
|
@@ -17,7 +17,7 @@
{
extern DWORD g_GracefulShutdownEndtime;
- bool StartWin32App ();
+ bool StartWin32App (bool isWinService);
void StopWin32App ();
int RunWin32App ();
bool GracefulShutdown ();
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Win32/Win32NetState.cpp
^
|
@@ -15,6 +15,7 @@
INetworkListManager *pNetworkListManager = nullptr;
IConnectionPointContainer *pCPContainer = nullptr;
IConnectionPoint *pConnectPoint = nullptr;
+CNetworkListManagerEvent *pNetEvent = nullptr;
DWORD Cookie = 0;
void SubscribeToEvents()
@@ -29,7 +30,11 @@
if (SUCCEEDED(Result))
{
VARIANT_BOOL IsConnect = VARIANT_FALSE;
+#if defined(_MSC_VER)
+ Result = pNetworkListManager->get_IsConnectedToInternet(&IsConnect);
+#else
Result = pNetworkListManager->IsConnectedToInternet(&IsConnect);
+#endif
if (SUCCEEDED(Result)) {
i2p::transport::transports.SetOnline (true);
LogPrint(eLogInfo, "NetState: Current state: ", IsConnect == VARIANT_TRUE ? "connected" : "disconnected");
@@ -41,8 +46,8 @@
Result = pCPContainer->FindConnectionPoint(IID_INetworkListManagerEvents, &pConnectPoint);
if(SUCCEEDED(Result))
{
- CNetworkListManagerEvent *NetEvent = new CNetworkListManagerEvent;
- Result = pConnectPoint->Advise((IUnknown *)NetEvent, &Cookie);
+ pNetEvent = new CNetworkListManagerEvent;
+ Result = pConnectPoint->Advise((IUnknown *)pNetEvent, &Cookie);
if (SUCCEEDED(Result))
LogPrint(eLogInfo, "NetState: Successfully subscribed to NetworkListManagerEvent messages");
else
@@ -59,6 +64,7 @@
void UnSubscribeFromEvents()
{
+ LogPrint(eLogInfo, "NetState: Unsubscribing from NetworkListManagerEvents");
try
{
if (pConnectPoint) {
@@ -66,6 +72,9 @@
pConnectPoint->Release();
}
+ if (pNetEvent)
+ pNetEvent->Release();
+
if (pCPContainer)
pCPContainer->Release();
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Win32/Win32NetState.h
^
|
@@ -19,21 +19,18 @@
{
public:
CNetworkListManagerEvent() : m_ref(1) { }
- ~CNetworkListManagerEvent() { }
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
{
- HRESULT Result = S_OK;
if (IsEqualIID(riid, IID_IUnknown)) {
*ppvObject = (IUnknown *)this;
} else if (IsEqualIID(riid ,IID_INetworkListManagerEvents)) {
*ppvObject = (INetworkListManagerEvents *)this;
} else {
- Result = E_NOINTERFACE;
+ return E_NOINTERFACE;
}
AddRef();
-
- return Result;
+ return S_OK;
}
ULONG STDMETHODCALLTYPE AddRef()
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/Win32/Win32Service.cpp
^
|
@@ -21,7 +21,7 @@
HWINSTA hWinStation = GetProcessWindowStation();
if (hWinStation != NULL)
{
- USEROBJECTFLAGS uof = { 0 };
+ USEROBJECTFLAGS uof = { FALSE, FALSE, 0 };
if (GetUserObjectInformation(hWinStation, UOI_FLAGS, &uof, sizeof(USEROBJECTFLAGS), NULL) && ((uof.dwFlags & WSF_VISIBLE) == 0))
{
bIsService = TRUE;
@@ -119,12 +119,12 @@
}
catch (DWORD dwError)
{
- LogPrint(eLogError, "Win32Service: Start error: ", dwError);
+ LogPrint(eLogCritical, "Win32Service: Start error: ", dwError);
SetServiceStatus(SERVICE_STOPPED, dwError);
}
catch (...)
{
- LogPrint(eLogError, "Win32Service: failed to start: ", EVENTLOG_ERROR_TYPE);
+ LogPrint(eLogCritical, "Win32Service: failed to start: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_STOPPED);
}
}
@@ -162,7 +162,7 @@
}
catch (...)
{
- LogPrint(eLogError, "Win32Service: Failed to stop: ", EVENTLOG_ERROR_TYPE);
+ LogPrint(eLogCritical, "Win32Service: Failed to stop: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(dwOriginalState);
}
}
@@ -191,12 +191,12 @@
}
catch (DWORD dwError)
{
- LogPrint(eLogError, "Win32Service: Pause error: ", dwError);
+ LogPrint(eLogCritical, "Win32Service: Pause error: ", dwError);
SetServiceStatus(SERVICE_RUNNING);
}
catch (...)
{
- LogPrint(eLogError, "Win32Service: Failed to pause: ", EVENTLOG_ERROR_TYPE);
+ LogPrint(eLogCritical, "Win32Service: Failed to pause: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_RUNNING);
}
}
@@ -215,12 +215,12 @@
}
catch (DWORD dwError)
{
- LogPrint(eLogError, "Win32Service: Continue error: ", dwError);
+ LogPrint(eLogCritical, "Win32Service: Continue error: ", dwError);
SetServiceStatus(SERVICE_PAUSED);
}
catch (...)
{
- LogPrint(eLogError, "Win32Service: Failed to resume: ", EVENTLOG_ERROR_TYPE);
+ LogPrint(eLogCritical, "Win32Service: Failed to resume: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_PAUSED);
}
}
@@ -238,11 +238,11 @@
}
catch (DWORD dwError)
{
- LogPrint(eLogError, "Win32Service: Shutdown error: ", dwError);
+ LogPrint(eLogCritical, "Win32Service: Shutdown error: ", dwError);
}
catch (...)
{
- LogPrint(eLogError, "Win32Service: Failed to shut down: ", EVENTLOG_ERROR_TYPE);
+ LogPrint(eLogCritical, "Win32Service: Failed to shut down: ", EVENTLOG_ERROR_TYPE);
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/build/.gitignore
^
|
@@ -1,6 +1,13 @@
# Various generated files
/CMakeFiles/
+/Testing/
+/tests/
+/.ninja_*
+/arch.c
+/build.ninja
/i2pd
+/i2pd.exe
+/i2pd.exe.debug
/libi2pd.a
/libi2pdclient.a
/libi2pdlang.a
@@ -8,8 +15,13 @@
/CMakeCache.txt
/CPackConfig.cmake
/CPackSourceConfig.cmake
+/CTestTestfile.cmake
/install_manifest.txt
-/arch.c
+/Makefile
# windows build script
i2pd*.zip
build*.log
+# MVS project files
+*.vcxproj
+*.vcxproj.filters
+*.sln
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/build/CMakeLists.txt
^
|
@@ -1,14 +1,32 @@
cmake_minimum_required(VERSION 3.7)
-cmake_policy(VERSION 3.7)
-project("i2pd")
+
+if(${CMAKE_VERSION} VERSION_LESS 3.22)
+ cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
+else()
+ cmake_policy(VERSION 3.22)
+endif()
# for debugging
#set(CMAKE_VERBOSE_MAKEFILE on)
-# Win32 build with cmake is not supported
-if(WIN32 OR MSVC OR MSYS OR MINGW)
- message(SEND_ERROR "cmake build for windows is not supported. Please use MSYS2 with makefiles in project root.")
-endif()
+# paths
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
+set(CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
+
+set(LIBI2PD_SRC_DIR ${CMAKE_SOURCE_DIR}/libi2pd)
+set(LIBI2PD_CLIENT_SRC_DIR ${CMAKE_SOURCE_DIR}/libi2pd_client)
+set(LANG_SRC_DIR ${CMAKE_SOURCE_DIR}/i18n)
+set(DAEMON_SRC_DIR ${CMAKE_SOURCE_DIR}/daemon)
+
+include(Version)
+set_version("${LIBI2PD_SRC_DIR}/version.h" PROJECT_VERSION)
+
+project(
+ i2pd
+ VERSION ${PROJECT_VERSION}
+ HOMEPAGE_URL "https://i2pd.website/"
+ LANGUAGES C CXX
+)
# configurable options
option(WITH_AESNI "Use AES-NI instructions set" ON)
@@ -20,28 +38,28 @@
option(WITH_GIT_VERSION "Use git commit info as version" OFF)
option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF)
option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF)
+option(BUILD_TESTING "Build tests" OFF)
-# paths
-set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
-set(CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
+IF(BUILD_TESTING)
+ enable_testing()
+ENDIF()
-#Handle paths nicely
+# Handle paths nicely
include(GNUInstallDirs)
-# architecture
+# Architecture
include(TargetArch)
target_architecture(ARCHITECTURE)
-set(LIBI2PD_SRC_DIR ../libi2pd)
-set(LIBI2PD_CLIENT_SRC_DIR ../libi2pd_client)
-set(LANG_SRC_DIR ../i18n)
-set(DAEMON_SRC_DIR ../daemon)
+include(CheckAtomic)
-include_directories(${LIBI2PD_SRC_DIR})
-include_directories(${LIBI2PD_CLIENT_SRC_DIR})
-include_directories(${LANG_SRC_DIR})
-include_directories(${DAEMON_SRC_DIR})
+if(WITH_STATIC)
+ if(MSVC)
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+ endif()
+endif()
+include_directories(${LIBI2PD_SRC_DIR})
FILE(GLOB LIBI2PD_SRC ${LIBI2PD_SRC_DIR}/*.cpp)
add_library(libi2pd ${LIBI2PD_SRC})
set_target_properties(libi2pd PROPERTIES PREFIX "")
@@ -52,11 +70,9 @@
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT Libraries)
-# TODO Make libi2pd available to 3rd party projects via CMake as imported target
-# FIXME This pulls stdafx
-# install(EXPORT libi2pd DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
+include_directories(${LIBI2PD_CLIENT_SRC_DIR})
FILE(GLOB CLIENT_SRC ${LIBI2PD_CLIENT_SRC_DIR}/*.cpp)
add_library(libi2pdclient ${CLIENT_SRC})
set_target_properties(libi2pdclient PROPERTIES PREFIX "")
@@ -69,6 +85,7 @@
COMPONENT Libraries)
endif()
+include_directories(${LANG_SRC_DIR})
FILE(GLOB LANG_SRC ${LANG_SRC_DIR}/*.cpp)
add_library(libi2pdlang ${LANG_SRC})
set_target_properties(libi2pdlang PROPERTIES PREFIX "")
@@ -81,14 +98,33 @@
COMPONENT Libraries)
endif()
+include_directories(${DAEMON_SRC_DIR})
+
set(DAEMON_SRC
"${DAEMON_SRC_DIR}/Daemon.cpp"
"${DAEMON_SRC_DIR}/HTTPServer.cpp"
"${DAEMON_SRC_DIR}/I2PControl.cpp"
+ "${DAEMON_SRC_DIR}/I2PControlHandlers.cpp"
"${DAEMON_SRC_DIR}/i2pd.cpp"
"${DAEMON_SRC_DIR}/UPnP.cpp"
)
+if(WIN32)
+ set(WIN32_SRC_DIR ${CMAKE_SOURCE_DIR}/Win32)
+ include_directories(${WIN32_SRC_DIR})
+
+ list(APPEND DAEMON_SRC
+ "${WIN32_SRC_DIR}/DaemonWin32.cpp"
+ "${WIN32_SRC_DIR}/Win32App.cpp"
+ "${WIN32_SRC_DIR}/Win32Service.cpp"
+ "${WIN32_SRC_DIR}/Win32NetState.cpp"
+ )
+
+ file(GLOB WIN32_RC ${WIN32_SRC_DIR}/*.rc)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWIN32_APP -DWIN32_LEAN_AND_MEAN -DNOMINMAX")
+
+endif()
+
if(WITH_UPNP)
add_definitions(-DUSE_UPNP)
endif()
@@ -96,30 +132,44 @@
if(WITH_GIT_VERSION)
include(GetGitRevisionDescription)
git_describe(GIT_VERSION)
- add_definitions(-DGITVER="${GIT_VERSION}")
+ add_definitions(-DGITVER=${GIT_VERSION})
endif()
if(APPLE)
add_definitions(-DMAC_OSX)
endif()
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch -Wno-unused-parameter")
-set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic")
-# TODO: The following is incompatible with static build and enabled hardening for OpenWRT.
-# Multiple definitions of __stack_chk_fail(libssp & libc)
-set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -flto -s -ffunction-sections -fdata-sections")
-set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections") # -flto is added from above
-
-# check for c++17 & c++11 support
-include(CheckCXXCompilerFlag)
-CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED)
-CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED)
-if(CXX17_SUPPORTED)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
-elseif(CXX11_SUPPORTED)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+if(HAIKU)
+ add_definitions(-D_DEFAULT_SOURCE -D_GNU_SOURCE)
+endif()
+
+if(MSVC)
+ add_definitions(-DWINVER=0x0600)
+ add_definitions(-D_WIN32_WINNT=0x0600)
else()
- message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch -Wno-unused-parameter -Wno-uninitialized")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic")
+ # TODO: The following is incompatible with static build and enabled hardening for OpenWRT.
+ # Multiple definitions of __stack_chk_fail(libssp & libc)
+ if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -flto -s")
+ endif()
+ set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -ffunction-sections -fdata-sections")
+ set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections") # -flto is added from above
+
+ # check for c++17 & c++11 support
+ include(CheckCXXCompilerFlag)
+
+ CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED)
+ CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED)
+
+ if(CXX17_SUPPORTED)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
+ elseif(CXX11_SUPPORTED)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ else()
+ message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?")
+ endif()
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
@@ -151,8 +201,11 @@
# Note: AES-NI and AVX is available on x86-based CPU's.
# Here also ARM64 implementation, but currently we don't support it.
+# MSVC is not supported due to different ASM processing, so we hope OpenSSL has its own checks to run optimized code.
if(WITH_AESNI AND (ARCHITECTURE MATCHES "x86_64" OR ARCHITECTURE MATCHES "i386"))
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
+ if(NOT MSVC)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
+ endif()
add_definitions(-D__AES__)
endif()
@@ -170,16 +223,48 @@
endif()
endif()
+# Use std::atomic instead of GCC builtins on macOS PowerPC:
+# For more information refer to: https://github.com/PurpleI2P/i2pd/issues/1726#issuecomment-1306335111
+# This has been fixed in Boost 1.81, nevertheless we retain the setting for the sake of compatibility.
+if(APPLE AND CMAKE_OSX_ARCHITECTURES MATCHES "ppc")
+ add_definitions(-DBOOST_SP_USE_STD_ATOMIC)
+endif()
# libraries
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
if(WITH_STATIC)
+ if(NOT MSVC)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
+ endif()
+
set(Boost_USE_STATIC_LIBS ON)
- set(Boost_USE_STATIC_RUNTIME ON)
+ if(MSVC)
+ set(Boost_USE_STATIC_RUNTIME ON)
+ else()
+ set(Boost_USE_STATIC_RUNTIME OFF)
+ endif()
+
+ if(MSVC)
+ set(OPENSSL_MSVC_STATIC_RT ON)
+ endif()
set(OPENSSL_USE_STATIC_LIBS ON)
+
+ set(ZLIB_USE_STATIC_LIBS ON)
+ if(MSVC)
+ set(ZLIB_NAMES zlibstatic zlibstat)
+ else()
+ set(ZLIB_NAMES libz zlibstatic zlibstat zlib z)
+ endif()
+
+ if(WITH_UPNP)
+ set(MINIUPNPC_USE_STATIC_LIBS ON)
+ add_definitions(-DMINIUPNP_STATICLIB)
+ endif()
+
set(BUILD_SHARED_LIBS OFF)
+
if(${CMAKE_CXX_COMPILER} MATCHES ".*-openwrt-.*")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
# set(CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,--whole-archive -lpthread -Wl,--no-whole-archive")
@@ -189,17 +274,23 @@
# TODO: Consider separate compilation for LIBI2PD_SRC for library.
# No need in -fPIC overhead for binary if not interested in library
# HINT: revert c266cff CMakeLists.txt: compilation speed up
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
- add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
+ if(NOT MSVC)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
+ endif()
+ add_definitions(-DBOOST_ATOMIC_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
+ if(WIN32)
+ set(Boost_USE_STATIC_LIBS OFF)
+ set(Boost_USE_STATIC_RUNTIME OFF)
+ endif()
endif()
-find_package(Boost COMPONENTS system filesystem program_options date_time REQUIRED)
-if(NOT DEFINED Boost_INCLUDE_DIRS)
+find_package(Boost REQUIRED COMPONENTS system filesystem program_options date_time OPTIONAL_COMPONENTS atomic)
+if(NOT DEFINED Boost_FOUND)
message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!")
endif()
find_package(OpenSSL REQUIRED)
-if(NOT DEFINED OPENSSL_INCLUDE_DIR)
+if(NOT DEFINED OPENSSL_FOUND)
message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!")
endif()
@@ -224,8 +315,6 @@
# load includes
include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
-include(CheckAtomic)
-
# show summary
message(STATUS "---------------------------------------")
message(STATUS "Build type : ${CMAKE_BUILD_TYPE}")
@@ -241,16 +330,34 @@
message(STATUS " BINARY : ${WITH_BINARY}")
message(STATUS " STATIC BUILD : ${WITH_STATIC}")
message(STATUS " UPnP : ${WITH_UPNP}")
+if(WITH_GIT_VERSION)
+message(STATUS " GIT VERSION : ${WITH_GIT_VERSION} (${GIT_VERSION})")
+else()
message(STATUS " GIT VERSION : ${WITH_GIT_VERSION}")
+endif()
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
message(STATUS "---------------------------------------")
if(WITH_BINARY)
- add_executable("${PROJECT_NAME}" ${DAEMON_SRC})
+ if(WIN32)
+ add_executable("${PROJECT_NAME}" WIN32 ${DAEMON_SRC} ${WIN32_RC})
+ else()
+ add_executable("${PROJECT_NAME}" ${DAEMON_SRC})
+ endif()
+
+ if(WIN32)
+ list(APPEND MINGW_EXTRA "wsock32" "ws2_32" "iphlpapi")
+ # OpenSSL may require Crypt32 library on MSVC build, which is not added by CMake lesser than 3.21
+ if(MSVC AND ${CMAKE_VERSION} VERSION_LESS 3.21)
+ list(APPEND MINGW_EXTRA "crypt32")
+ endif()
+ endif()
if(WITH_STATIC)
- set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static")
+ if(NOT MSVC)
+ set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static")
+ endif()
endif()
if(WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
@@ -263,13 +370,24 @@
list(REMOVE_AT Boost_LIBRARIES -1)
endif()
+ # synchronization library is incompatible with Windows 7
+ if(WIN32)
+ get_target_property(BOOSTFSLIBS Boost::filesystem INTERFACE_LINK_LIBRARIES)
+ list(REMOVE_ITEM BOOSTFSLIBS synchronization)
+ set_target_properties(Boost::filesystem PROPERTIES INTERFACE_LINK_LIBRARIES "${BOOSTFSLIBS}")
+ endif()
+
if(WITH_STATIC)
set(DL_LIB ${CMAKE_DL_LIBS})
endif()
- target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${DL_LIB} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto ${MINIUPNPC_LIBRARY} ZLIB::ZLIB Threads::Threads ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
+ target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto ${MINIUPNPC_LIBRARY} ZLIB::ZLIB Threads::Threads ${MINGW_EXTRA} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
set(DIRS "${Boost_LIBRARY_DIR};${OPENSSL_INCLUDE_DIR}/../bin;${ZLIB_INCLUDE_DIR}/../bin;/mingw32/bin")
endif()
+
+if(BUILD_TESTING)
+ add_subdirectory(${CMAKE_SOURCE_DIR}/tests ${CMAKE_CURRENT_BINARY_DIR}/tests)
+endif()
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/build/cmake_modules/CheckAtomic.cmake
^
|
@@ -1,18 +1,23 @@
# atomic builtins are required for threading support.
INCLUDE(CheckCXXSourceCompiles)
+INCLUDE(CheckLibraryExists)
# Sometimes linking against libatomic is required for atomic ops, if
# the platform doesn't support lock-free atomics.
function(check_working_cxx_atomics varname)
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
- set(CMAKE_REQUIRED_FLAGS "-std=c++11")
+ set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11")
CHECK_CXX_SOURCE_COMPILES("
#include <atomic>
std::atomic<int> x;
+std::atomic<short> y;
+std::atomic<char> z;
int main() {
- return x;
+ ++z;
+ ++y;
+ return ++x;
}
" ${varname})
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
@@ -27,6 +32,7 @@
std::atomic<uint64_t> x (0);
int main() {
uint64_t i = x.load(std::memory_order_relaxed);
+ (void)i;
return 0;
}
" ${varname})
@@ -34,15 +40,16 @@
endfunction(check_working_cxx_atomics64)
-# This isn't necessary on MSVC, so avoid command-line switch annoyance
-# by only running on GCC-like hosts.
-if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
+# Check for (non-64-bit) atomic operations.
+if(MSVC)
+ set(HAVE_CXX_ATOMICS_WITHOUT_LIB True)
+else()
# First check if atomics work without the library.
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB)
# If not, check if the library exists, and atomics work with it.
if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC)
- if( HAVE_LIBATOMIC )
+ if(HAVE_LIBATOMIC)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS_WITH_LIB)
@@ -58,20 +65,20 @@
if(MSVC)
set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True)
else()
+ # First check if atomics work without the library.
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB)
-endif()
-
-# If not, check if the library exists, and atomics work with it.
-if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
- check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64)
- if(HAVE_CXX_LIBATOMICS64)
- list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
- check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB)
- if (NOT HAVE_CXX_ATOMICS64_WITH_LIB)
- message(FATAL_ERROR "Host compiler must support std::atomic!")
+ # If not, check if the library exists, and atomics work with it.
+ if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
+ check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64)
+ if(HAVE_CXX_LIBATOMICS64)
+ list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
+ check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB)
+ if (NOT HAVE_CXX_ATOMICS64_WITH_LIB)
+ message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!")
+ endif()
+ else()
+ message(FATAL_ERROR "Host compiler appears to require libatomic for 64-bit operations, but cannot find it.")
endif()
- else()
- message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.")
endif()
endif()
@@ -80,7 +87,6 @@
## assumes C++11 <atomic> works.
CHECK_CXX_SOURCE_COMPILES("
#ifdef _MSC_VER
-#include <Intrin.h> /* Workaround for PR19898. */
#include <windows.h>
#endif
int main() {
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/build/cmake_modules/FindCheck.cmake
^
|
@@ -0,0 +1,55 @@
+# - Try to find the CHECK libraries
+# Once done this will define
+#
+# CHECK_FOUND - system has check
+# CHECK_INCLUDE_DIRS - the check include directory
+# CHECK_LIBRARIES - check library
+#
+# Copyright (c) 2007 Daniel Gollub <gollub@b1-systems.de>
+# Copyright (c) 2007-2009 Bjoern Ricks <bjoern.ricks@gmail.com>
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+INCLUDE( FindPkgConfig )
+
+IF ( Check_FIND_REQUIRED )
+ SET( _pkgconfig_REQUIRED "REQUIRED" )
+ELSE( Check_FIND_REQUIRED )
+ SET( _pkgconfig_REQUIRED "" )
+ENDIF ( Check_FIND_REQUIRED )
+
+IF ( CHECK_MIN_VERSION )
+ PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check>=${CHECK_MIN_VERSION} )
+ELSE ( CHECK_MIN_VERSION )
+ PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check )
+ENDIF ( CHECK_MIN_VERSION )
+
+# Look for CHECK include dir and libraries
+IF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND )
+
+ FIND_PATH( CHECK_INCLUDE_DIRS check.h )
+
+ FIND_LIBRARY( CHECK_LIBRARIES NAMES check )
+
+ IF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
+ SET( CHECK_FOUND 1 )
+ IF ( NOT Check_FIND_QUIETLY )
+ MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" )
+ ENDIF ( NOT Check_FIND_QUIETLY )
+ ELSE ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
+ IF ( Check_FIND_REQUIRED )
+ MESSAGE( FATAL_ERROR "Could NOT find CHECK" )
+ ELSE ( Check_FIND_REQUIRED )
+ IF ( NOT Check_FIND_QUIETLY )
+ MESSAGE( STATUS "Could NOT find CHECK" )
+ ENDIF ( NOT Check_FIND_QUIETLY )
+ ENDIF ( Check_FIND_REQUIRED )
+ ENDIF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
+ENDIF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND )
+
+# Hide advanced variables from CMake GUIs
+MARK_AS_ADVANCED( CHECK_INCLUDE_DIRS CHECK_LIBRARIES )
+
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/build/cmake_modules/TargetArch.cmake
^
|
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2022, The PurpleI2P Project
+# Copyright (c) 2017-2023, The PurpleI2P Project
# This file is part of Purple i2pd project and licensed under BSD3
# See full license text in LICENSE file at top of project tree
@@ -18,7 +18,7 @@
|| defined(_M_ARM64) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 8)
#error cmake_ARCH arm64
- #if defined(__ARM_ARCH_7__) \\
+ #elif defined(__ARM_ARCH_7__) \\
|| defined(__ARM_ARCH_7A__) \\
|| defined(__ARM_ARCH_7R__) \\
|| defined(__ARM_ARCH_7M__) \\
@@ -61,7 +61,7 @@
#else
#error cmake_ARCH mips
#endif
-#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
+#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) || defined(__POWERPC__) \\
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
|| defined(_M_MPPC) || defined(_M_PPC)
#if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
@@ -83,13 +83,13 @@
# First let's normalize the order of the values
# Note that it's not possible to compile PowerPC applications if you are using
- # the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
- # disable it by default
+ # the OS X SDK version 10.7 or later - you'll need 10.4/10.5/10.6 for that, so we
+ # disable it by default. Also, ppc64 is not supported in 10.6.
# See this page for more information:
# http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
# Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
- # On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
+ # On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise; 10.6 also supports ppc.
foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
@@ -133,11 +133,11 @@
enable_language(C)
# Detect the architecture in a rather creative way...
- # This compiles a small C program which is a series of ifdefs that selects a
- # particular #error preprocessor directive whose message string contains the
- # target architecture. The program will always fail to compile (both because
- # file is not a valid C program, and obviously because of the presence of the
- # #error preprocessor directives... but by exploiting the preprocessor in this
+ # This compiles a small C program which is a series of ifdefs that selects
+ # a particular #error preprocessor directive whose message string contains
+ # the target architecture. The program will always fail to compile (both because
+ # file is not a valid C program, and obviously because of the presence of
+ # the #error preprocessor directives... but by exploiting the preprocessor in this
# way, we can detect the correct target architecture even when cross-compiling,
# since the program itself never needs to be run (only the compiler/preprocessor)
try_run(
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/build/cmake_modules/Version.cmake
^
|
@@ -0,0 +1,16 @@
+# read version
+
+function(set_version version_file output_var)
+ file(READ "${version_file}" version_data)
+
+ string(REGEX MATCH "I2PD_VERSION_MAJOR ([0-9]*)" _ ${version_data})
+ set(version_major ${CMAKE_MATCH_1})
+
+ string(REGEX MATCH "I2PD_VERSION_MINOR ([0-9]*)" _ ${version_data})
+ set(version_minor ${CMAKE_MATCH_1})
+
+ string(REGEX MATCH "I2PD_VERSION_MICRO ([0-9]*)" _ ${version_data})
+ set(version_micro ${CMAKE_MATCH_1})
+
+ set(${output_var} "${version_major}.${version_minor}.${version_micro}" PARENT_SCOPE)
+endfunction()
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/apparmor/docker-i2pd
^
|
@@ -0,0 +1,42 @@
+# _________________________________________
+# / Copy this file to the right location \
+# | then load with: |
+# | |
+# | apparmor_parser -r -W |
+# | /etc/apparmor.d/docker-i2pd |
+# | |
+# | docker run --security-opt |
+# | "apparmor=docker-i2pd" ... |
+# | purplei2p/i2pd |
+# | |
+# \ And "aa-status" to verify it's loaded. /
+# -----------------------------------------
+# \ ^__^
+# \ (oo)\_______
+# (__)\ )\/\
+# ||----w |
+# || ||
+
+#include <tunables/global>
+
+profile docker-i2pd flags=(attach_disconnected,mediate_deleted) {
+ #include <abstractions/base>
+ #include <abstractions/openssl>
+ #include <abstractions/nameservice>
+
+ /bin/busybox ix,
+ /usr/local/bin/i2pd ix,
+ /entrypoint.sh ixr,
+
+ /i2pd_certificates/** r,
+
+ /home/i2pd/data/** rw,
+
+ /home/i2pd/data/i2pd.pid k,
+
+ deny /home/i2pd/data/i2pd.conf w,
+ deny /home/i2pd/data/tunnels.conf w,
+ deny /home/i2pd/data/tunnels.d/** w,
+ deny /home/i2pd/data/certificates/** w,
+ deny /home/i2pd/data/i2pd.log r,
+}
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/certificates/reseed/arnavbhatt288_at_mail.i2p.crt
^
|
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF2TCCA8GgAwIBAgIQIHQPtSoFU+cUpYD8PZaWZjANBgkqhkiG9w0BAQsFADB2
+MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
+ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEfMB0GA1UEAwwW
+YXJuYXZiaGF0dDI4OEBtYWlsLmkycDAeFw0yMzAxMjUxODUzNDFaFw0zMzAxMjUx
+ODUzNDFaMHYxCzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgx
+HjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMR8w
+HQYDVQQDDBZhcm5hdmJoYXR0Mjg4QG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAtwG73sC0jYd3fgEzZh0SveAdUd5yD35nINJRrdPSrSwY
+n3i1qGe3fNLj877PvUDU+qiHH0fFZfyFkXTaq3TUp1u4YkmvaoPHy6FZlojB08lK
+FBm+iJ1hifQ7MFmvIKUGv+cjlN6xSoQ0U6B2QOy6iZnBgFZ/7jbRY4iZOIj7VJtY
+aodeHfy0bWe447VJovbkUi7NJPFZQS65LMcAIWcWTxrC0Gj8SmdxL3a5+hxpmmg0
++KCQvWQDdxAQjsc16sgUCdUc6cWYO4yw9H6fgdq9GJX+LnXR9OB58GsAjjlLlFoI
+CZxdARDpoqcIj6AoKIanALf8yfbIyrqqJE47cuaqV9bht5MWKnXbwHplEkT4ZNkh
+PnRDia7B5HY3uwbt39CBm264PEWXvWG2sozTWKQqBjmMN2cj/NFDUEqKv6BggMY1
+HcqxWFKRcgKCtRvrmTmfp5l0/ou+OtUaFUg0a6Qhtb93Hj10vK6wZzidBqj0ggzB
+eJDI95b89u8JgzRoOBriuMKTc91WTkOvBLkB3dgUbUpx2p8KHjvf/pppBH9u0oxp
+qJFFK840DbnJydEvjKezeVe5Ax6YRSRxyEdKzRoWdvKVxb3qBBKMdCKTYEPxHPBu
+JMEQVUCXJMti++1KEiQGhcfWvLyT7OewbcIZNk9XWNrxlKcGrTp9AOwaaNC5m1kC
+AwEAAaNjMGEwDgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
+BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB8GA1UdDgQYBBZhcm5hdmJoYXR0Mjg4
+QG1haWwuaTJwMA0GCSqGSIb3DQEBCwUAA4ICAQAHiK0ld/1PF9DIhutD660/bzBg
+mF2Z76hcBqDZ8tnQai/u/RXYrH9wso9BYyrVsvk3fr6tpGT49Ian0MVpPOxMoTU2
+oBEmQlYrfclQLFsOLmA0y2r1ggXzIrt69jB710Vhwdnz09oOE8rS4E2T5oDD8Wvy
+Kony+AarRceqtkOlzyquc42KjzdrbHsosF7G2iGhNI6t+T3BfWJ+Q+d5sj3OIh6e
+gSfvHL44E4vZt6dtofRN3MAZ60kNLF5YWyaUo3Snv9Lso1IwIz3AVr5ehv+8sFL/
+KxaXdkZ5Yn2YUX7p1t4VQd+eXVPYjf1befg4PvrwSkylu3Jpee3fllZSKXeSVx9x
+jpJiq5vIakqk22pnWb1Vn7xzSW1vtEG7QLjobOr1WrcGiwdv+HKiWcXJXDzKoWXs
+h3VEfr51Kap8cIJv+D6lJIG9IcIhiQ6CXWBmtjWJvbdVwFBy1/3Fhaou9liHi+gK
+4Yh5a5OGCzc7xjtpGaTmoLEz7NzDNOdd/r840qRDOh70izzmFZd5Gwq4hoVcPJcS
+EAySwtgqK0/4d0zDd2Wg9ASJV9DnDf8QuSmHZgZ9Efs47XcWz9TvkWUS1E66AJsN
+mmI1NDQ3mv3dv5+WPq+dqqYFsnx3xWL1g5Z3buk0opeuXMzoHwM7UfN8h7Q1M5+t
++XBgkaYA4iEwYKqlCQ==
+-----END CERTIFICATE-----
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/certificates/reseed/igor_at_novg.net.crt
^
|
@@ -1,33 +1,33 @@
-----BEGIN CERTIFICATE-----
-MIIFvjCCA6agAwIBAgIQIDtv8tGMh0FyB2w5XjfZxTANBgkqhkiG9w0BAQsFADBt
+MIIFvjCCA6agAwIBAgIQBnsUOmOu2oZZIwHBmQc1BDANBgkqhkiG9w0BAQsFADBt
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwN
-aWdvckBub3ZnLm5ldDAeFw0xNzA3MjQxODI4NThaFw0yNzA3MjQxODI4NThaMG0x
+aWdvckBub3ZnLm5ldDAeFw0yMzAxMjgxNDM4MzFaFw0zMzAxMjgxNDM4MzFaMG0x
CzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxHjAcBgNVBAoT
FUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRYwFAYDVQQDDA1p
-Z29yQG5vdmcubmV0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxst4
-cam3YibBtQHGPCPX13uRQti56U3XZytSZntaKrUFmJxjt41Q/mOy3KYo+lBvhfDF
-x3tWKjgP9LJOJ28zvddFhZVNxqZRjcnAoPuSOVCw88g01D9OAasKF11hCfdxZP6h
-vGm8WCnjD8KPcYFxJC4HJUiFeProAwuTzEAESTRk4CAQe3Ie91JspuqoLUc5Qxlm
-w5QpjnjfZY4kaVHmZDKGIZDgNIt5v85bu4pWwZ6O+o90xQqjxvjyz/xccIec3sHw
-MHJ8h8ZKMokCKEJTaRWBvdeNXki7nf3gUy/3GjYQlzo0Nxk/Hw4svPcA+eL0AYiy
-Jn83bIB5VToW2zYUdV4u3qHeAhEg8Y7HI0kKcSUGm9AQXzbzP8YCHxi0sbb0GAJy
-f1Xf3XzoPfT64giD8ReUHhwKpyMB6uvG/NfWSZAzeAO/NT7DAwXpKIVQdkVdqy8b
-mvHvjf9/kWKOirA2Nygf3r79Vbg2mqbYC/b63XI9hheU689+O7qyhTEhNz+11X0d
-Zax7UPrLrwOeB9TNfEnztsmrHNdv2n+KcOO2o11Wvz2nHP9g+dgwoZSD1ZEpFzWP
-0sD5knKLwAL/64qLlAQ1feqW7hMr80IADcKjLSODkIDIIGm0ksXqEzTjz1JzbRDq
-jUjq7EAlkw3G69rv1gHxIntllJRQidAqecyWHOMCAwEAAaNaMFgwDgYDVR0PAQH/
+Z29yQG5vdmcubmV0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvLkf
+bM3uiYfp9m0vgdoftyXtk2/9bHf3u5iaM0WfoJIsw1iizo/mxJl+Iy7SxLC16nV0
+v5FpncVv+Z8x9dgoAYVuLq9zKfsAbpj6kuxAqw6vJMlD1TiIL3nSODV9BJLk47X5
+tmvoOSj9BgvemYThTE3nj+DbuJRW5q90KyBV/LdLrQJX3k5R3FFL5tTad2LKFNZ4
+vEOcYwwx6mvrkJ2lly6bAQUCtfc648Jyq+NO3Rba1fmn7gcP9zXXc5KYsj/ovyY2
+OaocSF5wMhzBuPxO+M2HqbYLMAkc6/GesGds8Rm8wofuhJoI5YtqJuLKZm6nQXSc
+fx6PKgbKcTIUWNFMsxyfghz9hpbg0rkvC7PtfAjtV0yaDtUum1eZeNEx1HbRWN2n
+TQNCVuv0yaKC41qxqzhEybkdjL9JlgUh7VuskaCelB0lz+kgYjGu8ezOa0ua2iKq
+4FC/1MbPulxN8NOt4pmbGqqoxmCdShp38wdnOBM3DsAS9f0JaQZd4CDyY4DCSfVn
+xPdWk31+VXVt3Ixh1EUqZWYTRSsZApkCyYzkiZ/qPGG6FR9Hq2SuhC5o4P44k7eo
+6wwBWD8a5RjsZhvr05E5yBrKXh/PjLwmtG73QC+ouR54/5xtedvdTwNS94FnNctX
+FT6QGZnRwCkhPaRe1oQMzP+88pGoCfO33GBAuwUCAwEAAaNaMFgwDgYDVR0PAQH/
BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8E
BTADAQH/MBYGA1UdDgQPBA1pZ29yQG5vdmcubmV0MA0GCSqGSIb3DQEBCwUAA4IC
-AQADyPaec28qc1HQtAV5dscJr47k92RTfvan+GEgIwyQDHZQm38eyTb05xipQCdk
-5ruUDFXLB5qXXFJKUbQM6IpaktmWDJqk4Zn+1nGbtFEbKgrF55pd63+NQer5QW9o
-3+dGj0eZJa3HX5EBkd2r7j2LFuB6uxv3r/xiTeHaaflCnsmyDLfb7axvYhyEzHQS
-AUi1bR+ln+dXewdtuojqc1+YmVGDgzWZK2T0oOz2E21CpZUDiP3wv9QfMaotLEal
-zECnbhS++q889inN3GB4kIoN6WpPpeYtTV+/r7FLv9+KUOV1s2z6mxIqC5wBFhZs
-0Sr1kVo8hB/EW/YYhDp99LoAOjIO6nn1h+qttfzBYr6C16j+8lGK2A12REJ4LiUQ
-cQI/0zTjt2C8Ns6ueNzMLQN1Mvmlg1Z8wIB7Az7jsIbY2zFJ0M5qR5VJveTj33K4
-4WSbC/zMWOBYHTVBvGmc6JGhu5ZUTZ+mWP7QfimGu+tdhvtrybFjE9ROIE/4yFr6
-GkxEyt0UY87TeKXJ/3KygvkMwdvqGWiZhItb807iy99+cySujtbGfF2ZXYGjBXVW
-dJOVRbyGQkHh6lrWHQM4ntBv4x+5QA+OAan5PBF3tcDx1vefPx+asYslbOXpzII5
-qhvoQxuRs6j5jsVFG6RdsKNeQAt87Mb2u2zK2ZakMdyD1w==
+AQCteAb5/bqhHr/i5CJbDzlofprXFC826c19GxQ/9Hw0kA52l0J9Q8Vz8Vy7VQyP
+QNa8MCv6FeNy8a/wXp6cafyFsBtvehVQO8lFlpCgMEl2Bma43+GaCwkrM6bFNXeW
+iQ9h4e1KjsUZ8cQDNEcamiJ80+xbMhBrj5bAZwKmZs8MoGEMyXKEZmcmwA+/fy1c
+cx4izsOsmRXmEHXsvB9ydJHZZeKW8+r0DAtgPslwXuXHG6MuBQo7dKCqn+iMxHXV
+Jxriq3yvNffdGx4maSLJrjQ1ealt/UMzql7huVSItnVFWoYf7GAELXNJ/PmqVyaK
+q11LQ8W/Aud6s/bblaJrFJnK8PbPpaw4RvHoWVLYaZYmQnV2msWs5EuESBlEADbv
+UklQXLMc2f9HKWPA5678nvYPrmu8IL5pMkAxgGRqmd+7vCz4lU9M5z3HObU+WRBt
+qEMYyXywV8o3tbmnlDS5S5Xxf+tLZn1cxz3ZrmcHPHDbLBNdvszF3CTJH/R2sQvD
+bizvYJM+p5F+GWM5mt6w0HrOut5MRlpOws/NRrkbijuVA/A45nzTtKplIFYE3qe8
+q5SAbwYLc8cJcZCN3PxtWwbEv81V33abMt5QcjnWGLH5t2+1Z2KLCgKLSCQTxM8s
+zBPHtUe8qtSQaElnNLILYbtJ1w67dPnGYTphHihC+CXjBg==
-----END CERTIFICATE-----
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/certificates/reseed/ls_at_mail.i2p.crt
^
|
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFdTCCA12gAwIBAgIEQ5vCxzANBgkqhkiG9w0BAQ0FADBrMQswCQYDVQQGEwJY
+WDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnlt
+b3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEUMBIGA1UEAwwLbHNAbWFpbC5pMnAw
+HhcNMjMxMDE2MjAwNTA5WhcNMzMxMDEzMjAwNTA5WjBrMQswCQYDVQQGEwJYWDEL
+MAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnltb3Vz
+IE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEUMBIGA1UEAwwLbHNAbWFpbC5pMnAwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDPcbKRtf4PzrDa0iRit0XrwnmA
+2c1fJhkBipdPor7gMOAlkR82H1lkZSizR7kTZnr7vYqjDrOQr7bl5Dy3qo8/YCbZ
+jsnUCTIIgIJQUxUlR40RjaSXphqzUEiXKHR6b0RahhFisQ3hlbbgzSch5YgSLKws
+hOLi+eDSXw+HlwHlWFlT1XOKxSTJ/F3Bv40gxqZVC2pbxiPOeRZHQ6Ojw75lxTSF
+gww2WzgztiWt4X9BO1yepnVqhAVRPmTfGUMfKzq9jkMzZKeQFV4uZSP9nCqzEpYd
+WNDUfpTWiAQ9F+BwFXGusXXA3tGVwS7s6IEoiJFM5fsoJYfRoWGh3/1eirhBXW7U
+M6oubMSTADyrvfjLfJBMmMnc2hNblRlKr0ZKUjMfv8cnyT4kQxlXLAHHXY2P89TM
+TEVODkU48gnv6tC4t1JCb1/Da+3yVMjNX6rCzQfUwnLFrWthrwiI0NivAKFtiZjq
+w1/ZQcYke2YyeqcfXMn+NTUA22Sm2mJoMo7jUf+rbM9Pi27/DncJgRGj5qwY0D3S
+gc7829EjuZNPttGBmae1EmO7WQMB32cqdmItnV2FXpMhnn9h0u5H52kYqwn+mdtc
+dTJRcbfKG1RTr3UjFISaTwL8qigMIkVXIzcpnr/R/sSeEs8xCqfsJ6rb4dCyFx+M
+hqQcOCL5tumyd4W/LQIDAQABoyEwHzAdBgNVHQ4EFgQUgfaOG5HCnlW82wZ5BahL
+GRO06igwDQYJKoZIhvcNAQENBQADggIBAKdVpqS9qF7gGotgXaVA1iP5YNsWlTvG
+daGqeA/87//U21W6gpq82FhzsmsvUtXZfIeVIlDPI7WNDzS+A3K/KKrwM7dLgSie
+r9eMl3D8WYPU95QF4mAlRyl7PCCsYoVjyvfro0iq3/iudIA5476rjfLdTXRi5hAT
+qemPj0S+6sRjKEldRtGXrQATFlvLIWVYpgHijdDDx5M2hAz2y0mFxlDZTlA4BhL4
+DwtGlVKmbc2x5MvIQM4UhbQqkxYS4gXnzf5Qx9QIytHfTr/hmbrkhKR1GCO31BSk
+x9LhZxdI8LlwKSo6YgwXEB9E0M/tplaK9iZJFv4HPYLZrVJpb4IklMumyLMrgW5P
+fR0dgKn+R9lk0emJ1Cu+qyyzf1vsLycYBwaEztINn4VK+/HfDFpnVCvJOyNuDmj5
+KBLIoGdGoVfylmnc+e8zAXe+DY41fgniHMISOO78P8Bx9vTB+rhqnOUr9MzlUxPB
+sKGjbXy2YynEqiGb+9g344v/+ukTSDenqTPHVzJ5uOi0iedy+3ASzUNN6GJocovP
+167VOhwaETM0FwiKe0VdZRLLbbZ79CtJC0tmgcgPQPRa9Ldr6KN7u1J3D6lUp6zl
+byPom10ueKONRb36t7ai79l2SEUZRSMkx6AXIU0JJ1SMtQtav7b5LkpYJfdL7+vO
+dDx2/Za0VmdD
+-----END CERTIFICATE-----
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/certificates/reseed/null_at_i2pmail.org.crt
^
|
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFyDCCA7CgAwIBAgIRAO8lBnTo+hlvglQwug2jHZkwDQYJKoZIhvcNAQELBQAw
+cDELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE
+ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGTAXBgNVBAMM
+EG51bGxAaTJwbWFpbC5vcmcwHhcNMjMwOTIxMjIzMTM2WhcNMzMwOTIxMjIzMTM2
+WjBwMQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYD
+VQQKExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEZMBcGA1UE
+AwwQbnVsbEBpMnBtYWlsLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAMMpAvaHwzuZZ6qelRU4jcgpuAIZFH++F1Te4b1t02pRfnQ0Eeh04VC1JxO0
+XjUr1/iszEyvrI4+AdxaobDyRFPylkOLtfec4d2ciDc1cupj6y2vyYhMVN31rrvE
+ve7sKoTHJ5Dx+UPGOVZZsSsmK9TXIU23W2bo7k2VnjVBXdWZyNE4twfTYCosDnYA
+1HIEaIUFVv+COqw2pktxkMmfUAlnDLeVSfsAzEr37K+x0Xk5hO8m6GWQx0NRjjYp
+gyEcFhWAJjAYaF3gUVR9rVVky1OeFhZgxE/KzVrW7uc84ZCMKITEPwT0qqIpsTJp
+486YXzuPSc+ef78cKSQf5992l7imySJ24I/5H73HkovGAFGZdwvl6V6Ta5YqO7RR
+gVDOL1EIVUnMCqFBCE6RmyZqXBVrv4Cacdc6lZ4fj42SRtWZfe6rNCpJzTRtbOyW
+DBmYpK6q/jddfqI1sX0PXIn9U+Rod5Z4uz82PAjhamqyr5fpAnoQxKppBvQ3tNfn
+KQhmP73Hdpvl24pRyQLBIRUL86i7TPBBn7n3XZlQfXP7lp8+KJYLkL2/zCVDrwLX
+kC9hRIxCU9bZbXlkRE2R/PrK53LZecjk2KcgINA4ZlguNgze/Qj8BXelUF4izbpV
+bTSvniTM46AECvjDcICAOky9Ku4RnmUJxQVf3ahDEuso7/N7AgMBAAGjXTBbMA4G
+A1UdDwEB/wQEAwIChDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDwYD
+VR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQbnVsbEBpMnBtYWlsLm9yZzANBgkqhkiG
+9w0BAQsFAAOCAgEAEUfYJTdDH7uCojnpF0Gs2tXxPJ22UhdqEsXfqR7KhhmmApss
+q5kiiPIYoy5T/4IM7NVyeeJAMYwQsdJjwZ4QyxLBb9EqMS2krREcPZNRfFzBr2Wj
+EBhJEYTnbIn4docwJWyXsJVG0CqFXPF1qGd0Sc2u87yj2xZNTnloWKAEQAO7DE39
+gWfDH6slM/3h3WD3Mjuk7JoYSYmBfvvm2hkBbC6lzD7XY7rdSmIUwJ050e9UrJaV
+La51dd5r4q8d1cHrVUwLiACAaXJ15AEqUDLHQcvKvyfhkabwRy+v0wsodSMgSMEH
+xA+kGhkIW7yV7o2exYOYypHCca3IA+pimMpEseNNrHSwbHOMfauiN7jiZLEPg6D6
+a8XwK7qmMYUq7j6QWuIqI81o29WZRf4LZ0GFoVce+e5VxkVKSItKcJoedIAp1ML8
+NhFwd9s/nqWidu/StscEEbGzz6ZuDXwshERXC0QR8HjHEPi4U8220juf4cxUahxK
+heEU91l7VksSZYRUN98h28vovGcukLcnVoLj5H/+Z4r/BgxMrOUJKetxf8fU7FjO
+j1U6XV36tGi+IOwYQb9D5fTVafC3hHkuUIjlOdUGYadse98ILhn9kaNtqkBtk/EU
+vK+McnrEv7tcKrbvYEop/KaUayhjFiL+wGWnpxt7gLhIiavnIeUyD7acltw=
+-----END CERTIFICATE-----
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/certificates/reseed/reheatedburger_at_protonmail.com.crt
^
|
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF7zCCA9egAwIBAgIRANVB/+wEuXS0Ttoh5teJt90wDQYJKoZIhvcNAQELBQAw
+fTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE
+ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxJjAkBgNVBAMM
+HXJlaGVhdGVkYnVyZ2VyQHByb3Rvbm1haWwuY29tMB4XDTIzMDkyMTE4MDAyOVoX
+DTMzMDkyMTE4MDAyOVowfTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYD
+VQQJEwJYWDEeMBwGA1UEChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQL
+EwNJMlAxJjAkBgNVBAMMHXJlaGVhdGVkYnVyZ2VyQHByb3Rvbm1haWwuY29tMIIC
+IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuNwmiIY3MLSBS5sL5PXRDVK6
+MoSNw4qx0o8nDHvVBxNtzgc0/qjYvsuUggY0tZbPpxhML6GHd4qo7Z3Ip1x0MxhI
+Ao5MJaflaEdm4+HeMy0IE3aU73KRUwp+nF3cUHZdlps+9mtYs4oncVEWkFQwGsgt
+4yrLtXf6PmPWfFH28ffeaev90e+hdhQpTvr54Ewx6NTaMQr8mkhXL2utvPpjnPM5
+UAhOeJCMgfhLzgS4rahG0O8CQMtH5gKZ+6zjoSRatnjj0j1mBO7+e1TL5O7dVS9k
+P83tmkIDDl4tXBzXr9aXQMJstbM2CEvinVcCsR74GjPcg4iB0Ift71Dx7oGKI06t
+3bSvll0GZm2mFhIba/4q6f4oAJ2aeq6ejt1Kcm8g5cxtwrRZnXv5JXHZqba3y8J5
+zWaRHzhc9tyEqRBRkc6c7xMdZQ31iJ6TlxUT8vAJ1N7OnX87oHrCjwyikpyOen4r
+Uvv1Ge054XPTeoHz+Jyt34t71ty1W13uPHpuvtPVR9MfgGrxd4Z9+LWvAjmMbFsZ
+lC3Ll+94nUk+O0puU6KisuCGP4hCtdEtebkIqT8zo8LicLAYUMjX7KwnS7681Cu1
+sY2mB2oZAytN9Zy42oOoNeY5x39kxfwuut/2E1kxKX75O0bwfIXr611abCKc3bbz
+euMrIsaB/2VFp9nAah8CAwEAAaNqMGgwDgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQW
+MBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCYGA1UdDgQf
+BB1yZWhlYXRlZGJ1cmdlckBwcm90b25tYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOC
+AgEATuHi2Yz52OK7e+sKVdHu2KrSLCGm98BG1UIMHFi3WRBTOFyp+lZ519bJ1rFj
+tmP9E1a+k/vlbc7FbV4PcV6HJYfGEv/ImtJsEnrzbhrQphC1zMFv7q6JCTUbAzl6
+ySlJ++mVxQ6AzPNH3TQgL1wPKuLh76/Y4053fg+NI3PmzzhkTUheVDkg0/a9ENSf
+xMnCa3fIm869735qHk67QlikFvAfWwc4zT1Ncwodh8G4+oX0GFzIl+OZaM1GTMuD
+UCcFKoqwtjyLCr22xNk8CfyiExPJXQG1HzEvDcxyoxQtnh9occR9PgqXySz26/NM
+XDyM+l4utLMGBcVY4x9fksRiaWEfxiygYOxY9zDl6clh6S10b3CLut4UMiS1RTtE
+Mjx2BZN3p0nxpT2leJdGxtBPGrvxuiCOEmTbOMLc3DQtppXO97B3dVMtJ5Ee8Y6p
+Tq/8eiHI6eQXat6dgFT5X16vzF7w7XO7fAxuqk4Kx1D1aTVyikdo+Fcdg44dWOjq
+NZu8VcCzZij/Dfjlce6t6h8D+wvDD8AkiivaDljpvbNDx/QQlQXFgH98TZA8Rnvr
+QcyNNATfz+1yQUiyO6Lrjaw64OJwXYX/llgnDC+qQpP6kqZabi2TsG0EVPukVvr9
+0HyAUu4lnXtTIDq2yPNenegCloqDL1ZQdaYd2XIItnfZdTY=
+-----END CERTIFICATE-----
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/README
^
|
@@ -1,2 +1,5 @@
-This forder contain systemd unit files.
-To use systemd daemon control, place files from this directory to debian folder before building package.
+This forder contain files required for building debian packages.
+
+The trunk repository is contains the packaging files for the latest stable version of Debian (if we not forgot to update them).
+
+Files in subdirectories contains fixes to make possible to build package on specific versions of Debian/Ubuntu. They are used when building the release package.
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/bionic/compat
^
|
@@ -0,0 +1 @@
+11
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/bionic/control
^
|
@@ -0,0 +1,18 @@
+Source: i2pd
+Section: net
+Priority: optional
+Maintainer: r4sas <r4sas@i2pmail.org>
+Build-Depends: debhelper (>= 11~), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev
+Standards-Version: 4.2.0
+Homepage: http://i2pd.website/
+Vcs-Git: git://github.com/PurpleI2P/i2pd.git
+Vcs-Browser: https://github.com/PurpleI2P/i2pd
+
+Package: i2pd
+Architecture: any
+Pre-Depends: ${misc:Pre-Depends}, adduser
+Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base,
+Description: Full-featured C++ implementation of I2P client.
+ I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
+ communications over I2P are anonymous and end-to-end encrypted, participants
+ don't reveal their real IP addresses.
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/trusty/compat
^
|
@@ -0,0 +1 @@
+9
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/trusty/control
^
|
@@ -0,0 +1,18 @@
+Source: i2pd
+Section: net
+Priority: optional
+Maintainer: r4sas <r4sas@i2pmail.org>
+Build-Depends: debhelper (>= 9), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev
+Standards-Version: 3.9.8
+Homepage: http://i2pd.website/
+Vcs-Git: git://github.com/PurpleI2P/i2pd.git
+Vcs-Browser: https://github.com/PurpleI2P/i2pd
+
+Package: i2pd
+Architecture: any
+Pre-Depends: ${misc:Pre-Depends}, adduser
+Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base,
+Description: Full-featured C++ implementation of I2P client.
+ I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
+ communications over I2P are anonymous and end-to-end encrypted, participants
+ don't reveal their real IP addresses.
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/trusty/patches/01-upnp.patch
^
|
(renamed from upstream/debian/patches/02-upnp.patch)
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/trusty/patches/02-service.patch
^
|
@@ -0,0 +1,19 @@
+Description: Disable LogsDirectory and LogsDirectoryMode options in service
+Author: r4sas <r4sas@i2pmail.org>
+
+Reviewed-By: r4sas <r4sas@i2pmail.org>
+Last-Update: 2023-05-17
+
+--- a/contrib/i2pd.service
++++ b/contrib/i2pd.service
+@@ -8,8 +8,8 @@ User=i2pd
+ Group=i2pd
+ RuntimeDirectory=i2pd
+ RuntimeDirectoryMode=0700
+-LogsDirectory=i2pd
+-LogsDirectoryMode=0700
++#LogsDirectory=i2pd
++#LogsDirectoryMode=0700
+ Type=forking
+ ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
+ ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/trusty/patches/series
^
|
@@ -0,0 +1,2 @@
+01-upnp.patch
+02-service.patch
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/trusty/rules
^
|
@@ -0,0 +1,18 @@
+#!/usr/bin/make -f
+#export DH_VERBOSE=1
+
+export DEB_BUILD_MAINT_OPTIONS=hardening=+all
+
+include /usr/share/dpkg/architecture.mk
+
+ifeq ($(DEB_HOST_ARCH),i386)
+ export DEB_BUILD_OPTIONS=parallel=1
+endif
+
+export DEB_CXXFLAGS_MAINT_APPEND=-Wall -pedantic
+export DEB_LDFLAGS_MAINT_APPEND=
+
+%:
+ dh $@ --parallel
+
+override_dh_auto_install:
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/xenial/compat
^
|
@@ -0,0 +1 @@
+9
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/xenial/control
^
|
@@ -0,0 +1,18 @@
+Source: i2pd
+Section: net
+Priority: optional
+Maintainer: r4sas <r4sas@i2pmail.org>
+Build-Depends: debhelper (>= 9), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev
+Standards-Version: 3.9.8
+Homepage: http://i2pd.website/
+Vcs-Git: git://github.com/PurpleI2P/i2pd.git
+Vcs-Browser: https://github.com/PurpleI2P/i2pd
+
+Package: i2pd
+Architecture: any
+Pre-Depends: ${misc:Pre-Depends}, adduser
+Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base,
+Description: Full-featured C++ implementation of I2P client.
+ I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
+ communications over I2P are anonymous and end-to-end encrypted, participants
+ don't reveal their real IP addresses.
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/xenial/patches/01-upnp.patch
^
|
@@ -0,0 +1,17 @@
+Description: Enable UPnP usage in package
+Author: r4sas <r4sas@i2pmail.org>
+
+Reviewed-By: r4sas <r4sas@i2pmail.org>
+Last-Update: 2022-03-23
+
+--- i2pd.orig/Makefile
++++ i2pd/Makefile
+@@ -31,7 +31,7 @@ include filelist.mk
+
+ USE_AESNI := $(or $(USE_AESNI),yes)
+ USE_STATIC := $(or $(USE_STATIC),no)
+-USE_UPNP := $(or $(USE_UPNP),no)
++USE_UPNP := $(or $(USE_UPNP),yes)
+ DEBUG := $(or $(DEBUG),yes)
+
+ # for debugging purposes only, when commit hash needed in trunk builds in i2pd version string
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/xenial/patches/02-service.patch
^
|
@@ -0,0 +1,19 @@
+Description: Disable LogsDirectory and LogsDirectoryMode options in service
+Author: r4sas <r4sas@i2pmail.org>
+
+Reviewed-By: r4sas <r4sas@i2pmail.org>
+Last-Update: 2023-05-17
+
+--- a/contrib/i2pd.service
++++ b/contrib/i2pd.service
+@@ -8,8 +8,8 @@ User=i2pd
+ Group=i2pd
+ RuntimeDirectory=i2pd
+ RuntimeDirectoryMode=0700
+-LogsDirectory=i2pd
+-LogsDirectoryMode=0700
++#LogsDirectory=i2pd
++#LogsDirectoryMode=0700
+ Type=forking
+ ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
+ ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/xenial/patches/series
^
|
@@ -0,0 +1,2 @@
+01-upnp.patch
+02-service.patch
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/debian/xenial/rules
^
|
@@ -0,0 +1,13 @@
+#!/usr/bin/make -f
+#export DH_VERBOSE=1
+export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+
+include /usr/share/dpkg/architecture.mk
+
+export DEB_CXXFLAGS_MAINT_APPEND = -Wall -pedantic
+export DEB_LDFLAGS_MAINT_APPEND =
+
+%:
+ dh $@ --parallel
+
+override_dh_auto_install:
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/dinit/i2pd
^
|
@@ -0,0 +1,8 @@
+type = bgprocess
+run-as = i2pd
+command = /usr/bin/i2pd --conf=/var/lib/i2pd/i2pd.conf --pidfile=/var/lib/i2pd/i2pd.pid --daemon --service
+smooth-recovery = true
+depends-on = ntpd
+# uncomment if you want to use i2pd with yggdrasil
+# depends-on = yggdrasil
+pid-file = /var/lib/i2pd/i2pd.pid
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/docker/Dockerfile
^
|
@@ -1,5 +1,18 @@
+#
+# Copyright (c) 2017-2022, The PurpleI2P Project
+#
+# This file is part of Purple i2pd project and licensed under BSD3
+#
+# See full license text in LICENSE file at top of project tree
+#
+
FROM alpine:latest
-LABEL authors "Mikal Villa <mikal@sigterm.no>, Darknet Villain <supervillain@riseup.net>"
+LABEL authors="Mikal Villa <mikal@sigterm.no>, Darknet Villain <supervillain@riseup.net>"
+LABEL maintainer="R4SAS <r4sas@i2pmail.org>"
+
+LABEL org.opencontainers.image.source=https://github.com/PurpleI2P/i2pd
+LABEL org.opencontainers.image.documentation=https://i2pd.readthedocs.io/en/latest/
+LABEL org.opencontainers.image.licenses=BSD3
# Expose git branch, tag and URL variables as arguments
ARG GIT_BRANCH="openssl"
@@ -11,27 +24,28 @@
ENV I2PD_HOME="/home/i2pd"
ENV DATA_DIR="${I2PD_HOME}/data"
-ENV DEFAULT_ARGS=" --datadir=$DATA_DIR --reseed.verify=true --upnp.enabled=false --http.enabled=true --http.address=0.0.0.0 --httpproxy.enabled=true --httpproxy.address=0.0.0.0 --socksproxy.enabled=true --socksproxy.address=0.0.0.0 --sam.enabled=true --sam.address=0.0.0.0"
+ENV DEFAULT_ARGS=" --datadir=$DATA_DIR"
RUN mkdir -p "$I2PD_HOME" "$DATA_DIR" \
&& adduser -S -h "$I2PD_HOME" i2pd \
&& chown -R i2pd:nobody "$I2PD_HOME"
+
+# 1. Building binary
+# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the
+# image under 20mb we need to remove all the build dependencies in the same "RUN" / layer.
#
-# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the
-# image under 20mb we need to remove all the build dependencies in the same "RUN" / layer.
-#
+# 1. install deps, clone and build.
+# 2. strip binaries.
+# 3. Purge all dependencies and other unrelated packages, including build directory.
-# 1. install deps, clone and build.
-# 2. strip binaries.
-# 3. Purge all dependencies and other unrelated packages, including build directory.
RUN apk update \
&& apk --no-cache --virtual build-dependendencies add make gcc g++ libtool zlib-dev boost-dev build-base openssl-dev openssl miniupnpc-dev git \
&& mkdir -p /tmp/build \
&& cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \
&& cd i2pd \
&& if [ -n "${GIT_TAG}" ]; then git checkout tags/${GIT_TAG}; fi \
- && make USE_UPNP=yes \
+ && make -j$(nproc) USE_UPNP=yes \
&& cp -R contrib/certificates /i2pd_certificates \
&& mkdir -p /usr/local/bin \
&& mv i2pd /usr/local/bin \
@@ -45,6 +59,9 @@
# 2. Adding required libraries to run i2pd to ensure it will run.
RUN apk --no-cache add boost-filesystem boost-system boost-program_options boost-date_time boost-thread boost-iostreams openssl miniupnpc musl-utils libstdc++
+# 3. Copy preconfigured config file and entrypoint
+COPY i2pd-docker.conf "$DATA_DIR/i2pd.conf"
+RUN chown i2pd:nobody "$DATA_DIR/i2pd.conf"
COPY entrypoint.sh /entrypoint.sh
RUN chmod a+x /entrypoint.sh
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/docker/i2pd-docker.conf
^
|
@@ -0,0 +1,52 @@
+## Preconfigured i2pd configuration file for a Docker container
+## See https://i2pd.readthedocs.io/en/latest/user-guide/configuration/
+## for more options you can use in this file.
+
+## Note that for exposing ports outside of container you need to bind all services to 0.0.0.0
+
+log = file
+loglevel = none
+
+ipv4 = true
+ipv6 = false
+
+# bandwidth = L
+# notransit = false
+# floodfill = false
+
+[ntcp2]
+enabled = true
+published = true
+
+[ssu2]
+enabled = true
+published = true
+
+[http]
+enabled = true
+address = 0.0.0.0
+port = 7070
+
+[httpproxy]
+enabled = true
+address = 0.0.0.0
+port = 4444
+
+[socksproxy]
+enabled = true
+address = 0.0.0.0
+port = 4447
+
+[sam]
+enabled = true
+address = 0.0.0.0
+port = 7656
+
+[upnp]
+enabled = false
+
+[reseed]
+verify = true
+
+[limits]
+# transittunnels = 2500
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/i18n/English.po
^
|
@@ -1,13 +1,13 @@
# i2pd
-# Copyright (C) 2021-2022 PurpleI2P team
+# Copyright (C) 2021-2023 PurpleI2P team
# This file is distributed under the same license as the i2pd package.
-# R4SAS <r4sas@i2pmail.org>, 2021-2022.
+# R4SAS <r4sas@i2pmail.org>, 2021-2023.
#
msgid ""
msgstr ""
"Project-Id-Version: i2pd\n"
"Report-Msgid-Bugs-To: https://github.com/PurpleI2P/i2pd/issues\n"
-"POT-Creation-Date: 2022-07-26 21:22\n"
+"POT-Creation-Date: 2023-06-10 01:25\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -18,66 +18,73 @@
"X-Poedit-SearchPath-0: daemon/HTTPServer.cpp\n"
"X-Poedit-SearchPath-1: libi2pd_client/HTTPProxy.cpp\n"
-#: daemon/HTTPServer.cpp:108
-msgid "day"
-msgid_plural "days"
+#: daemon/HTTPServer.cpp:107
+#, c-format
+msgid "%d day"
+msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
-#: daemon/HTTPServer.cpp:112
-msgid "hour"
-msgid_plural "hours"
+#: daemon/HTTPServer.cpp:111
+#, c-format
+msgid "%d hour"
+msgid_plural "%d hours"
msgstr[0] ""
msgstr[1] ""
-#: daemon/HTTPServer.cpp:116
-msgid "minute"
-msgid_plural "minutes"
+#: daemon/HTTPServer.cpp:115
+#, c-format
+msgid "%d minute"
+msgid_plural "%d minutes"
msgstr[0] ""
msgstr[1] ""
-#: daemon/HTTPServer.cpp:119
-msgid "second"
-msgid_plural "seconds"
+#: daemon/HTTPServer.cpp:118
+#, c-format
+msgid "%d second"
+msgid_plural "%d seconds"
msgstr[0] ""
msgstr[1] ""
-#. tr: Kibibit
-#: daemon/HTTPServer.cpp:127 daemon/HTTPServer.cpp:155
-msgid "KiB"
+#. tr: Kibibyte
+#: daemon/HTTPServer.cpp:126
+#, c-format
+msgid "%.2f KiB"
msgstr ""
-#. tr: Mebibit
-#: daemon/HTTPServer.cpp:129
-msgid "MiB"
+#. tr: Mebibyte
+#: daemon/HTTPServer.cpp:128
+#, c-format
+msgid "%.2f MiB"
msgstr ""
-#. tr: Gibibit
-#: daemon/HTTPServer.cpp:131
-msgid "GiB"
+#. tr: Gibibyte
+#: daemon/HTTPServer.cpp:130
+#, c-format
+msgid "%.2f GiB"
msgstr ""
-#: daemon/HTTPServer.cpp:148
+#: daemon/HTTPServer.cpp:147
msgid "building"
msgstr ""
-#: daemon/HTTPServer.cpp:149
+#: daemon/HTTPServer.cpp:148
msgid "failed"
msgstr ""
-#: daemon/HTTPServer.cpp:150
+#: daemon/HTTPServer.cpp:149
msgid "expiring"
msgstr ""
-#: daemon/HTTPServer.cpp:151
+#: daemon/HTTPServer.cpp:150
msgid "established"
msgstr ""
-#: daemon/HTTPServer.cpp:152
+#: daemon/HTTPServer.cpp:151
msgid "unknown"
msgstr ""
-#: daemon/HTTPServer.cpp:154
+#: daemon/HTTPServer.cpp:153
msgid "exploratory"
msgstr ""
@@ -94,32 +101,32 @@
msgid "Main page"
msgstr ""
-#: daemon/HTTPServer.cpp:194 daemon/HTTPServer.cpp:700
+#: daemon/HTTPServer.cpp:194 daemon/HTTPServer.cpp:742
msgid "Router commands"
msgstr ""
-#: daemon/HTTPServer.cpp:195 daemon/HTTPServer.cpp:382
-#: daemon/HTTPServer.cpp:394
+#: daemon/HTTPServer.cpp:195 daemon/HTTPServer.cpp:395
+#: daemon/HTTPServer.cpp:407
msgid "Local Destinations"
msgstr ""
-#: daemon/HTTPServer.cpp:197 daemon/HTTPServer.cpp:352
-#: daemon/HTTPServer.cpp:438 daemon/HTTPServer.cpp:444
-#: daemon/HTTPServer.cpp:597 daemon/HTTPServer.cpp:640
-#: daemon/HTTPServer.cpp:644
+#: daemon/HTTPServer.cpp:197 daemon/HTTPServer.cpp:365
+#: daemon/HTTPServer.cpp:454 daemon/HTTPServer.cpp:474
+#: daemon/HTTPServer.cpp:636 daemon/HTTPServer.cpp:682
+#: daemon/HTTPServer.cpp:686
msgid "LeaseSets"
msgstr ""
-#: daemon/HTTPServer.cpp:199 daemon/HTTPServer.cpp:650
+#: daemon/HTTPServer.cpp:199 daemon/HTTPServer.cpp:692
msgid "Tunnels"
msgstr ""
-#: daemon/HTTPServer.cpp:201 daemon/HTTPServer.cpp:359
-#: daemon/HTTPServer.cpp:770 daemon/HTTPServer.cpp:786
+#: daemon/HTTPServer.cpp:201 daemon/HTTPServer.cpp:372
+#: daemon/HTTPServer.cpp:813 daemon/HTTPServer.cpp:830
msgid "Transit Tunnels"
msgstr ""
-#: daemon/HTTPServer.cpp:203 daemon/HTTPServer.cpp:839
+#: daemon/HTTPServer.cpp:203 daemon/HTTPServer.cpp:898
msgid "Transports"
msgstr ""
@@ -127,15 +134,16 @@
msgid "I2P tunnels"
msgstr ""
-#: daemon/HTTPServer.cpp:206 daemon/HTTPServer.cpp:908
-#: daemon/HTTPServer.cpp:918
+#: daemon/HTTPServer.cpp:206 daemon/HTTPServer.cpp:927
+#: daemon/HTTPServer.cpp:937
msgid "SAM sessions"
msgstr ""
-#: daemon/HTTPServer.cpp:222 daemon/HTTPServer.cpp:1302
-#: daemon/HTTPServer.cpp:1305 daemon/HTTPServer.cpp:1308
-#: daemon/HTTPServer.cpp:1322 daemon/HTTPServer.cpp:1367
-#: daemon/HTTPServer.cpp:1370 daemon/HTTPServer.cpp:1373
+#: daemon/HTTPServer.cpp:222 daemon/HTTPServer.cpp:1329
+#: daemon/HTTPServer.cpp:1332 daemon/HTTPServer.cpp:1335
+#: daemon/HTTPServer.cpp:1362 daemon/HTTPServer.cpp:1365
+#: daemon/HTTPServer.cpp:1379 daemon/HTTPServer.cpp:1424
+#: daemon/HTTPServer.cpp:1427 daemon/HTTPServer.cpp:1430
msgid "ERROR"
msgstr ""
@@ -151,14 +159,14 @@
msgid "Firewalled"
msgstr ""
-#: daemon/HTTPServer.cpp:232 daemon/HTTPServer.cpp:253
-#: daemon/HTTPServer.cpp:325
+#: daemon/HTTPServer.cpp:232 daemon/HTTPServer.cpp:235
+#: daemon/HTTPServer.cpp:336
msgid "Unknown"
msgstr ""
-#: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:369
-#: daemon/HTTPServer.cpp:370 daemon/HTTPServer.cpp:976
-#: daemon/HTTPServer.cpp:985
+#: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:382
+#: daemon/HTTPServer.cpp:383 daemon/HTTPServer.cpp:1003
+#: daemon/HTTPServer.cpp:1011
msgid "Proxy"
msgstr ""
@@ -166,564 +174,610 @@
msgid "Mesh"
msgstr ""
-#: daemon/HTTPServer.cpp:237
-msgid "Error"
-msgstr ""
-
-#: daemon/HTTPServer.cpp:241
+#: daemon/HTTPServer.cpp:242
msgid "Clock skew"
msgstr ""
-#: daemon/HTTPServer.cpp:244
+#: daemon/HTTPServer.cpp:245
msgid "Offline"
msgstr ""
-#: daemon/HTTPServer.cpp:247
+#: daemon/HTTPServer.cpp:248
msgid "Symmetric NAT"
msgstr ""
-#: daemon/HTTPServer.cpp:259
+#: daemon/HTTPServer.cpp:251
+msgid "Full cone NAT"
+msgstr ""
+
+#: daemon/HTTPServer.cpp:254
+msgid "No Descriptors"
+msgstr ""
+
+#: daemon/HTTPServer.cpp:263
msgid "Uptime"
msgstr ""
-#: daemon/HTTPServer.cpp:262
+#: daemon/HTTPServer.cpp:266
msgid "Network status"
msgstr ""
-#: daemon/HTTPServer.cpp:267
+#: daemon/HTTPServer.cpp:271
msgid "Network status v6"
msgstr ""
-#: daemon/HTTPServer.cpp:273 daemon/HTTPServer.cpp:280
+#: daemon/HTTPServer.cpp:277 daemon/HTTPServer.cpp:284
msgid "Stopping in"
msgstr ""
-#: daemon/HTTPServer.cpp:287
+#: daemon/HTTPServer.cpp:291
msgid "Family"
msgstr ""
-#: daemon/HTTPServer.cpp:288
+#: daemon/HTTPServer.cpp:292
msgid "Tunnel creation success rate"
msgstr ""
-#: daemon/HTTPServer.cpp:289
+#: daemon/HTTPServer.cpp:296
+msgid "Total tunnel creation success rate"
+msgstr ""
+
+#: daemon/HTTPServer.cpp:298
msgid "Received"
msgstr ""
-#. tr: Kibibit/s
-#: daemon/HTTPServer.cpp:291 daemon/HTTPServer.cpp:294
-#: daemon/HTTPServer.cpp:297
-msgid "KiB/s"
+#. tr: Kibibyte/s
+#: daemon/HTTPServer.cpp:300 daemon/HTTPServer.cpp:303
+#: daemon/HTTPServer.cpp:306
+#, c-format
+msgid "%.2f KiB/s"
msgstr ""
-#: daemon/HTTPServer.cpp:292
+#: daemon/HTTPServer.cpp:301
msgid "Sent"
msgstr ""
-#: daemon/HTTPServer.cpp:295
+#: daemon/HTTPServer.cpp:304
msgid "Transit"
msgstr ""
-#: daemon/HTTPServer.cpp:298
+#: daemon/HTTPServer.cpp:307
msgid "Data path"
msgstr ""
-#: daemon/HTTPServer.cpp:301
+#: daemon/HTTPServer.cpp:310
msgid "Hidden content. Press on text to see."
msgstr ""
-#: daemon/HTTPServer.cpp:304
+#: daemon/HTTPServer.cpp:314
msgid "Router Ident"
msgstr ""
-#: daemon/HTTPServer.cpp:306
+#: daemon/HTTPServer.cpp:316
msgid "Router Family"
msgstr ""
-#: daemon/HTTPServer.cpp:307
+#: daemon/HTTPServer.cpp:317
msgid "Router Caps"
msgstr ""
-#: daemon/HTTPServer.cpp:308
+#: daemon/HTTPServer.cpp:318
msgid "Version"
msgstr ""
-#: daemon/HTTPServer.cpp:309
+#: daemon/HTTPServer.cpp:319
msgid "Our external address"
msgstr ""
-#: daemon/HTTPServer.cpp:337
+#. tr: Shown when router doesn't publish itself and have "Firewalled" state
+#: daemon/HTTPServer.cpp:349
msgid "supported"
msgstr ""
-#: daemon/HTTPServer.cpp:350
+#: daemon/HTTPServer.cpp:363
msgid "Routers"
msgstr ""
-#: daemon/HTTPServer.cpp:351
+#: daemon/HTTPServer.cpp:364
msgid "Floodfills"
msgstr ""
-#: daemon/HTTPServer.cpp:358 daemon/HTTPServer.cpp:962
+#: daemon/HTTPServer.cpp:371 daemon/HTTPServer.cpp:987
msgid "Client Tunnels"
msgstr ""
-#: daemon/HTTPServer.cpp:368
+#: daemon/HTTPServer.cpp:381
msgid "Services"
msgstr ""
-#: daemon/HTTPServer.cpp:369 daemon/HTTPServer.cpp:370
-#: daemon/HTTPServer.cpp:371 daemon/HTTPServer.cpp:372
-#: daemon/HTTPServer.cpp:373 daemon/HTTPServer.cpp:374
+#: daemon/HTTPServer.cpp:382 daemon/HTTPServer.cpp:383
+#: daemon/HTTPServer.cpp:384 daemon/HTTPServer.cpp:385
+#: daemon/HTTPServer.cpp:386 daemon/HTTPServer.cpp:387
msgid "Enabled"
msgstr ""
-#: daemon/HTTPServer.cpp:369 daemon/HTTPServer.cpp:370
-#: daemon/HTTPServer.cpp:371 daemon/HTTPServer.cpp:372
-#: daemon/HTTPServer.cpp:373 daemon/HTTPServer.cpp:374
+#: daemon/HTTPServer.cpp:382 daemon/HTTPServer.cpp:383
+#: daemon/HTTPServer.cpp:384 daemon/HTTPServer.cpp:385
+#: daemon/HTTPServer.cpp:386 daemon/HTTPServer.cpp:387
msgid "Disabled"
msgstr ""
-#: daemon/HTTPServer.cpp:417
+#: daemon/HTTPServer.cpp:434
msgid "Encrypted B33 address"
msgstr ""
-#: daemon/HTTPServer.cpp:426
+#: daemon/HTTPServer.cpp:442
msgid "Address registration line"
msgstr ""
-#: daemon/HTTPServer.cpp:431
+#: daemon/HTTPServer.cpp:447
msgid "Domain"
msgstr ""
-#: daemon/HTTPServer.cpp:432
+#: daemon/HTTPServer.cpp:448
msgid "Generate"
msgstr ""
-#: daemon/HTTPServer.cpp:433
+#: daemon/HTTPServer.cpp:449
msgid ""
"<b>Note:</b> result string can be used only for registering 2LD domains "
"(example.i2p). For registering subdomains please use i2pd-tools."
msgstr ""
-#: daemon/HTTPServer.cpp:439
+#: daemon/HTTPServer.cpp:457
msgid "Address"
msgstr ""
-#: daemon/HTTPServer.cpp:439
+#: daemon/HTTPServer.cpp:459
msgid "Type"
msgstr ""
-#: daemon/HTTPServer.cpp:439
+#: daemon/HTTPServer.cpp:460
msgid "EncType"
msgstr ""
-#: daemon/HTTPServer.cpp:449 daemon/HTTPServer.cpp:655
+#: daemon/HTTPServer.cpp:467
+msgid "Expire LeaseSet"
+msgstr ""
+
+#: daemon/HTTPServer.cpp:479 daemon/HTTPServer.cpp:697
msgid "Inbound tunnels"
msgstr ""
#. tr: Milliseconds
-#: daemon/HTTPServer.cpp:464 daemon/HTTPServer.cpp:484
-#: daemon/HTTPServer.cpp:669 daemon/HTTPServer.cpp:689
-msgid "ms"
+#: daemon/HTTPServer.cpp:494 daemon/HTTPServer.cpp:514
+#: daemon/HTTPServer.cpp:711 daemon/HTTPServer.cpp:731
+#, c-format
+msgid "%dms"
msgstr ""
-#: daemon/HTTPServer.cpp:469 daemon/HTTPServer.cpp:674
+#: daemon/HTTPServer.cpp:499 daemon/HTTPServer.cpp:716
msgid "Outbound tunnels"
msgstr ""
-#: daemon/HTTPServer.cpp:491
+#: daemon/HTTPServer.cpp:521
msgid "Tags"
msgstr ""
-#: daemon/HTTPServer.cpp:491
+#: daemon/HTTPServer.cpp:522
msgid "Incoming"
msgstr ""
-#: daemon/HTTPServer.cpp:498 daemon/HTTPServer.cpp:501
+#: daemon/HTTPServer.cpp:529 daemon/HTTPServer.cpp:535
msgid "Outgoing"
msgstr ""
-#: daemon/HTTPServer.cpp:499 daemon/HTTPServer.cpp:515
+#: daemon/HTTPServer.cpp:532 daemon/HTTPServer.cpp:551
msgid "Destination"
msgstr ""
-#: daemon/HTTPServer.cpp:499
+#: daemon/HTTPServer.cpp:532 daemon/HTTPServer.cpp:814
msgid "Amount"
msgstr ""
-#: daemon/HTTPServer.cpp:506
+#: daemon/HTTPServer.cpp:540
msgid "Incoming Tags"
msgstr ""
-#: daemon/HTTPServer.cpp:514 daemon/HTTPServer.cpp:517
+#: daemon/HTTPServer.cpp:548 daemon/HTTPServer.cpp:554
msgid "Tags sessions"
msgstr ""
-#: daemon/HTTPServer.cpp:515
+#: daemon/HTTPServer.cpp:551
msgid "Status"
msgstr ""
-#: daemon/HTTPServer.cpp:524 daemon/HTTPServer.cpp:582
+#: daemon/HTTPServer.cpp:561 daemon/HTTPServer.cpp:621
msgid "Local Destination"
msgstr ""
-#: daemon/HTTPServer.cpp:535 daemon/HTTPServer.cpp:941
+#: daemon/HTTPServer.cpp:572 daemon/HTTPServer.cpp:960
msgid "Streams"
msgstr ""
-#: daemon/HTTPServer.cpp:558
+#: daemon/HTTPServer.cpp:595
msgid "Close stream"
msgstr ""
-#: daemon/HTTPServer.cpp:587
+#: daemon/HTTPServer.cpp:613 daemon/HTTPServer.cpp:1430
+msgid "Such destination is not found"
+msgstr ""
+
+#: daemon/HTTPServer.cpp:626
msgid "I2CP session not found"
msgstr ""
-#: daemon/HTTPServer.cpp:590
+#: daemon/HTTPServer.cpp:629
msgid "I2CP is not enabled"
msgstr ""
-#: daemon/HTTPServer.cpp:616
+#: daemon/HTTPServer.cpp:658
msgid "Invalid"
msgstr ""
-#: daemon/HTTPServer.cpp:619
+#: daemon/HTTPServer.cpp:661
msgid "Store type"
msgstr ""
-#: daemon/HTTPServer.cpp:620
+#: daemon/HTTPServer.cpp:662
msgid "Expires"
msgstr ""
-#: daemon/HTTPServer.cpp:625
+#: daemon/HTTPServer.cpp:667
msgid "Non Expired Leases"
msgstr ""
-#: daemon/HTTPServer.cpp:628
+#: daemon/HTTPServer.cpp:670
msgid "Gateway"
msgstr ""
-#: daemon/HTTPServer.cpp:629
+#: daemon/HTTPServer.cpp:671
msgid "TunnelID"
msgstr ""
-#: daemon/HTTPServer.cpp:630
+#: daemon/HTTPServer.cpp:672
msgid "EndDate"
msgstr ""
-#: daemon/HTTPServer.cpp:640
-msgid "not floodfill"
+#: daemon/HTTPServer.cpp:682
+msgid "floodfill mode is disabled"
msgstr ""
-#: daemon/HTTPServer.cpp:651
+#: daemon/HTTPServer.cpp:693
msgid "Queue size"
msgstr ""
-#: daemon/HTTPServer.cpp:701
+#: daemon/HTTPServer.cpp:743
msgid "Run peer test"
msgstr ""
-#: daemon/HTTPServer.cpp:706
+#: daemon/HTTPServer.cpp:744
+msgid "Reload tunnels configuration"
+msgstr ""
+
+#: daemon/HTTPServer.cpp:747
msgid "Decline transit tunnels"
msgstr ""
-#: daemon/HTTPServer.cpp:708
+#: daemon/HTTPServer.cpp:749
msgid "Accept transit tunnels"
msgstr ""
-#: daemon/HTTPServer.cpp:712 daemon/HTTPServer.cpp:717
+#: daemon/HTTPServer.cpp:753 daemon/HTTPServer.cpp:758
msgid "Cancel graceful shutdown"
msgstr ""
-#: daemon/HTTPServer.cpp:714 daemon/HTTPServer.cpp:719
+#: daemon/HTTPServer.cpp:755 daemon/HTTPServer.cpp:760
msgid "Start graceful shutdown"
msgstr ""
-#: daemon/HTTPServer.cpp:722
+#: daemon/HTTPServer.cpp:763
msgid "Force shutdown"
msgstr ""
-#: daemon/HTTPServer.cpp:723
+#: daemon/HTTPServer.cpp:764
msgid "Reload external CSS styles"
msgstr ""
-#: daemon/HTTPServer.cpp:726
+#: daemon/HTTPServer.cpp:767
msgid ""
"<b>Note:</b> any action done here are not persistent and not changes your "
"config files."
msgstr ""
-#: daemon/HTTPServer.cpp:728
+#: daemon/HTTPServer.cpp:770
msgid "Logging level"
msgstr ""
-#: daemon/HTTPServer.cpp:736
+#: daemon/HTTPServer.cpp:779
msgid "Transit tunnels limit"
msgstr ""
-#: daemon/HTTPServer.cpp:741 daemon/HTTPServer.cpp:760
+#: daemon/HTTPServer.cpp:784 daemon/HTTPServer.cpp:803
msgid "Change"
msgstr ""
-#: daemon/HTTPServer.cpp:748
+#: daemon/HTTPServer.cpp:791
msgid "Change language"
msgstr ""
-#: daemon/HTTPServer.cpp:786
+#: daemon/HTTPServer.cpp:830
msgid "no transit tunnels currently built"
msgstr ""
-#: daemon/HTTPServer.cpp:902 daemon/HTTPServer.cpp:925
+#: daemon/HTTPServer.cpp:921 daemon/HTTPServer.cpp:944
msgid "SAM disabled"
msgstr ""
-#: daemon/HTTPServer.cpp:918
+#: daemon/HTTPServer.cpp:937
msgid "no sessions currently running"
msgstr ""
-#: daemon/HTTPServer.cpp:931
+#: daemon/HTTPServer.cpp:950
msgid "SAM session not found"
msgstr ""
-#: daemon/HTTPServer.cpp:936
+#: daemon/HTTPServer.cpp:955
msgid "SAM Session"
msgstr ""
-#: daemon/HTTPServer.cpp:993
+#: daemon/HTTPServer.cpp:1020
msgid "Server Tunnels"
msgstr ""
-#: daemon/HTTPServer.cpp:1009
+#: daemon/HTTPServer.cpp:1036
msgid "Client Forwards"
msgstr ""
-#: daemon/HTTPServer.cpp:1023
+#: daemon/HTTPServer.cpp:1050
msgid "Server Forwards"
msgstr ""
-#: daemon/HTTPServer.cpp:1223
+#: daemon/HTTPServer.cpp:1250
msgid "Unknown page"
msgstr ""
-#: daemon/HTTPServer.cpp:1242
+#: daemon/HTTPServer.cpp:1269
msgid "Invalid token"
msgstr ""
-#: daemon/HTTPServer.cpp:1300 daemon/HTTPServer.cpp:1357
-#: daemon/HTTPServer.cpp:1397
+#: daemon/HTTPServer.cpp:1327 daemon/HTTPServer.cpp:1359
+#: daemon/HTTPServer.cpp:1414 daemon/HTTPServer.cpp:1454
msgid "SUCCESS"
msgstr ""
-#: daemon/HTTPServer.cpp:1300
+#: daemon/HTTPServer.cpp:1327
msgid "Stream closed"
msgstr ""
-#: daemon/HTTPServer.cpp:1302
+#: daemon/HTTPServer.cpp:1329
msgid "Stream not found or already was closed"
msgstr ""
-#: daemon/HTTPServer.cpp:1305
+#: daemon/HTTPServer.cpp:1332 daemon/HTTPServer.cpp:1365
msgid "Destination not found"
msgstr ""
-#: daemon/HTTPServer.cpp:1308
+#: daemon/HTTPServer.cpp:1335
msgid "StreamID can't be null"
msgstr ""
-#: daemon/HTTPServer.cpp:1310 daemon/HTTPServer.cpp:1375
+#: daemon/HTTPServer.cpp:1337 daemon/HTTPServer.cpp:1367
+#: daemon/HTTPServer.cpp:1432
msgid "Return to destination page"
msgstr ""
-#: daemon/HTTPServer.cpp:1311 daemon/HTTPServer.cpp:1324
-#: daemon/HTTPServer.cpp:1399
-msgid "You will be redirected in 5 seconds"
+#: daemon/HTTPServer.cpp:1338 daemon/HTTPServer.cpp:1368
+#: daemon/HTTPServer.cpp:1381 daemon/HTTPServer.cpp:1456
+#, c-format
+msgid "You will be redirected in %d seconds"
+msgstr ""
+
+#: daemon/HTTPServer.cpp:1359
+msgid "LeaseSet expiration time updated"
+msgstr ""
+
+#: daemon/HTTPServer.cpp:1362
+msgid "LeaseSet is not found or already expired"
msgstr ""
-#: daemon/HTTPServer.cpp:1322
-msgid "Transit tunnels count must not exceed 65535"
+#: daemon/HTTPServer.cpp:1379
+#, c-format
+msgid "Transit tunnels count must not exceed %d"
msgstr ""
-#: daemon/HTTPServer.cpp:1323 daemon/HTTPServer.cpp:1398
+#: daemon/HTTPServer.cpp:1380 daemon/HTTPServer.cpp:1455
msgid "Back to commands list"
msgstr ""
-#: daemon/HTTPServer.cpp:1359
+#: daemon/HTTPServer.cpp:1416
msgid "Register at reg.i2p"
msgstr ""
-#: daemon/HTTPServer.cpp:1360
+#: daemon/HTTPServer.cpp:1417
msgid "Description"
msgstr ""
-#: daemon/HTTPServer.cpp:1360
+#: daemon/HTTPServer.cpp:1417
msgid "A bit information about service on domain"
msgstr ""
-#: daemon/HTTPServer.cpp:1361
+#: daemon/HTTPServer.cpp:1418
msgid "Submit"
msgstr ""
-#: daemon/HTTPServer.cpp:1367
+#: daemon/HTTPServer.cpp:1424
msgid "Domain can't end with .b32.i2p"
msgstr ""
-#: daemon/HTTPServer.cpp:1370
+#: daemon/HTTPServer.cpp:1427
msgid "Domain must end with .i2p"
msgstr ""
-#: daemon/HTTPServer.cpp:1373
-msgid "Such destination is not found"
-msgstr ""
-
-#: daemon/HTTPServer.cpp:1393
+#: daemon/HTTPServer.cpp:1450
msgid "Unknown command"
msgstr ""
-#: daemon/HTTPServer.cpp:1397
+#: daemon/HTTPServer.cpp:1454
msgid "Command accepted"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:163
+#: libi2pd_client/HTTPProxy.cpp:166
msgid "Proxy error"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:171
+#: libi2pd_client/HTTPProxy.cpp:174
msgid "Proxy info"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:179
+#: libi2pd_client/HTTPProxy.cpp:182
msgid "Proxy error: Host not found"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:180
+#: libi2pd_client/HTTPProxy.cpp:183
msgid "Remote host not found in router's addressbook"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:181
+#: libi2pd_client/HTTPProxy.cpp:184
msgid "You may try to find this host on jump services below"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:282 libi2pd_client/HTTPProxy.cpp:297
-#: libi2pd_client/HTTPProxy.cpp:331 libi2pd_client/HTTPProxy.cpp:372
+#: libi2pd_client/HTTPProxy.cpp:333 libi2pd_client/HTTPProxy.cpp:348
+#: libi2pd_client/HTTPProxy.cpp:417 libi2pd_client/HTTPProxy.cpp:460
msgid "Invalid request"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:282
+#: libi2pd_client/HTTPProxy.cpp:333
msgid "Proxy unable to parse your request"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:297
-msgid "addresshelper is not supported"
+#: libi2pd_client/HTTPProxy.cpp:348
+msgid "Addresshelper is not supported"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:306 libi2pd_client/HTTPProxy.cpp:315
-#: libi2pd_client/HTTPProxy.cpp:392
-msgid "Host"
+#: libi2pd_client/HTTPProxy.cpp:373
+#, c-format
+msgid ""
+"Host %s is <font color=red>already in router's addressbook</font>. <b>Be "
+"careful: source of this URL may be harmful!</b> Click here to update record: "
+"<a href=\"%s%s%s&update=true\">Continue</a>."
+msgstr ""
+
+#: libi2pd_client/HTTPProxy.cpp:375
+msgid "Addresshelper forced update rejected"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:306
-msgid "added to router's addressbook from helper"
+#: libi2pd_client/HTTPProxy.cpp:382
+#, c-format
+msgid ""
+"To add host <b>%s</b> in router's addressbook, click here: <a "
+"href=\"%s%s%s\">Continue</a>."
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:307
-msgid "Click here to proceed:"
+#: libi2pd_client/HTTPProxy.cpp:384
+msgid "Addresshelper request"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:307 libi2pd_client/HTTPProxy.cpp:317
-msgid "Continue"
+#: libi2pd_client/HTTPProxy.cpp:393
+#, c-format
+msgid ""
+"Host %s added to router's addressbook from helper. Click here to proceed: <a "
+"href=\"%s\">Continue</a>."
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:308 libi2pd_client/HTTPProxy.cpp:318
-msgid "Addresshelper found"
+#: libi2pd_client/HTTPProxy.cpp:395
+msgid "Addresshelper adding"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:315
-msgid "already in router's addressbook"
+#: libi2pd_client/HTTPProxy.cpp:402
+#, c-format
+msgid ""
+"Host %s is <font color=red>already in router's addressbook</font>. Click "
+"here to update record: <a href=\"%s%s%s&update=true\">Continue</a>."
msgstr ""
-#. tr: The "record" means addressbook's record. That message appears when domain was already added to addressbook, but helper link is opened for it.
-#: libi2pd_client/HTTPProxy.cpp:316
-msgid "Click here to update record:"
+#: libi2pd_client/HTTPProxy.cpp:404
+msgid "Addresshelper update"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:331
-msgid "invalid request uri"
+#: libi2pd_client/HTTPProxy.cpp:417
+msgid "Invalid request URI"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:372
+#: libi2pd_client/HTTPProxy.cpp:460
msgid "Can't detect destination host from request"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:389 libi2pd_client/HTTPProxy.cpp:393
+#: libi2pd_client/HTTPProxy.cpp:477 libi2pd_client/HTTPProxy.cpp:481
msgid "Outproxy failure"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:389
-msgid "bad outproxy settings"
+#: libi2pd_client/HTTPProxy.cpp:477
+msgid "Bad outproxy settings"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:392
-msgid "not inside I2P network, but outproxy is not enabled"
+#: libi2pd_client/HTTPProxy.cpp:480
+#, c-format
+msgid "Host %s is not inside I2P network, but outproxy is not enabled"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:482
-msgid "unknown outproxy url"
+#: libi2pd_client/HTTPProxy.cpp:569
+msgid "Unknown outproxy URL"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:490
-msgid "cannot resolve upstream proxy"
+#: libi2pd_client/HTTPProxy.cpp:575
+msgid "Cannot resolve upstream proxy"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:498
-msgid "hostname too long"
+#: libi2pd_client/HTTPProxy.cpp:583
+msgid "Hostname is too long"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:525
-msgid "cannot connect to upstream socks proxy"
+#: libi2pd_client/HTTPProxy.cpp:610
+msgid "Cannot connect to upstream SOCKS proxy"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:531
-msgid "Cannot negotiate with socks proxy"
+#: libi2pd_client/HTTPProxy.cpp:616
+msgid "Cannot negotiate with SOCKS proxy"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:573
+#: libi2pd_client/HTTPProxy.cpp:658
msgid "CONNECT error"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:573
-msgid "Failed to Connect"
+#: libi2pd_client/HTTPProxy.cpp:658
+msgid "Failed to connect"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:584 libi2pd_client/HTTPProxy.cpp:610
-msgid "socks proxy error"
+#: libi2pd_client/HTTPProxy.cpp:669 libi2pd_client/HTTPProxy.cpp:695
+msgid "SOCKS proxy error"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:592
-msgid "failed to send request to upstream"
+#: libi2pd_client/HTTPProxy.cpp:677
+msgid "Failed to send request to upstream"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:613
-msgid "No Reply From socks proxy"
+#: libi2pd_client/HTTPProxy.cpp:698
+msgid "No reply from SOCKS proxy"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:620
-msgid "cannot connect"
+#: libi2pd_client/HTTPProxy.cpp:705
+msgid "Cannot connect"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:620
-msgid "http out proxy not implemented"
+#: libi2pd_client/HTTPProxy.cpp:705
+msgid "HTTP out proxy not implemented"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:621
-msgid "cannot connect to upstream http proxy"
+#: libi2pd_client/HTTPProxy.cpp:706
+msgid "Cannot connect to upstream HTTP proxy"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:654
+#: libi2pd_client/HTTPProxy.cpp:739
msgid "Host is down"
msgstr ""
-#: libi2pd_client/HTTPProxy.cpp:654
+#: libi2pd_client/HTTPProxy.cpp:739
msgid ""
"Can't create connection to requested host, it may be down. Please try again "
"later."
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/i18n/README.md
^
|
@@ -1,29 +1,30 @@
-`xgettext` command for extracting translation
----
-
-```
-xgettext --omit-header -ctr: -ktr -ktr:1,2 daemon/HTTPServer.cpp libi2pd_client/HTTPProxy.cpp
-```
-
-Regex for transforming gettext translations to our format:
----
-
-```
-in: msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\n(msgstr\[1\]\ \"(.*)\"\n)?(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)?
-out: #{"$2", {"$3", "$4", "$6", "$8", "$10"}},\n
-```
-
-```
-in: msgid\ \"(.*)\"\nmsgstr\ \"(.*)\"\n
-out: {"$1", "$2"},\n
-```
-
-```
-in: ^#[:.](.*)$\n
-out: <to empty line>
-```
-
-```
-in: \n\n
-out: \n
-```
+`xgettext` command for extracting translation
+---
+
+```
+xgettext --omit-header -ctr: -ktr -kntr:1,2 daemon/HTTPServer.cpp libi2pd_client/HTTPProxy.cpp
+```
+
+Regex for transforming gettext translations to our format:
+---
+
+```
+in: ^(\"|#[:.,]|msgctxt)(.*)$\n
+out: <to empty line>
+```
+
+```
+in: msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\n(msgstr\[1\]\ \"(.*)\"\n)?(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)?
+out: #{"$2", {"$3", "$5", "$7", "$9", "$11"}},\n
+```
+
+```
+in: msgid\ \"(.*)\"\nmsgstr\ \"(.*)\"\n
+out: {"$1", "$2"},\n
+```
+
+
+```
+in: \n\n
+out: \n
+```
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/i2pd.conf
^
|
@@ -19,7 +19,7 @@
## Default: ~/.i2pd/certificates or /var/lib/i2pd/certificates
# certsdir = /var/lib/i2pd/certificates
-## Where to write pidfile (default: i2pd.pid, not used in Windows)
+## Where to write pidfile (default: /run/i2pd.pid, not used in Windows)
# pidfile = /run/i2pd.pid
## Logging configuration section
@@ -31,15 +31,16 @@
## * file - log entries to a file
## * syslog - use syslog, see man 3 syslog
# log = file
-## Path to logfile (default - autodetect)
+## Path to logfile (default: autodetect)
# logfile = /var/log/i2pd/i2pd.log
-## Log messages above this level (debug, info, *warn, error, none)
+## Log messages above this level (debug, info, *warn, error, critical, none)
## If you set it to none, logging will be disabled
# loglevel = warn
## Write full CLF-formatted date and time to log (default: write only time)
# logclftime = true
## Daemon mode. Router will go to background after start. Ignored on Windows
+## (default: true)
# daemon = true
## Specify a family, router belongs to (default - none)
@@ -70,90 +71,97 @@
## don't just uncomment this
# port = 4567
-## Enable communication through ipv4
+## Enable communication through ipv4 (default: true)
ipv4 = true
-## Enable communication through ipv6
+## Enable communication through ipv6 (default: false)
ipv6 = false
-## Enable SSU transport (default = true)
-ssu = false
-
## Bandwidth configuration
-## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec,
+## L limit bandwidth to 32 KB/sec, O - to 256 KB/sec, P - to 2048 KB/sec,
## X - unlimited
-## Default is L (regular node) and X if floodfill mode enabled. If you want to
-## share more bandwidth without floodfill mode, uncomment that line and adjust
-## value to your possibilities
+## Default is L (regular node) and X if floodfill mode enabled.
+## If you want to share more bandwidth without floodfill mode, uncomment
+## that line and adjust value to your possibilities. Value can be set to
+## integer in kilobytes, it will apply that limit and flag will be used
+## from next upper limit (example: if you set 4096 flag will be X, but real
+## limit will be 4096 KB/s). Same can be done when floodfill mode is used,
+## but keep in mind that low values may be negatively evaluated by Java
+## router algorithms.
# bandwidth = L
-## Max % of bandwidth limit for transit. 0-100. 100 by default
+## Max % of bandwidth limit for transit. 0-100 (default: 100)
# share = 100
## Router will not accept transit tunnels, disabling transit traffic completely
-## (default = false)
+## (default: false)
# notransit = true
-## Router will be floodfill
+## Router will be floodfill (default: false)
## Note: that mode uses much more network connections and CPU!
# floodfill = true
[ntcp2]
-## Enable NTCP2 transport (default = true)
+## Enable NTCP2 transport (default: true)
# enabled = true
-## Publish address in RouterInfo (default = true)
+## Publish address in RouterInfo (default: true)
# published = true
## Port for incoming connections (default is global port option value)
# port = 4567
[ssu2]
-## Enable SSU2 transport (default = false for 2.43.0)
-enabled = true
-## Publish address in RouterInfo (default = false for 2.43.0)
-published = true
-## Port for incoming connections (default is global port option value or port + 1 if SSU is enabled)
+## Enable SSU2 transport (default: true)
+# enabled = true
+## Publish address in RouterInfo (default: true)
+# published = true
+## Port for incoming connections (default is global port option value)
# port = 4567
[http]
## Web Console settings
-## Uncomment and set to 'false' to disable Web Console
+## Enable the Web Console (default: true)
# enabled = true
-## Address and port service will listen on
-address = 127.0.0.1
-port = 7070
-## Path to web console, default "/"
+## Address and port service will listen on (default: 127.0.0.1:7070)
+# address = 127.0.0.1
+# port = 7070
+## Path to web console (default: /)
# webroot = /
-## Uncomment following lines to enable Web Console authentication
+## Enable Web Console authentication (default: false)
+## You should not use Web Console via public networks without additional encryption.
+## HTTP authentication is not encryption layer!
# auth = true
# user = i2pd
# pass = changeme
## Select webconsole language
-## Currently supported english (default), afrikaans, armenian, chinese, french,
-## german, russian, turkmen, ukrainian and uzbek languages
+## Currently supported english (default), afrikaans, armenian, chinese, czech, french,
+## german, italian, polish, portuguese, russian, spanish, turkish, turkmen, ukrainian
+## and uzbek languages
# lang = english
[httpproxy]
-## Uncomment and set to 'false' to disable HTTP Proxy
+## Enable the HTTP proxy (default: true)
# enabled = true
-## Address and port service will listen on
-address = 127.0.0.1
-port = 4444
-## Optional keys file for proxy local destination
+## Address and port service will listen on (default: 127.0.0.1:4444)
+# address = 127.0.0.1
+# port = 4444
+## Optional keys file for proxy local destination (default: http-proxy-keys.dat)
# keys = http-proxy-keys.dat
## Enable address helper for adding .i2p domains with "jump URLs" (default: true)
+## You should disable this feature if your i2pd HTTP Proxy is public,
+## because anyone could spoof the short domain via addresshelper and forward other users to phishing links
# addresshelper = true
## Address of a proxy server inside I2P, which is used to visit regular Internet
# outproxy = http://false.i2p
## httpproxy section also accepts I2CP parameters, like "inbound.length" etc.
[socksproxy]
-## Uncomment and set to 'false' to disable SOCKS Proxy
+## Enable the SOCKS proxy (default: true)
# enabled = true
-## Address and port service will listen on
-address = 127.0.0.1
-port = 4447
-## Optional keys file for proxy local destination
+## Address and port service will listen on (default: 127.0.0.1:4447)
+# address = 127.0.0.1
+# port = 4447
+## Optional keys file for proxy local destination (default: socks-proxy-keys.dat)
# keys = socks-proxy-keys.dat
## Socks outproxy. Example below is set to use Tor for all connections except i2p
-## Uncomment and set to 'true' to enable using of SOCKS outproxy
+## Enable using of SOCKS outproxy (works only with SOCKS4, default: false)
# outproxy.enabled = false
## Address and port of outproxy
# outproxy = 127.0.0.1
@@ -161,33 +169,34 @@
## socksproxy section also accepts I2CP parameters, like "inbound.length" etc.
[sam]
-## Comment or set to 'false' to disable SAM Bridge
-enabled = true
-## Address and port service will listen on
+## Enable the SAM bridge (default: true)
+# enabled = false
+## Address and ports service will listen on (default: 127.0.0.1:7656, udp: 7655)
# address = 127.0.0.1
# port = 7656
+# portudp = 7655
[bob]
-## Uncomment and set to 'true' to enable BOB command channel
+## Enable the BOB command channel (default: false)
# enabled = false
-## Address and port service will listen on
+## Address and port service will listen on (default: 127.0.0.1:2827)
# address = 127.0.0.1
# port = 2827
[i2cp]
-## Uncomment and set to 'true' to enable I2CP protocol
+## Enable the I2CP protocol (default: false)
# enabled = false
-## Address and port service will listen on
+## Address and port service will listen on (default: 127.0.0.1:7654)
# address = 127.0.0.1
# port = 7654
[i2pcontrol]
-## Uncomment and set to 'true' to enable I2PControl protocol
+## Enable the I2PControl protocol (default: false)
# enabled = false
-## Address and port service will listen on
+## Address and port service will listen on (default: 127.0.0.1:7650)
# address = 127.0.0.1
# port = 7650
-## Authentication password. "itoopie" by default
+## Authentication password (default: itoopie)
# password = itoopie
[precomputation]
@@ -198,11 +207,11 @@
[upnp]
## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID)
# enabled = false
-## Name i2pd appears in UPnP forwardings list (default = I2Pd)
+## Name i2pd appears in UPnP forwardings list (default: I2Pd)
# name = I2Pd
[meshnets]
-## Enable connectivity over the Yggdrasil network
+## Enable connectivity over the Yggdrasil network (default: false)
# yggdrasil = false
## You can bind address from your Yggdrasil subnet 300::/64
## The address must first be added to the network interface
@@ -210,13 +219,13 @@
[reseed]
## Options for bootstrapping into I2P network, aka reseeding
-## Enable or disable reseed data verification.
+## Enable reseed data verification (default: true)
verify = true
## URLs to request reseed data from, separated by comma
## Default: "mainline" I2P Network reseeds
# urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/
## Reseed URLs through the Yggdrasil, separated by comma
-# yggurls = http://[324:9de3:fea4:f6ac::ace]:7070/
+# yggurls = http://[324:71e:281a:9ed3::ace]:7070/
## Path to local reseed data file (.su3) for manual reseeding
# file = /path/to/i2pseeds.su3
## or HTTPS URL to reseed from
@@ -226,7 +235,7 @@
## If you run i2pd behind a proxy server, set proxy server for reseeding here
## Should be http://address:port or socks://address:port
# proxy = http://127.0.0.1:8118
-## Minimum number of known routers, below which i2pd triggers reseeding. 25 by default
+## Minimum number of known routers, below which i2pd triggers reseeding (default: 25)
# threshold = 25
[addressbook]
@@ -237,21 +246,22 @@
# subscriptions = http://reg.i2p/hosts.txt,http://identiguy.i2p/hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt,http://rus.i2p/hosts.txt
[limits]
-## Maximum active transit sessions (default:2500)
-# transittunnels = 2500
+## Maximum active transit sessions (default: 5000)
+## This value is doubled if floodfill mode is enabled!
+# transittunnels = 5000
## Limit number of open file descriptors (0 - use system limit)
# openfiles = 0
## Maximum size of corefile in Kb (0 - use system limit)
# coresize = 0
[trust]
-## Enable explicit trust options. false by default
+## Enable explicit trust options. (default: false)
# enabled = true
## Make direct I2P connections only to routers in specified Family.
# family = MyFamily
## Make direct I2P connections only to routers specified here. Comma separated list of base64 identities.
# routers =
-## Should we hide our router from other routers? false by default
+## Should we hide our router from other routers? (default: false)
# hidden = true
[exploratory]
@@ -270,8 +280,6 @@
[cpuext]
## Use CPU AES-NI instructions set when work with cryptography when available (default: true)
# aesni = true
-## Use CPU AVX instructions set when work with cryptography when available (default: true)
-# avx = true
-## Force usage of CPU instructions set, even if they not found
+## Force usage of CPU instructions set, even if they not found (default: false)
## DO NOT TOUCH that option if you really don't know what are you doing!
# force = false
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/i2pd.service
^
|
@@ -29,7 +29,7 @@
#TimeoutStopSec=10m
# If you have problems with hanging i2pd, you can try increase this
-LimitNOFILE=4096
+LimitNOFILE=8192
# To enable write of coredump uncomment this
#LimitCORE=infinity
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/rpm/i2pd-git.spec
^
|
@@ -1,7 +1,7 @@
%define git_hash %(git rev-parse HEAD | cut -c -7)
Name: i2pd-git
-Version: 2.43.0
+Version: 2.50.2
Release: git%{git_hash}%{?dist}
Summary: I2P router written in C++
Conflicts: i2pd
@@ -28,9 +28,11 @@
Requires: systemd
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
+
%description
C++ implementation of I2P.
+
%prep
%setup -q -n i2pd-openssl
@@ -38,72 +40,56 @@
%build
cd build
%if 0%{?rhel} == 7
-%cmake3 \
+ %cmake3 \
-DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \
-DWITH_HARDENING=ON \
-DBUILD_SHARED_LIBS:BOOL=OFF
%else
-%cmake \
+ %cmake \
-DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \
-DWITH_HARDENING=ON \
-%if 0%{?fedora} > 29
+ %if 0%{?fedora} > 29
-DBUILD_SHARED_LIBS:BOOL=OFF \
.
-%else
+ %else
-DBUILD_SHARED_LIBS:BOOL=OFF
-%endif
+ %endif
%endif
-
-%if 0%{?rhel} == 9
-pushd redhat-linux-build
-%endif
-
-%if 0%{?fedora} >= 35
-pushd redhat-linux-build
+%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln}
+ pushd redhat-linux-build
%else
-%if 0%{?fedora} >= 33
-pushd %{_target_platform}
-%endif
-%endif
-
-%if 0%{?mageia} > 7
-pushd build
+ %if 0%{?fedora} >= 33
+ pushd %{_target_platform}
+ %endif
+
+ %if 0%{?mageia} > 7
+ pushd build
+ %endif
%endif
make %{?_smp_mflags}
-%if 0%{?rhel} == 9
-popd
-%endif
-
-%if 0%{?fedora} >= 33
-popd
+%if 0%{?rhel} == 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7
+ popd
%endif
-%if 0%{?mageia} > 7
-popd
-%endif
%install
pushd build
-%if 0%{?rhel} == 9
-pushd redhat-linux-build
-%endif
-
-%if 0%{?fedora} >= 35
-pushd redhat-linux-build
+%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln}
+ pushd redhat-linux-build
%else
-%if 0%{?fedora} >= 33
-pushd %{_target_platform}
-%endif
-%endif
-
-%if 0%{?mageia}
-pushd build
+ %if 0%{?fedora} >= 33
+ pushd %{_target_platform}
+ %endif
+
+ %if 0%{?mageia}
+ pushd build
+ %endif
%endif
chrpath -d i2pd
@@ -158,6 +144,39 @@
%changelog
+* Sat Jan 06 2024 orignal <orignal@i2pmail.org> - 2.50.2
+- update to 2.50.2
+
+* Sat Dec 23 2023 r4sas <r4sas@i2pmail.org> - 2.50.1
+- update to 2.50.1
+
+* Mon Dec 18 2023 orignal <orignal@i2pmail.org> - 2.50.0
+- update to 2.50.0
+
+* Mon Sep 18 2023 orignal <orignal@i2pmail.org> - 2.49.0
+- update to 2.49.0
+
+* Mon Jun 12 2023 orignal <orignal@i2pmail.org> - 2.48.0
+- update to 2.48.0
+
+* Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0
+- update to 2.47.0
+
+* Mon Feb 20 2023 r4sas <r4sas@i2pmail.org> - 2.46.1
+- update to 2.46.1
+
+* Wed Feb 15 2023 orignal <orignal@i2pmail.org> - 2.46.0
+- update to 2.46.0
+
+* Wed Jan 11 2023 orignal <orignal@i2pmail.org> - 2.45.1
+- update to 2.45.1
+
+* Tue Jan 3 2023 orignal <orignal@i2pmail.org> - 2.45.0
+- update to 2.45.0
+
+* Sun Nov 20 2022 orignal <orignal@i2pmail.org> - 2.44.0
+- update to 2.44.0
+
* Mon Aug 22 2022 orignal <orignal@i2pmail.org> - 2.43.0
- update to 2.43.0
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/rpm/i2pd.spec
^
|
@@ -1,5 +1,5 @@
Name: i2pd
-Version: 2.43.0
+Version: 2.50.2
Release: 1%{?dist}
Summary: I2P router written in C++
Conflicts: i2pd-git
@@ -26,9 +26,11 @@
Requires: systemd
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
+
%description
C++ implementation of I2P.
+
%prep
%setup -q
@@ -36,71 +38,56 @@
%build
cd build
%if 0%{?rhel} == 7
-%cmake3 \
+ %cmake3 \
-DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \
-DWITH_HARDENING=ON \
-DBUILD_SHARED_LIBS:BOOL=OFF
%else
-%cmake \
+ %cmake \
-DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \
-DWITH_HARDENING=ON \
-%if 0%{?fedora} > 29
+ %if 0%{?fedora} > 29
-DBUILD_SHARED_LIBS:BOOL=OFF \
.
-%else
+ %else
-DBUILD_SHARED_LIBS:BOOL=OFF
-%endif
+ %endif
%endif
-%if 0%{?rhel} == 9
-pushd redhat-linux-build
-%endif
-
-%if 0%{?fedora} >= 35
-pushd redhat-linux-build
+%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln}
+ pushd redhat-linux-build
%else
-%if 0%{?fedora} >= 33
-pushd %{_target_platform}
-%endif
-%endif
-
-%if 0%{?mageia} > 7
-pushd build
+ %if 0%{?fedora} >= 33
+ pushd %{_target_platform}
+ %endif
+
+ %if 0%{?mageia} > 7
+ pushd build
+ %endif
%endif
make %{?_smp_mflags}
-%if 0%{?rhel} == 9
-popd
+%if 0%{?rhel} == 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7
+ popd
%endif
-%if 0%{?fedora} >= 33
-popd
-%endif
-
-%if 0%{?mageia} > 7
-popd
-%endif
%install
pushd build
-%if 0%{?rhel} == 9
-pushd redhat-linux-build
-%endif
-
-%if 0%{?fedora} >= 35
-pushd redhat-linux-build
+%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln}
+ pushd redhat-linux-build
%else
-%if 0%{?fedora} >= 33
-pushd %{_target_platform}
-%endif
-%endif
-
-%if 0%{?mageia}
-pushd build
+ %if 0%{?fedora} >= 33
+ pushd %{_target_platform}
+ %endif
+
+ %if 0%{?mageia}
+ pushd build
+ %endif
%endif
chrpath -d i2pd
@@ -155,6 +142,39 @@
%changelog
+* Sat Jan 06 2024 orignal <orignal@i2pmail.org> - 2.50.2
+- update to 2.50.2
+
+* Sat Dec 23 2023 r4sas <r4sas@i2pmail.org> - 2.50.1
+- update to 2.50.1
+
+* Mon Dec 18 2023 orignal <orignal@i2pmail.org> - 2.50.0
+- update to 2.50.0
+
+* Mon Sep 18 2023 orignal <orignal@i2pmail.org> - 2.49.0
+- update to 2.49.0
+
+* Mon Jun 12 2023 orignal <orignal@i2pmail.org> - 2.48.0
+- update to 2.48.0
+
+* Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0
+- update to 2.47.0
+
+* Mon Feb 20 2023 r4sas <r4sas@i2pmail.org> - 2.46.1
+- update to 2.46.1
+
+* Wed Feb 15 2023 orignal <orignal@i2pmail.org> - 2.46.0
+- update to 2.46.0
+
+* Wed Jan 11 2023 orignal <orignal@i2pmail.org> - 2.45.1
+- update to 2.45.1
+
+* Tue Jan 3 2023 orignal <orignal@i2pmail.org> - 2.45.0
+- update to 2.45.0
+
+* Sun Nov 20 2022 orignal <orignal@i2pmail.org> - 2.44.0
+- update to 2.44.0
+
* Mon Aug 22 2022 orignal <orignal@i2pmail.org> - 2.43.0
- update to 2.43.0
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/contrib/webconsole/style.css
^
|
@@ -1,293 +1,293 @@
-/*
- * Copyright (c) 2021-2022, The PurpleI2P Project
- *
- * This file is part of Purple i2pd project and licensed under BSD3
- *
- * See full license text in LICENSE file at top of project tree
- *
- ******************************************************************
- *
- * This is style sheet for webconsole, with @media selectors for adaptive
- * view on desktop and mobile devices, respecting preferred user's color
- * scheme used in system/browser.
- *
- * Minified copy of that style sheet is bundled inside i2pd sources.
-*/
-
-:root {
- --main-bg-color: #fafafa;
- --main-text-color: #103456;
- --main-link-color: #894c84;
- --main-link-hover-color: #fafafa;
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- --main-bg-color: #242424;
- --main-text-color: #17ab5c;
- --main-link-color: #bf64b7;
- --main-link-hover-color: #000000;
- }
-}
-
-body {
- font: 100%/1.5em sans-serif;
- margin: 0;
- padding: 1.5em;
- background: var(--main-bg-color);
- color: var(--main-text-color);
-}
-
-a, .slide label {
- text-decoration: none;
- color: var(--main-link-color);
-}
-
-a:hover, .slide label:hover, button[type=submit]:hover {
- color: var(--main-link-hover-color);
- background: var(--main-link-color);
-}
-
-a.button {
- appearance: button;
- text-decoration: none;
- padding: 0 5px;
- border: 1px solid var(--main-link-color);
-}
-
-.header {
- font-size: 2.5em;
- text-align: center;
- margin: 1em 0;
- color: var(--main-link-color);
-}
-
-.wrapper {
- margin: 0 auto;
- padding: 1em;
- max-width: 64em;
-}
-
-.menu {
- display: block;
- float: left;
- overflow: hidden;
- padding: 4px;
- max-width: 12em;
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-
-.listitem {
- display: block;
- font-family: monospace;
- font-size: 1.2em;
- white-space: nowrap;
-}
-
-.tableitem {
- font-family: monospace;
- font-size: 1.2em;
- white-space: nowrap;
-}
-
-.content {
- float: left;
- font-size: 1em;
- margin-left: 2em;
- padding: 4px;
- max-width: 50em;
- overflow: auto;
-}
-
-.tunnel.established {
- color: #56B734;
-}
-
-.tunnel.expiring {
- color: #D3AE3F;
-}
-
-.tunnel.failed {
- color: #D33F3F;
-}
-
-.tunnel.building {
- color: #434343;
-}
-
-caption {
- font-size: 1.5em;
- text-align: center;
- color: var(--main-link-color);
-}
-
-table {
- display: table;
- border-collapse: collapse;
- text-align: center;
-}
-
-table.extaddr {
- text-align: left;
-}
-
-table.services {
- width: 100%;
-}
-
-textarea {
- background-color: var(--main-bg-color);
- color: var(--main-text-color);
- word-break: break-all;
-}
-
-.streamdest {
- width: 120px;
- max-width: 240px;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.slide div.slidecontent, .slide [type="checkbox"] {
- display: none;
-}
-
-.slide [type="checkbox"]:checked ~ div.slidecontent {
- display: block;
- margin-top: 0;
- padding: 0;
-}
-
-.disabled {
- color: #D33F3F;
-}
-
-.enabled {
- color: #56B734;
-}
-
-button[type=submit] {
- background-color: transparent;
- color: var(--main-link-color);
- text-decoration: none;
- padding: 5px;
- border: 1px solid var(--main-link-color);
- font-size: 14px;
-}
-
-input, select, select option {
- background-color: var(--main-bg-color);
- color: var(--main-link-color);
- padding: 5px;
- border: 1px solid var(--main-link-color);
- font-size: 14px;
-}
-
-input:focus, select:focus, select option:focus {
- outline: none;
-}
-
-input[type=number]::-webkit-inner-spin-button {
- -webkit-appearance: none;
-}
-
-@media screen and (max-width: 1150px) { /* adaptive style */
- .wrapper {
- max-width: 58em;
- }
-
- .content {
- max-width: 40em;
- }
-}
-
-@media screen and (max-width: 980px) {
- body {
- font: 100%/1.2em sans-serif;
- padding: 1.2em 0 0 0;
- }
-
- .menu {
- width: 100%;
- max-width: unset;
- display: block;
- float: none;
- position: unset;
- font-size: 16px;
- text-align: center;
- }
-
- .menu a, .commands a {
- display: inline-block;
- padding: 4px;
- }
-
- .content {
- float: none;
- margin-left: unset;
- margin-top: 16px;
- max-width: 100%;
- width: 100%;
- text-align: center;
- }
-
- a, .slide label {
- display: block;
- }
-
- .header {
- margin: unset;
- font-size: 1.5em;
- }
-
- small {
- display: block
- }
-
- a.button {
- appearance: button;
- text-decoration: none;
- margin-top: 10px;
- padding: 6px;
- border: 2px solid var(--main-link-color);
- border-radius: 5px;
- width: -webkit-fill-available;
- }
-
- input, select {
- width: 35%;
- text-align: center;
- padding: 5px;
- border: 2px solid var(--main-link-color);
- border-radius: 5px;
- font-size: 18px;
- }
-
- table.extaddr {
- margin: auto;
- text-align: unset;
- }
-
- textarea {
- width: -webkit-fill-available;
- height: auto;
- padding: 5px;
- border: 2px solid var(--main-link-color);
- border-radius: 5px;
- font-size: 12px;
- }
-
- button[type=submit] {
- padding: 5px 15px;
- background: transparent;
- border: 2px solid var(--main-link-color);
- cursor: pointer;
- -webkit-border-radius: 5px;
- border-radius: 5px;
- position: relative;
- height: 36px;
- display: -webkit-inline-box;
- margin-top: 10px;
- }
-}
\ No newline at end of file
+/*
+ * Copyright (c) 2021-2023, The PurpleI2P Project
+ *
+ * This file is part of Purple i2pd project and licensed under BSD3
+ *
+ * See full license text in LICENSE file at top of project tree
+ *
+ ******************************************************************
+ *
+ * This is style sheet for webconsole, with @media selectors for adaptive
+ * view on desktop and mobile devices, respecting preferred user's color
+ * scheme used in system/browser.
+ *
+ * Minified copy of that style sheet is bundled inside i2pd sources.
+*/
+
+:root {
+ --main-bg-color: #fafafa;
+ --main-text-color: #103456;
+ --main-link-color: #894c84;
+ --main-link-hover-color: #fafafa;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --main-bg-color: #242424;
+ --main-text-color: #17ab5c;
+ --main-link-color: #bf64b7;
+ --main-link-hover-color: #000000;
+ }
+}
+
+body {
+ font: 100%/1.5em sans-serif;
+ margin: 0;
+ padding: 1.5em;
+ background: var(--main-bg-color);
+ color: var(--main-text-color);
+}
+
+a, .slide label {
+ text-decoration: none;
+ color: var(--main-link-color);
+}
+
+a:hover, a.button.selected, .slide label:hover, button[type=submit]:hover {
+ color: var(--main-link-hover-color);
+ background: var(--main-link-color);
+}
+
+a.button {
+ appearance: button;
+ text-decoration: none;
+ padding: 0 5px;
+ border: 1px solid var(--main-link-color);
+}
+
+.header {
+ font-size: 2.5em;
+ text-align: center;
+ margin: 1em 0;
+ color: var(--main-link-color);
+}
+
+.wrapper {
+ margin: 0 auto;
+ padding: 1em;
+ max-width: 64em;
+}
+
+.menu {
+ display: block;
+ float: left;
+ overflow: hidden;
+ padding: 4px;
+ max-width: 12em;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.listitem {
+ display: block;
+ font-family: monospace;
+ font-size: 1.2em;
+ white-space: nowrap;
+}
+
+.tableitem {
+ font-family: monospace;
+ font-size: 1.2em;
+ white-space: nowrap;
+}
+
+.content {
+ float: left;
+ font-size: 1em;
+ margin-left: 2em;
+ padding: 4px;
+ max-width: 50em;
+ overflow: auto;
+}
+
+.tunnel.established {
+ color: #56B734;
+}
+
+.tunnel.expiring {
+ color: #D3AE3F;
+}
+
+.tunnel.failed {
+ color: #D33F3F;
+}
+
+.tunnel.building {
+ color: #434343;
+}
+
+caption {
+ font-size: 1.5em;
+ text-align: center;
+ color: var(--main-link-color);
+}
+
+table {
+ display: table;
+ border-collapse: collapse;
+ text-align: center;
+}
+
+table.extaddr {
+ text-align: left;
+}
+
+table.services {
+ width: 100%;
+}
+
+textarea {
+ background-color: var(--main-bg-color);
+ color: var(--main-text-color);
+ word-break: break-all;
+}
+
+.streamdest {
+ width: 120px;
+ max-width: 240px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.slide div.slidecontent, .slide [type="checkbox"] {
+ display: none;
+}
+
+.slide [type="checkbox"]:checked ~ div.slidecontent {
+ display: block;
+ margin-top: 0;
+ padding: 0;
+}
+
+.disabled {
+ color: #D33F3F;
+}
+
+.enabled {
+ color: #56B734;
+}
+
+button[type=submit] {
+ background-color: transparent;
+ color: var(--main-link-color);
+ text-decoration: none;
+ padding: 5px;
+ border: 1px solid var(--main-link-color);
+ font-size: 14px;
+}
+
+input, select, select option {
+ background-color: var(--main-bg-color);
+ color: var(--main-link-color);
+ padding: 5px;
+ border: 1px solid var(--main-link-color);
+ font-size: 14px;
+}
+
+input:focus, select:focus, select option:focus {
+ outline: none;
+}
+
+input[type=number]::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+}
+
+@media screen and (max-width: 1150px) { /* adaptive style */
+ .wrapper {
+ max-width: 58em;
+ }
+
+ .content {
+ max-width: 40em;
+ }
+}
+
+@media screen and (max-width: 980px) {
+ body {
+ font: 100%/1.2em sans-serif;
+ padding: 1.2em 0 0 0;
+ }
+
+ .menu {
+ width: 100%;
+ max-width: unset;
+ display: block;
+ float: none;
+ position: unset;
+ font-size: 16px;
+ text-align: center;
+ }
+
+ .menu a, .commands a {
+ display: inline-block;
+ padding: 4px;
+ }
+
+ .content {
+ float: none;
+ margin-left: unset;
+ margin-top: 16px;
+ max-width: 100%;
+ width: 100%;
+ text-align: center;
+ }
+
+ a, .slide label {
+ display: block;
+ }
+
+ .header {
+ margin: unset;
+ font-size: 1.5em;
+ }
+
+ small {
+ display: block
+ }
+
+ a.button {
+ appearance: button;
+ text-decoration: none;
+ margin-top: 10px;
+ padding: 6px;
+ border: 2px solid var(--main-link-color);
+ border-radius: 5px;
+ width: -webkit-fill-available;
+ }
+
+ input, select {
+ width: 35%;
+ text-align: center;
+ padding: 5px;
+ border: 2px solid var(--main-link-color);
+ border-radius: 5px;
+ font-size: 18px;
+ }
+
+ table.extaddr {
+ margin: auto;
+ text-align: unset;
+ }
+
+ textarea {
+ width: -webkit-fill-available;
+ height: auto;
+ padding: 5px;
+ border: 2px solid var(--main-link-color);
+ border-radius: 5px;
+ font-size: 12px;
+ }
+
+ button[type=submit] {
+ padding: 5px 15px;
+ background: transparent;
+ border: 2px solid var(--main-link-color);
+ cursor: pointer;
+ -webkit-border-radius: 5px;
+ border-radius: 5px;
+ position: relative;
+ height: 36px;
+ display: -webkit-inline-box;
+ margin-top: 10px;
+ }
+}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/daemon/Daemon.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -31,7 +31,6 @@
#include "Crypto.h"
#include "UPnP.h"
#include "Timestamp.h"
-#include "util.h"
#include "I18N.h"
namespace i2p
@@ -151,135 +150,35 @@
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);
- bool avx; i2p::config::GetOption("cpuext.avx", avx);
bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt);
bool ssu; i2p::config::GetOption("ssu", ssu);
if (!ssu && i2p::config::IsDefault ("precomputation.elgamal"))
precomputation = false; // we don't elgamal table if no ssu, unless it's specified explicitly
- i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt);
+ i2p::crypto::InitCrypto (precomputation, aesni, forceCpuExt);
+
+ i2p::transport::InitAddressFromIface (); // get address4/6 from interfaces
int netID; i2p::config::GetOption("netid", netID);
i2p::context.SetNetID (netID);
i2p::context.Init ();
- bool ipv6; i2p::config::GetOption("ipv6", ipv6);
- bool ipv4; i2p::config::GetOption("ipv4", ipv4);
-
- // ifname -> address
- std::string ifname; i2p::config::GetOption("ifname", ifname);
- if (ipv4 && i2p::config::IsDefault ("address4"))
- {
- std::string ifname4; i2p::config::GetOption("ifname4", ifname4);
- if (!ifname4.empty ())
- i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname4, false).to_string ()); // v4
- else if (!ifname.empty ())
- i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname, false).to_string ()); // v4
- }
- if (ipv6 && i2p::config::IsDefault ("address6"))
- {
- std::string ifname6; i2p::config::GetOption("ifname6", ifname6);
- if (!ifname6.empty ())
- i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname6, true).to_string ()); // v6
- else if (!ifname.empty ())
- i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname, true).to_string ()); // v6
- }
-
- bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
- boost::asio::ip::address_v6 yggaddr;
- if (ygg)
- {
- std::string yggaddress; i2p::config::GetOption ("meshnets.yggaddress", yggaddress);
- if (!yggaddress.empty ())
- {
- yggaddr = boost::asio::ip::address_v6::from_string (yggaddress);
- if (yggaddr.is_unspecified () || !i2p::util::net::IsYggdrasilAddress (yggaddr) ||
- !i2p::util::net::IsLocalAddress (yggaddr))
- {
- LogPrint(eLogWarning, "Daemon: Can't find Yggdrasil address ", yggaddress);
- ygg = false;
- }
- }
- else
- {
- yggaddr = i2p::util::net::GetYggdrasilAddress ();
- if (yggaddr.is_unspecified ())
- {
- LogPrint(eLogWarning, "Daemon: Yggdrasil is not running. Disabled");
- ygg = false;
- }
- }
- }
-
- uint16_t port; i2p::config::GetOption("port", port);
- if (!i2p::config::IsDefault("port"))
- {
- LogPrint(eLogInfo, "Daemon: Accepting incoming connections at port ", port);
- i2p::context.UpdatePort (port);
- }
- i2p::context.SetSupportsV6 (ipv6);
- i2p::context.SetSupportsV4 (ipv4);
- i2p::context.SetSupportsMesh (ygg, yggaddr);
-
- i2p::context.RemoveNTCPAddress (!ipv6); // TODO: remove later
- bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
- if (ntcp2)
- {
- bool published; i2p::config::GetOption("ntcp2.published", published);
- if (published)
- {
- std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy);
- if (!ntcp2proxy.empty ()) published = false;
- }
- if (published)
- {
- uint16_t ntcp2port; i2p::config::GetOption("ntcp2.port", ntcp2port);
- if (!ntcp2port) ntcp2port = port; // use standard port
- i2p::context.PublishNTCP2Address (ntcp2port, true, ipv4, ipv6, false); // publish
- if (ipv6)
- {
- std::string ipv6Addr; i2p::config::GetOption("ntcp2.addressv6", ipv6Addr);
- auto addr = boost::asio::ip::address_v6::from_string (ipv6Addr);
- if (!addr.is_unspecified () && addr != boost::asio::ip::address_v6::any ())
- i2p::context.UpdateNTCP2V6Address (addr); // set ipv6 address if configured
- }
- }
- else
- i2p::context.PublishNTCP2Address (port, false, ipv4, ipv6, false); // unpublish
- }
- if (ygg)
- {
- i2p::context.PublishNTCP2Address (port, true, false, false, true);
- i2p::context.UpdateNTCP2V6Address (yggaddr);
- if (!ipv4 && !ipv6)
- i2p::context.SetStatus (eRouterStatusMesh);
- }
- if (!ssu) i2p::context.RemoveSSUAddress (); // TODO: remove later
- bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
- if (ssu2)
- {
- uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port);
- if (!ssu2port) ssu2port = ssu ? (port + 1) : port;
- bool published; i2p::config::GetOption("ssu2.published", published);
- if (published)
- i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish
- else
- i2p::context.PublishSSU2Address (ssu2port, false, ipv4, ipv6); // unpublish
- }
-
- bool transit; i2p::config::GetOption("notransit", transit);
- i2p::context.SetAcceptsTunnels (!transit);
- uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels);
- SetMaxNumTransitTunnels (transitTunnels);
+ i2p::transport::InitTransports ();
bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill);
- if (isFloodfill) {
+ if (isFloodfill)
+ {
LogPrint(eLogInfo, "Daemon: Router configured as floodfill");
i2p::context.SetFloodfill (true);
}
else
- {
i2p::context.SetFloodfill (false);
- }
+
+ bool transit; i2p::config::GetOption("notransit", transit);
+ i2p::context.SetAcceptsTunnels (!transit);
+ uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels);
+ if (isFloodfill && i2p::config::IsDefault ("limits.transittunnels"))
+ transitTunnels *= 2; // double default number of transit tunnels for floodfill
+ i2p::tunnel::tunnels.SetMaxNumTransitTunnels (transitTunnels);
/* this section also honors 'floodfill' flag, if set above */
std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth);
@@ -369,7 +268,7 @@
if (hidden)
{
LogPrint(eLogInfo, "Daemon: Hidden mode enabled");
- i2p::data::netdb.SetHidden(true);
+ i2p::context.SetHidden(true);
}
std::string httpLang; i2p::config::GetOption("http.lang", httpLang);
@@ -399,19 +298,18 @@
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
- bool ssu; i2p::config::GetOption("ssu", ssu);
bool checkInReserved; i2p::config::GetOption("reservedrange", checkInReserved);
LogPrint(eLogInfo, "Daemon: Starting Transports");
- if(!ssu) LogPrint(eLogInfo, "Daemon: SSU disabled");
+ if(!ssu2) LogPrint(eLogInfo, "Daemon: SSU2 disabled");
if(!ntcp2) LogPrint(eLogInfo, "Daemon: NTCP2 disabled");
i2p::transport::transports.SetCheckReserved(checkInReserved);
- i2p::transport::transports.Start(ntcp2, ssu, ssu2);
- if (i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundSSU2() || i2p::transport::transports.IsBoundNTCP2())
+ i2p::transport::transports.Start(ntcp2, ssu2);
+ if (i2p::transport::transports.IsBoundSSU2() || i2p::transport::transports.IsBoundNTCP2())
LogPrint(eLogInfo, "Daemon: Transports started");
else
{
- LogPrint(eLogError, "Daemon: Failed to start Transports");
+ LogPrint(eLogCritical, "Daemon: Failed to start Transports");
/** shut down netdb right away */
i2p::transport::transports.Stop();
i2p::data::netdb.Stop();
@@ -430,15 +328,17 @@
}
catch (std::exception& ex)
{
- LogPrint (eLogError, "Daemon: Failed to start Webconsole: ", ex.what ());
+ LogPrint (eLogCritical, "Daemon: Failed to start Webconsole: ", ex.what ());
ThrowFatal ("Unable to start webconsole at ", httpAddr, ":", httpPort, ": ", ex.what ());
}
}
-
LogPrint(eLogInfo, "Daemon: Starting Tunnels");
i2p::tunnel::tunnels.Start();
+ LogPrint(eLogInfo, "Daemon: Starting Router context");
+ i2p::context.Start();
+
LogPrint(eLogInfo, "Daemon: Starting Client");
i2p::client::context.Start ();
@@ -455,7 +355,7 @@
}
catch (std::exception& ex)
{
- LogPrint (eLogError, "Daemon: Failed to start I2PControl: ", ex.what ());
+ LogPrint (eLogCritical, "Daemon: Failed to start I2PControl: ", ex.what ());
ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ());
}
}
@@ -467,6 +367,8 @@
LogPrint(eLogInfo, "Daemon: Shutting down");
LogPrint(eLogInfo, "Daemon: Stopping Client");
i2p::client::context.Stop();
+ LogPrint(eLogInfo, "Daemon: Stopping Router context");
+ i2p::context.Stop();
LogPrint(eLogInfo, "Daemon: Stopping Tunnels");
i2p::tunnel::tunnels.Stop();
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/daemon/HTTPServer.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -80,15 +80,14 @@
const char HTTP_COMMAND_SHUTDOWN_CANCEL[] = "shutdown_cancel";
const char HTTP_COMMAND_SHUTDOWN_NOW[] = "terminate";
const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test";
- const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config";
+ const char HTTP_COMMAND_RELOAD_TUNNELS_CONFIG[] = "reload_tunnels_config";
const char HTTP_COMMAND_LOGLEVEL[] = "set_loglevel";
const char HTTP_COMMAND_KILLSTREAM[] = "closestream";
const char HTTP_COMMAND_LIMITTRANSIT[] = "limittransit";
const char HTTP_COMMAND_GET_REG_STRING[] = "get_reg_string";
const char HTTP_COMMAND_SETLANGUAGE[] = "setlanguage";
const char HTTP_COMMAND_RELOAD_CSS[] = "reload_css";
- const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
- const char HTTP_PARAM_ADDRESS[] = "address";
+ const char HTTP_COMMAND_EXPIRELEASE[] = "expirelease";
static std::string ConvertTime (uint64_t time)
{
@@ -105,18 +104,18 @@
int num;
if ((num = seconds / 86400) > 0) {
- s << num << " " << tr("day", "days", num) << ", ";
+ s << ntr("%d day", "%d days", num, num) << ", ";
seconds -= num * 86400;
}
if ((num = seconds / 3600) > 0) {
- s << num << " " << tr("hour", "hours", num) << ", ";
+ s << ntr("%d hour", "%d hours", num, num) << ", ";
seconds -= num * 3600;
}
if ((num = seconds / 60) > 0) {
- s << num << " " << tr("minute", "minutes", num) << ", ";
+ s << ntr("%d minute", "%d minutes", num, num) << ", ";
seconds -= num * 60;
}
- s << seconds << " " << tr("second", "seconds", seconds);
+ s << ntr("%d second", "%d seconds", seconds, seconds);
}
static void ShowTraffic (std::stringstream& s, uint64_t bytes)
@@ -124,11 +123,11 @@
s << std::fixed << std::setprecision(2);
auto numKBytes = (double) bytes / 1024;
if (numKBytes < 1024)
- s << numKBytes << " " << tr(/* tr: Kibibit */ "KiB");
+ s << tr(/* tr: Kibibyte */ "%.2f KiB", numKBytes);
else if (numKBytes < 1024 * 1024)
- s << numKBytes / 1024 << " " << tr(/* tr: Mebibit */ "MiB");
+ s << tr(/* tr: Mebibyte */ "%.2f MiB", numKBytes / 1024);
else
- s << numKBytes / 1024 / 1024 << " " << tr(/* tr: Gibibit */ "GiB");
+ s << tr(/* tr: Gibibyte */ "%.2f GiB", numKBytes / 1024 / 1024);
}
static void ShowTunnelDetails (std::stringstream& s, enum i2p::tunnel::TunnelState eState, bool explr, int bytes)
@@ -152,12 +151,13 @@
else stateText = tr("unknown");
s << "<span class=\"tunnel " << state << "\"> " << stateText << ((explr) ? " (" + tr("exploratory") + ")" : "") << "</span>, ";
- s << " " << (int) (bytes / 1024) << " " << tr(/* tr: Kibibit */ "KiB") << "\r\n";
+ ShowTraffic(s, bytes);
+ s << "\r\n";
}
static void SetLogLevel (const std::string& level)
{
- if (level == "none" || level == "error" || level == "warn" || level == "info" || level == "debug")
+ if (level == "none" || level == "critical" || level == "error" || level == "warn" || level == "info" || level == "debug")
i2p::log::Logger().SetLogLevel(level);
else {
LogPrint(eLogError, "HTTPServer: Unknown loglevel set attempted");
@@ -200,7 +200,7 @@
if (i2p::context.AcceptsTunnels () || i2p::tunnel::tunnels.CountTransitTunnels())
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">" << tr("Transit Tunnels") << "</a><br>\r\n";
s <<
- " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">" << tr ("Transports") << "</a><br>\r\n"
+ " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">" << tr("Transports") << "</a><br>\r\n"
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">" << tr("I2P tunnels") << "</a><br>\r\n";
if (i2p::client::context.GetSAMBridge ())
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSIONS << "\">" << tr("SAM sessions") << "</a><br>\r\n";
@@ -222,35 +222,40 @@
s << "<b>" << tr("ERROR") << ":</b> " << string << "<br>\r\n";
}
- static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, RouterError error)
+ static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, bool testing, RouterError error)
{
switch (status)
{
case eRouterStatusOK: s << tr("OK"); break;
- case eRouterStatusTesting: s << tr("Testing"); break;
case eRouterStatusFirewalled: s << tr("Firewalled"); break;
case eRouterStatusUnknown: s << tr("Unknown"); break;
case eRouterStatusProxy: s << tr("Proxy"); break;
case eRouterStatusMesh: s << tr("Mesh"); break;
- case eRouterStatusError:
+ default: s << tr("Unknown");
+ }
+ if (testing)
+ s << " (" << tr("Testing") << ")";
+ if (error != eRouterErrorNone)
+ {
+ switch (error)
{
- s << tr("Error");
- switch (error)
- {
- case eRouterErrorClockSkew:
- s << " - " << tr("Clock skew");
- break;
- case eRouterErrorOffline:
- s << " - " << tr("Offline");
- break;
- case eRouterErrorSymmetricNAT:
- s << " - " << tr("Symmetric NAT");
- break;
- default: ;
- }
+ case eRouterErrorClockSkew:
+ s << " - " << tr("Clock skew");
+ break;
+ case eRouterErrorOffline:
+ s << " - " << tr("Offline");
break;
+ case eRouterErrorSymmetricNAT:
+ s << " - " << tr("Symmetric NAT");
+ break;
+ case eRouterErrorFullConeNAT:
+ s << " - " << tr("Full cone NAT");
+ break;
+ case eRouterErrorNoDescriptors:
+ s << " - " << tr("No Descriptors");
+ break;
+ default: ;
}
- default: s << tr("Unknown");
}
}
@@ -260,12 +265,12 @@
ShowUptime(s, i2p::context.GetUptime ());
s << "<br>\r\n";
s << "<b>" << tr("Network status") << ":</b> ";
- ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetError ());
+ ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetTesting(), i2p::context.GetError ());
s << "<br>\r\n";
if (i2p::context.SupportsV6 ())
{
s << "<b>" << tr("Network status v6") << ":</b> ";
- ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetErrorV6 ());
+ ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetTestingV6(), i2p::context.GetErrorV6 ());
s << "<br>\r\n";
}
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
@@ -286,60 +291,69 @@
if (family.length () > 0)
s << "<b>"<< tr("Family") << ":</b> " << family << "<br>\r\n";
s << "<b>" << tr("Tunnel creation success rate") << ":</b> " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%<br>\r\n";
+ bool isTotalTCSR;
+ i2p::config::GetOption("http.showTotalTCSR", isTotalTCSR);
+ if (isTotalTCSR) {
+ s << "<b>" << tr("Total tunnel creation success rate") << ":</b> " << i2p::tunnel::tunnels.GetTotalTunnelCreationSuccessRate() << "%<br/>\r\n";
+ }
s << "<b>" << tr("Received") << ":</b> ";
ShowTraffic (s, i2p::transport::transports.GetTotalReceivedBytes ());
- s << " (" << (double) i2p::transport::transports.GetInBandwidth () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
+ s << " (" << tr(/* tr: Kibibyte/s */ "%.2f KiB/s", (double) i2p::transport::transports.GetInBandwidth15s () / 1024) << ")<br>\r\n";
s << "<b>" << tr("Sent") << ":</b> ";
ShowTraffic (s, i2p::transport::transports.GetTotalSentBytes ());
- s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
+ s << " (" << tr(/* tr: Kibibyte/s */ "%.2f KiB/s", (double) i2p::transport::transports.GetOutBandwidth15s () / 1024) << ")<br>\r\n";
s << "<b>" << tr("Transit") << ":</b> ";
ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ());
- s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
+ s << " (" << tr(/* tr: Kibibyte/s */ "%.2f KiB/s", (double) i2p::transport::transports.GetTransitBandwidth15s () / 1024) << ")<br>\r\n";
s << "<b>" << tr("Data path") << ":</b> " << i2p::fs::GetUTF8DataDir() << "<br>\r\n";
s << "<div class='slide'>";
if ((outputFormat == OutputFormatEnum::forWebConsole) || !includeHiddenContent) {
s << "<label for=\"slide-info\">" << tr("Hidden content. Press on text to see.") << "</label>\r\n<input type=\"checkbox\" id=\"slide-info\" />\r\n<div class=\"slidecontent\">\r\n";
}
- if (includeHiddenContent) {
+ if (includeHiddenContent)
+ {
s << "<b>" << tr("Router Ident") << ":</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
if (!i2p::context.GetRouterInfo().GetProperty("family").empty())
s << "<b>" << tr("Router Family") << ":</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
s << "<b>" << tr("Router Caps") << ":</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
s << "<b>" << tr("Version") << ":</b> " VERSION "<br>\r\n";
s << "<b>"<< tr("Our external address") << ":</b>" << "<br>\r\n<table class=\"extaddr\"><tbody>\r\n";
- for (const auto& address : i2p::context.GetRouterInfo().GetAddresses())
+ auto addresses = i2p::context.GetRouterInfo().GetAddresses ();
+ if (addresses)
{
- s << "<tr>\r\n<td>";
- switch (address->transportStyle)
+ for (const auto& address : *addresses)
{
- case i2p::data::RouterInfo::eTransportNTCP:
- s << "NTCP2";
- break;
- case i2p::data::RouterInfo::eTransportSSU:
- s << "SSU";
- break;
- case i2p::data::RouterInfo::eTransportSSU2:
- s << "SSU2";
- break;
- default:
- s << tr("Unknown");
- }
- if (address->IsV6 ())
- {
- if (address->IsV4 ()) s << "v4";
- s << "v6";
- }
- s << "</td>\r\n";
- if (address->published)
- s << "<td>" << address->host.to_string() << ":" << address->port << "</td>\r\n";
- else
- {
- s << "<td>" << tr("supported");
- if (address->port)
- s << " :" << address->port;
+ if (!address) continue;
+ s << "<tr>\r\n<td>";
+ switch (address->transportStyle)
+ {
+ case i2p::data::RouterInfo::eTransportNTCP2:
+ s << "NTCP2";
+ break;
+ case i2p::data::RouterInfo::eTransportSSU2:
+ s << "SSU2";
+ break;
+ default:
+ s << tr("Unknown");
+ }
+ bool v6 = address->IsV6 ();
+ if (v6)
+ {
+ if (address->IsV4 ()) s << "v4";
+ s << "v6";
+ }
s << "</td>\r\n";
+ if (address->published)
+ s << "<td>" << (v6 ? "[" : "") << address->host.to_string() << (v6 ? "]:" : ":") << address->port << "</td>\r\n";
+ else
+ {
+ s << "<td>" << tr(/* tr: Shown when router doesn't publish itself and have "Firewalled" state */ "supported");
+ if (address->port)
+ s << " :" << address->port;
+ s << "</td>\r\n";
+ }
+ s << "</tr>\r\n";
}
- s << "</tr>\r\n";
}
s << "</tbody></table>\r\n";
}
@@ -409,8 +423,12 @@
static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest, uint32_t token)
{
+ s << "<b>Base32:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"1\">";
+ s << dest->GetIdentHash ().ToBase32 () << "</textarea><br>\r\n<br>\r\n";
+
s << "<b>Base64:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"8\">";
s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
+
if (dest->IsEncryptedLeaseSet ())
{
i2p::data::BlindedPublicKey blinded (dest->GetIdentity (), dest->IsPerClientAuth ());
@@ -422,12 +440,11 @@
if (dest->IsPublic() && token && !dest->IsEncryptedLeaseSet ())
{
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
- auto base32 = dest->GetIdentHash ().ToBase32 ();
s << "<div class='slide'><label for='slide-regaddr'><b>" << tr("Address registration line") << "</b></label>\r\n<input type=\"checkbox\" id=\"slide-regaddr\" />\r\n<div class=\"slidecontent\">\r\n"
"<form method=\"get\" action=\"" << webroot << "\">\r\n"
" <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_GET_REG_STRING << "\">\r\n"
" <input type=\"hidden\" name=\"token\" value=\"" << token << "\">\r\n"
- " <input type=\"hidden\" name=\"b32\" value=\"" << base32 << "\">\r\n"
+ " <input type=\"hidden\" name=\"b32\" value=\"" << dest->GetIdentHash ().ToBase32 () << "\">\r\n"
" <b>" << tr("Domain") << ":</b>\r\n<input type=\"text\" maxlength=\"67\" name=\"name\" placeholder=\"domain.i2p\" required>\r\n"
" <button type=\"submit\">" << tr("Generate") << "</button>\r\n"
"</form>\r\n<small>" << tr("<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.") << "</small>\r\n</div>\r\n</div>\r\n<br>\r\n";
@@ -436,9 +453,23 @@
if (dest->GetNumRemoteLeaseSets())
{
s << "<div class='slide'><label for='slide-lease'><b>" << tr("LeaseSets") << ":</b> <i>" << dest->GetNumRemoteLeaseSets ()
- << "</i></label>\r\n<input type=\"checkbox\" id=\"slide-lease\" />\r\n<div class=\"slidecontent\">\r\n<table><thead><th>"<< tr("Address") << "</th><th>" << tr("Type") << "</th><th>" << tr("EncType") << "</th></thead><tbody class=\"tableitem\">";
+ << "</i></label>\r\n<input type=\"checkbox\" id=\"slide-lease\" />\r\n<div class=\"slidecontent\">\r\n"
+ << "<table><thead>"
+ << "<th>" << tr("Address") << "</th>"
+ << "<th style=\"width:5px;\"> </th>" // LeaseSet expiration button column
+ << "<th>" << tr("Type") << "</th>"
+ << "<th>" << tr("EncType") << "</th>"
+ << "</thead><tbody class=\"tableitem\">";
for(auto& it: dest->GetLeaseSets ())
- s << "<tr><td>" << it.first.ToBase32 () << "</td><td>" << (int)it.second->GetStoreType () << "</td><td>" << (int)it.second->GetEncryptionType () <<"</td></tr>\r\n";
+ {
+ s << "<tr>"
+ << "<td>" << it.first.ToBase32 () << "</td>"
+ << "<td><a class=\"button\" href=\"/?cmd=" << HTTP_COMMAND_EXPIRELEASE<< "&b32=" << dest->GetIdentHash ().ToBase32 ()
+ << "&lease=" << it.first.ToBase32 () << "&token=" << token << "\" title=\"" << tr("Expire LeaseSet") << "\"> ✘ </a></td>"
+ << "<td>" << (int)it.second->GetStoreType () << "</td>"
+ << "<td>" << (int)it.second->GetEncryptionType () <<"</td>"
+ << "</tr>\r\n";
+ }
s << "</tbody></table>\r\n</div>\r\n</div>\r\n<br>\r\n";
} else
s << "<b>" << tr("LeaseSets") << ":</b> <i>0</i><br>\r\n<br>\r\n";
@@ -461,7 +492,7 @@
}
s << "⇒ " << it->GetTunnelID () << ":me";
if (it->LatencyIsKnown())
- s << " ( " << it->GetMeanLatency() << tr(/* tr: Milliseconds */ "ms") << " )";
+ s << " ( " << tr(/* tr: Milliseconds */ "%dms", it->GetMeanLatency()) << " )";
ShowTunnelDetails(s, it->GetState (), false, it->GetNumReceivedBytes ());
s << "</div>\r\n";
}
@@ -481,22 +512,26 @@
);
}
if (it->LatencyIsKnown())
- s << " ( " << it->GetMeanLatency() << tr("ms") << " )";
+ s << " ( " << tr("%dms", it->GetMeanLatency()) << " )";
ShowTunnelDetails(s, it->GetState (), false, it->GetNumSentBytes ());
s << "</div>\r\n";
}
}
s << "<br>\r\n";
- s << "<b>" << tr("Tags") << "</b><br>\r\n" << tr("Incoming") << ": <i>" << dest->GetNumIncomingTags () << "</i><br>\r\n";
+ s << "<b>" << tr("Tags") << "</b><br>\r\n"
+ << tr("Incoming") << ": <i>" << dest->GetNumIncomingTags () << "</i><br>\r\n";
if (!dest->GetSessions ().empty ()) {
std::stringstream tmp_s; uint32_t out_tags = 0;
for (const auto& it: dest->GetSessions ()) {
tmp_s << "<tr><td>" << i2p::client::context.GetAddressBook ().ToAddress(it.first) << "</td><td>" << it.second->GetNumOutgoingTags () << "</td></tr>\r\n";
out_tags += it.second->GetNumOutgoingTags ();
}
- s << "<div class='slide'><label for='slide-tags'>" << tr("Outgoing") << ": <i>" << out_tags << "</i></label>\r\n<input type=\"checkbox\" id=\"slide-tags\" />\r\n"
- << "<div class=\"slidecontent\">\r\n<table>\r\n<thead><th>" << tr("Destination") << "</th><th>" << tr("Amount") << "</th></thead>\r\n<tbody class=\"tableitem\">\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n";
+ s << "<div class='slide'><label for='slide-tags'>" << tr("Outgoing") << ": <i>" << out_tags << "</i></label>\r\n"
+ << "<input type=\"checkbox\" id=\"slide-tags\" />\r\n"
+ << "<div class=\"slidecontent\">\r\n"
+ << "<table>\r\n<thead><th>" << tr("Destination") << "</th><th>" << tr("Amount") << "</th></thead>\r\n"
+ << "<tbody class=\"tableitem\">\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n";
} else
s << tr("Outgoing") << ": <i>0</i><br>\r\n";
s << "<br>\r\n";
@@ -511,8 +546,11 @@
tmp_s << "<tr><td>" << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetDestination ()) << "</td><td>" << it.second->GetState () << "</td></tr>\r\n";
ecies_sessions++;
}
- s << "<div class='slide'><label for='slide-ecies-sessions'>" << tr("Tags sessions") << ": <i>" << ecies_sessions << "</i></label>\r\n<input type=\"checkbox\" id=\"slide-ecies-sessions\" />\r\n"
- << "<div class=\"slidecontent\">\r\n<table>\r\n<thead><th>" << tr("Destination") << "</th><th>" << tr("Status") << "</th></thead>\r\n<tbody class=\"tableitem\">\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n";
+ s << "<div class='slide'><label for='slide-ecies-sessions'>" << tr("Tags sessions") << ": <i>" << ecies_sessions << "</i></label>\r\n"
+ << "<input type=\"checkbox\" id=\"slide-ecies-sessions\" />\r\n"
+ << "<div class=\"slidecontent\">\r\n<table>\r\n"
+ << "<thead><th>" << tr("Destination") << "</th><th>" << tr("Status") << "</th></thead>\r\n"
+ << "<tbody class=\"tableitem\">\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n";
} else
s << tr("Tags sessions") << ": <i>0</i><br>\r\n";
s << "<br>\r\n";
@@ -535,7 +573,7 @@
<< tr("Streams")
<< "</caption>\r\n<thead>\r\n<tr>"
<< "<th style=\"width:25px;\">StreamID</th>"
- << "<th style=\"width:5px;\" \\>" // Stream closing button column
+ << "<th style=\"width:5px;\"> </th>" // Stream closing button column
<< "<th class=\"streamdest\">Destination</th>"
<< "<th>Sent</th>"
<< "<th>Received</th>"
@@ -572,6 +610,8 @@
}
s << "</tbody>\r\n</table>";
}
+ else
+ ShowError(s, tr("Such destination is not found"));
}
void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id)
@@ -606,7 +646,10 @@
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET)
ls.reset (new i2p::data::LeaseSet (leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
else
- ls.reset (new i2p::data::LeaseSet2 (storeType, leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
+ {
+ ls.reset (new i2p::data::LeaseSet2 (storeType));
+ ls->Update (leaseSet->GetBuffer(), leaseSet->GetBufferLen(), false);
+ }
if (!ls) return;
s << "<div class=\"leaseset listitem";
if (ls->IsExpired())
@@ -637,7 +680,7 @@
}
else if (!i2p::context.IsFloodfill ())
{
- s << "<b>" << tr("LeaseSets") << ":</b> " << tr("not floodfill") << ".<br>\r\n";
+ s << "<b>" << tr("LeaseSets") << ":</b> " << tr(/* Message on LeaseSets page */ "floodfill mode is disabled") << ".<br>\r\n";
}
else
{
@@ -666,7 +709,7 @@
}
s << "⇒ " << it->GetTunnelID () << ":me";
if (it->LatencyIsKnown())
- s << " ( " << it->GetMeanLatency() << tr("ms") << " )";
+ s << " ( " << tr("%dms", it->GetMeanLatency()) << " )";
ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumReceivedBytes ());
s << "</div>\r\n";
}
@@ -686,7 +729,7 @@
);
}
if (it->LatencyIsKnown())
- s << " ( " << it->GetMeanLatency() << tr("ms") << " )";
+ s << " ( " << tr("%dms", it->GetMeanLatency()) << " )";
ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumSentBytes ());
s << "</div>\r\n";
}
@@ -699,8 +742,7 @@
s << "<b>" << tr("Router commands") << "</b><br>\r\n<br>\r\n<div class=\"commands\">\r\n";
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">" << tr("Run peer test") << "</a><br>\r\n";
-
- // s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n";
+ s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_RELOAD_TUNNELS_CONFIG << "&token=" << token << "\">" << tr("Reload tunnels configuration") << "</a><br>\r\n";
if (i2p::context.AcceptsTunnels ())
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">" << tr("Decline transit tunnels") << "</a><br>\r\n";
@@ -725,19 +767,21 @@
s << "<br>\r\n<small>" << tr("<b>Note:</b> any action done here are not persistent and not changes your config files.") << "</small>\r\n<br>\r\n";
+ auto loglevel = i2p::log::Logger().GetLogLevel();
s << "<b>" << tr("Logging level") << "</b><br>\r\n";
- s << " <a class=\"button\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\"> none </a> \r\n";
- s << " <a class=\"button\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\"> error </a> \r\n";
- s << " <a class=\"button\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=warn&token=" << token << "\"> warn </a> \r\n";
- s << " <a class=\"button\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=info&token=" << token << "\"> info </a> \r\n";
- s << " <a class=\"button\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=debug&token=" << token << "\"> debug </a><br>\r\n<br>\r\n";
+ s << " <a class=\"button" << (loglevel == eLogNone ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\"> none </a> \r\n";
+ s << " <a class=\"button" << (loglevel == eLogCritical ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=critical&token=" << token << "\"> critical </a> \r\n";
+ s << " <a class=\"button" << (loglevel == eLogError ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\"> error </a> \r\n";
+ s << " <a class=\"button" << (loglevel == eLogWarning ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=warn&token=" << token << "\"> warn </a> \r\n";
+ s << " <a class=\"button" << (loglevel == eLogInfo ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=info&token=" << token << "\"> info </a> \r\n";
+ s << " <a class=\"button" << (loglevel == eLogDebug ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=debug&token=" << token << "\"> debug </a><br>\r\n<br>\r\n";
- uint16_t maxTunnels = GetMaxNumTransitTunnels ();
+ uint16_t maxTunnels = i2p::tunnel::tunnels.GetMaxNumTransitTunnels ();
s << "<b>" << tr("Transit tunnels limit") << "</b><br>\r\n";
s << "<form method=\"get\" action=\"" << webroot << "\">\r\n";
s << " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_LIMITTRANSIT << "\">\r\n";
s << " <input type=\"hidden\" name=\"token\" value=\"" << token << "\">\r\n";
- s << " <input type=\"number\" min=\"0\" max=\"65535\" name=\"limit\" value=\"" << maxTunnels << "\">\r\n";
+ s << " <input type=\"number\" min=\"0\" max=\"" << TRANSIT_TUNNELS_LIMIT <<"\" name=\"limit\" value=\"" << maxTunnels << "\">\r\n";
s << " <button type=\"submit\">" << tr("Change") << "</button>\r\n";
s << "</form>\r\n<br>\r\n";
@@ -767,56 +811,71 @@
{
if (i2p::tunnel::tunnels.CountTransitTunnels())
{
- s << "<b>" << tr("Transit Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
+ s << "<b>" << tr("Transit Tunnels") << ":</b><br>\r\n";
+ s << "<table><thead><th>⇒</th><th>ID</th><th>⇒</th><th>" << tr("Amount") << "</th></thead><tbody class=\"tableitem\">";
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ())
{
- s << "<div class=\"listitem\">\r\n";
if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it))
- s << it->GetTunnelID () << " ⇒ ";
+ s << "<tr><td></td><td>" << it->GetTunnelID () << "</td><td>⇒</td><td>";
else if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelEndpoint>(it))
- s << " ⇒ " << it->GetTunnelID ();
+ s << "<tr><td>⇒</td><td>" << it->GetTunnelID () << "</td><td></td><td>";
else
- s << " ⇒ " << it->GetTunnelID () << " ⇒ ";
- s << " " << it->GetNumTransmittedBytes () << "</div>\r\n";
+ s << "<tr><td>⇒</td><td>" << it->GetTunnelID () << "</td><td>⇒</td><td>";
+ ShowTraffic(s, it->GetNumTransmittedBytes ());
+ s << "</td></tr>\r\n";
}
- s << "</div>\r\n";
+ s << "</tbody></table>\r\n";
}
else
{
- s << "<b>" << tr("Transit Tunnels") << ":</b> " << tr("no transit tunnels currently built") << ".<br>\r\n";
+ s << "<b>" << tr("Transit Tunnels") << ":</b> " << tr(/* Message on transit tunnels page */ "no transit tunnels currently built") << ".<br>\r\n";
}
}
template<typename Sessions>
static void ShowTransportSessions (std::stringstream& s, const Sessions& sessions, const std::string name)
{
+ auto comp = [](typename Sessions::mapped_type a, typename Sessions::mapped_type b)
+ { return a->GetRemoteEndpoint() < b->GetRemoteEndpoint(); };
+ std::set<typename Sessions::mapped_type, decltype(comp)> sortedSessions(comp);
+ for (const auto& it : sessions)
+ {
+ auto ret = sortedSessions.insert(it.second);
+ if (!ret.second)
+ LogPrint(eLogError, "HTTPServer: Duplicate remote endpoint detected: ", (*ret.first)->GetRemoteEndpoint());
+ }
std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0;
- for (const auto& it: sessions )
+ for (const auto& it: sortedSessions)
{
- auto endpoint = it.second->GetRemoteEndpoint ();
- if (it.second && it.second->IsEstablished () && endpoint.address ().is_v4 ())
+ auto endpoint = it->GetRemoteEndpoint ();
+ if (it && it->IsEstablished () && endpoint.address ().is_v4 ())
{
tmp_s << "<div class=\"listitem\">\r\n";
- if (it.second->IsOutgoing ()) tmp_s << " ⇒ ";
- tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
+ if (it->IsOutgoing ()) tmp_s << " ⇒ ";
+ tmp_s << i2p::data::GetIdentHashAbbreviation (it->GetRemoteIdentity ()->GetIdentHash ()) << ": "
<< endpoint.address ().to_string () << ":" << endpoint.port ();
- if (!it.second->IsOutgoing ()) tmp_s << " ⇒ ";
- tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
- if (it.second->GetRelayTag ())
- tmp_s << " [itag:" << it.second->GetRelayTag () << "]";
+ if (!it->IsOutgoing ()) tmp_s << " ⇒ ";
+ tmp_s << " [" << it->GetNumSentBytes () << ":" << it->GetNumReceivedBytes () << "]";
+ if (it->GetRelayTag ())
+ tmp_s << " [itag:" << it->GetRelayTag () << "]";
+ if (it->GetSendQueueSize () > 0)
+ tmp_s << " [queue:" << it->GetSendQueueSize () << "]";
+ if (it->IsSlow ()) tmp_s << " [slow]";
tmp_s << "</div>\r\n" << std::endl;
cnt++;
}
- if (it.second && it.second->IsEstablished () && endpoint.address ().is_v6 ())
+ if (it && it->IsEstablished () && endpoint.address ().is_v6 ())
{
tmp_s6 << "<div class=\"listitem\">\r\n";
- if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
- tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
+ if (it->IsOutgoing ()) tmp_s6 << " ⇒ ";
+ tmp_s6 << i2p::data::GetIdentHashAbbreviation (it->GetRemoteIdentity ()->GetIdentHash ()) << ": "
<< "[" << endpoint.address ().to_string () << "]:" << endpoint.port ();
- if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
- tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
- if (it.second->GetRelayTag ())
- tmp_s6 << " [itag:" << it.second->GetRelayTag () << "]";
+ if (!it->IsOutgoing ()) tmp_s6 << " ⇒ ";
+ tmp_s6 << " [" << it->GetNumSentBytes () << ":" << it->GetNumReceivedBytes () << "]";
+ if (it->GetRelayTag ())
+ tmp_s6 << " [itag:" << it->GetRelayTag () << "]";
+ if (it->GetSendQueueSize () > 0)
+ tmp_s6 << " [queue:" << it->GetSendQueueSize () << "]";
tmp_s6 << "</div>\r\n" << std::endl;
cnt6++;
}
@@ -845,46 +904,6 @@
if (!sessions.empty ())
ShowTransportSessions (s, sessions, "NTCP2");
}
- auto ssuServer = i2p::transport::transports.GetSSUServer ();
- if (ssuServer)
- {
- auto sessions = ssuServer->GetSessions ();
- if (!sessions.empty ())
- {
- s << "<div class='slide'><label for='slide_ssu'><b>SSU</b> ( " << (int) sessions.size() << " )</label>\r\n<input type=\"checkbox\" id=\"slide_ssu\" />\r\n<div class=\"slidecontent list\">";
- for (const auto& it: sessions)
- {
- s << "<div class=\"listitem\">\r\n";
- auto endpoint = it.second->GetRemoteEndpoint ();
- if (it.second->IsOutgoing ()) s << " ⇒ ";
- s << endpoint.address ().to_string () << ":" << endpoint.port ();
- if (!it.second->IsOutgoing ()) s << " ⇒ ";
- s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
- if (it.second->GetRelayTag ())
- s << " [itag:" << it.second->GetRelayTag () << "]";
- s << "</div>\r\n" << std::endl;
- }
- s << "</div>\r\n</div>\r\n";
- }
- auto sessions6 = ssuServer->GetSessionsV6 ();
- if (!sessions6.empty ())
- {
- s << "<div class='slide'><label for='slide_ssuv6'><b>SSUv6</b> ( " << (int) sessions6.size() << " )</label>\r\n<input type=\"checkbox\" id=\"slide_ssuv6\" />\r\n<div class=\"slidecontent list\">";
- for (const auto& it: sessions6)
- {
- s << "<div class=\"listitem\">\r\n";
- auto endpoint = it.second->GetRemoteEndpoint ();
- if (it.second->IsOutgoing ()) s << " ⇒ ";
- s << "[" << endpoint.address ().to_string () << "]:" << endpoint.port ();
- if (!it.second->IsOutgoing ()) s << " ⇒ ";
- s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
- if (it.second->GetRelayTag ())
- s << " [itag:" << it.second->GetRelayTag () << "]";
- s << "</div>\r\n" << std::endl;
- }
- s << "</div>\r\n</div>\r\n";
- }
- }
auto ssu2Server = i2p::transport::transports.GetSSU2Server ();
if (ssu2Server)
{
@@ -916,7 +935,7 @@
s << "</div>\r\n";
}
else
- s << "<b>" << tr("SAM sessions") << ":</b> " << tr("no sessions currently running") << ".<br>\r\n";
+ s << "<b>" << tr("SAM sessions") << ":</b> " << tr(/* Message on SAM sessions page */ "no sessions currently running") << ".<br>\r\n";
}
void ShowSAMSession (std::stringstream& s, const std::string& id)
@@ -960,34 +979,42 @@
void ShowI2PTunnels (std::stringstream& s)
{
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
- s << "<b>" << tr("Client Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
- for (auto& it: i2p::client::context.GetClientTunnels ())
- {
- auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
- s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
- s << it.second->GetName () << "</a> ⇐ ";
- s << i2p::client::context.GetAddressBook ().ToAddress(ident);
- s << "</div>\r\n"<< std::endl;
- }
+
+ auto& clientTunnels = i2p::client::context.GetClientTunnels ();
auto httpProxy = i2p::client::context.GetHttpProxy ();
- if (httpProxy)
- {
- auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
- s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
- s << "HTTP " << tr("Proxy") << "</a> ⇐ ";
- s << i2p::client::context.GetAddressBook ().ToAddress(ident);
- s << "</div>\r\n"<< std::endl;
- }
auto socksProxy = i2p::client::context.GetSocksProxy ();
- if (socksProxy)
+ if (!clientTunnels.empty () || httpProxy || socksProxy)
{
- auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
- s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
- s << "SOCKS " << tr("Proxy") << "</a> ⇐ ";
- s << i2p::client::context.GetAddressBook ().ToAddress(ident);
- s << "</div>\r\n"<< std::endl;
+ s << "<b>" << tr("Client Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
+ if (!clientTunnels.empty ())
+ {
+ for (auto& it: clientTunnels)
+ {
+ auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
+ s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
+ s << it.second->GetName () << "</a> ⇐ ";
+ s << i2p::client::context.GetAddressBook ().ToAddress(ident);
+ s << "</div>\r\n"<< std::endl;
+ }
+ }
+ if (httpProxy)
+ {
+ auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
+ s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
+ s << "HTTP " << tr("Proxy") << "</a> ⇐ ";
+ s << i2p::client::context.GetAddressBook ().ToAddress(ident);
+ s << "</div>\r\n"<< std::endl;
+ }
+ if (socksProxy)
+ {
+ auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
+ s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
+ s << "SOCKS " << tr("Proxy") << "</a> ⇐ ";
+ s << i2p::client::context.GetAddressBook ().ToAddress(ident);
+ s << "</div>\r\n"<< std::endl;
+ }
+ s << "</div>\r\n";
}
- s << "</div>\r\n";
auto& serverTunnels = i2p::client::context.GetServerTunnels ();
if (!serverTunnels.empty ()) {
@@ -1025,7 +1052,7 @@
for (auto& it: serverForwards)
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
- s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
+ s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << it.second->GetName () << "</a> ⇐ ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "</div>\r\n"<< std::endl;
@@ -1235,7 +1262,7 @@
url.parse_query(params);
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
- std::string redirect = "5; url=" + webroot + "?page=commands";
+ std::string redirect = std::to_string(COMMAND_REDIRECT_TIMEOUT) + "; url=" + webroot + "?page=commands";
std::string token = params["token"];
if (token.empty () || m_Tokens.find (std::stoi (token)) == m_Tokens.end ())
@@ -1247,7 +1274,7 @@
std::string cmd = params["cmd"];
if (cmd == HTTP_COMMAND_RUN_PEER_TEST)
i2p::transport::transports.PeerTest ();
- else if (cmd == HTTP_COMMAND_RELOAD_CONFIG)
+ else if (cmd == HTTP_COMMAND_RELOAD_TUNNELS_CONFIG)
i2p::client::context.ReloadConfig ();
else if (cmd == HTTP_COMMAND_ENABLE_TRANSIT)
i2p::context.SetAcceptsTunnels (true);
@@ -1309,20 +1336,50 @@
s << "<b>" << tr("ERROR") << "</b>: " << tr("StreamID can't be null") << "<br>\r\n<br>\r\n";
s << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">" << tr("Return to destination page") << "</a><br>\r\n";
- s << "<p>" << tr("You will be redirected in 5 seconds") << "</b>";
- redirect = "5; url=" + webroot + "?page=local_destination&b32=" + b32;
+ s << "<p>" << tr("You will be redirected in %d seconds", COMMAND_REDIRECT_TIMEOUT) << "</b>";
+ redirect = std::to_string(COMMAND_REDIRECT_TIMEOUT) + "; url=" + webroot + "?page=local_destination&b32=" + b32;
+ res.add_header("Refresh", redirect.c_str());
+ return;
+ }
+ else if (cmd == HTTP_COMMAND_EXPIRELEASE)
+ {
+ std::string b32 = params["b32"];
+ std::string lease = params["lease"];
+
+ i2p::data::IdentHash ident, leaseident;
+ ident.FromBase32 (b32);
+ leaseident.FromBase32 (lease);
+ auto dest = i2p::client::context.FindLocalDestination (ident);
+
+ if (dest)
+ {
+ auto leaseset = dest->FindLeaseSet (leaseident);
+ if (leaseset)
+ {
+ leaseset->ExpireLease ();
+ s << "<b>" << tr("SUCCESS") << "</b>: " << tr("LeaseSet expiration time updated") << "<br>\r\n<br>\r\n";
+ }
+ else
+ s << "<b>" << tr("ERROR") << "</b>: " << tr("LeaseSet is not found or already expired") << "<br>\r\n<br>\r\n";
+ }
+ else
+ s << "<b>" << tr("ERROR") << "</b>: " << tr("Destination not found") << "<br>\r\n<br>\r\n";
+
+ s << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">" << tr("Return to destination page") << "</a><br>\r\n";
+ s << "<p>" << tr("You will be redirected in %d seconds", COMMAND_REDIRECT_TIMEOUT) << "</b>";
+ redirect = std::to_string(COMMAND_REDIRECT_TIMEOUT) + "; url=" + webroot + "?page=local_destination&b32=" + b32;
res.add_header("Refresh", redirect.c_str());
return;
}
else if (cmd == HTTP_COMMAND_LIMITTRANSIT)
{
uint32_t limit = std::stoul(params["limit"], nullptr);
- if (limit > 0 && limit <= 65535)
- SetMaxNumTransitTunnels (limit);
+ if (limit > 0 && limit <= TRANSIT_TUNNELS_LIMIT)
+ i2p::tunnel::tunnels.SetMaxNumTransitTunnels (limit);
else {
- s << "<b>" << tr("ERROR") << "</b>: " << tr("Transit tunnels count must not exceed 65535") << "\r\n<br>\r\n<br>\r\n";
+ s << "<b>" << tr("ERROR") << "</b>: " << tr("Transit tunnels count must not exceed %d", TRANSIT_TUNNELS_LIMIT) << "\r\n<br>\r\n<br>\r\n";
s << "<a href=\"" << webroot << "?page=commands\">" << tr("Back to commands list") << "</a>\r\n<br>\r\n";
- s << "<p>" << tr("You will be redirected in 5 seconds") << "</b>";
+ s << "<p>" << tr("You will be redirected in %d seconds", COMMAND_REDIRECT_TIMEOUT) << "</b>";
res.add_header("Refresh", redirect.c_str());
return;
}
@@ -1397,7 +1454,7 @@
s << "<b>" << tr("SUCCESS") << "</b>: " << tr("Command accepted") << "<br><br>\r\n";
s << "<a href=\"" << webroot << "?page=commands\">" << tr("Back to commands list") << "</a><br>\r\n";
- s << "<p>" << tr("You will be redirected in 5 seconds") << "</b>";
+ s << "<p>" << tr("You will be redirected in %d seconds", COMMAND_REDIRECT_TIMEOUT) << "</b>";
res.add_header("Refresh", redirect.c_str());
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/daemon/HTTPServer.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -24,6 +24,8 @@
{
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds
+ const int COMMAND_REDIRECT_TIMEOUT = 5; // in seconds
+ const int TRANSIT_TUNNELS_LIMIT = 65535;
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
{
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/daemon/HTTPServerResources.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -38,7 +38,7 @@
"@media (prefers-color-scheme: dark) { :root { --main-bg-color: #242424; --main-text-color: #17ab5c; --main-link-color: #bf64b7; --main-link-hover-color: #000000; } }\r\n"
"body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: var(--main-bg-color); color: var(--main-text-color); }\r\n"
"a, .slide label { text-decoration: none; color: var(--main-link-color); }\r\n"
- "a:hover, .slide label:hover, button[type=submit]:hover { color: var(--main-link-hover-color); background: var(--main-link-color); }\r\n"
+ "a:hover, a.button.selected, .slide label:hover, button[type=submit]:hover { color: var(--main-link-hover-color); background: var(--main-link-color); }\r\n"
"a.button { appearance: button; text-decoration: none; padding: 0 5px; border: 1px solid var(--main-link-color); }\r\n"
".header { font-size: 2.5em; text-align: center; margin: 1em 0; color: var(--main-link-color); }\r\n"
".wrapper { margin: 0 auto; padding: 1em; max-width: 64em; }\r\n"
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/daemon/I2PControl.cpp
^
|
@@ -14,25 +14,17 @@
// Use global placeholders from boost introduced when local_time.hpp is loaded
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
-#include <boost/lexical_cast.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
-#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/json_parser.hpp>
+#include <boost/lexical_cast.hpp>
-#include "Crypto.h"
#include "FS.h"
#include "Log.h"
#include "Config.h"
#include "NetDb.hpp"
-#include "RouterContext.h"
-#include "Daemon.h"
#include "Tunnel.h"
-#include "Timestamp.h"
-#include "Transports.h"
-#include "version.h"
-#include "util.h"
-#include "ClientContext.h"
+#include "Daemon.h"
#include "I2PControl.h"
namespace i2p
@@ -69,44 +61,18 @@
m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler;
m_MethodHandlers["Echo"] = &I2PControlService::EchoHandler;
m_MethodHandlers["I2PControl"] = &I2PControlService::I2PControlHandler;
- m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler;
+ m_MethodHandlers["RouterInfo"] = &I2PControlHandlers::RouterInfoHandler;
m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler;
- m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler;
- m_MethodHandlers["ClientServicesInfo"] = &I2PControlService::ClientServicesInfoHandler;
+ m_MethodHandlers["NetworkSetting"] = &I2PControlHandlers::NetworkSettingHandler;
+ m_MethodHandlers["ClientServicesInfo"] = &I2PControlHandlers::ClientServicesInfoHandler;
// I2PControl
m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
- // RouterInfo
- m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler;
- m_RouterInfoHandlers["i2p.router.version"] = &I2PControlService::VersionHandler;
- m_RouterInfoHandlers["i2p.router.status"] = &I2PControlService::StatusHandler;
- m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlService::NetDbKnownPeersHandler;
- m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlService::NetDbActivePeersHandler;
- m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlService::InboundBandwidth1S;
- m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S;
- m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler;
- m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler;
- m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = &I2PControlService::TunnelsSuccessRateHandler;
- m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes;
- m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes;
-
// RouterManager
m_RouterManagerHandlers["Reseed"] = &I2PControlService::ReseedHandler;
m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler;
m_RouterManagerHandlers["ShutdownGraceful"] = &I2PControlService::ShutdownGracefulHandler;
-
- // NetworkSetting
- m_NetworkSettingHandlers["i2p.router.net.bw.in"] = &I2PControlService::InboundBandwidthLimit;
- m_NetworkSettingHandlers["i2p.router.net.bw.out"] = &I2PControlService::OutboundBandwidthLimit;
-
- // ClientServicesInfo
- m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlService::I2PTunnelInfoHandler;
- m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlService::HTTPProxyInfoHandler;
- m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlService::SOCKSInfoHandler;
- m_ClientServicesInfoHandlers["SAM"] = &I2PControlService::SAMInfoHandler;
- m_ClientServicesInfoHandlers["BOB"] = &I2PControlService::BOBInfoHandler;
- m_ClientServicesInfoHandlers["I2CP"] = &I2PControlService::I2CPInfoHandler;
}
I2PControlService::~I2PControlService ()
@@ -280,37 +246,6 @@
}
}
- void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, int value) const
- {
- ss << "\"" << name << "\":" << value;
- }
-
- void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes) const
- {
- ss << "\"" << name << "\":";
- if (value.length () > 0)
- {
- if (quotes)
- ss << "\"" << value << "\"";
- else
- ss << value;
- }
- else
- ss << "null";
- }
-
- void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, double value) const
- {
- ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value;
- }
-
- void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const
- {
- std::ostringstream buf;
- boost::property_tree::write_json (buf, value, false);
- ss << "\"" << name << "\":" << buf.str();
- }
-
void I2PControlService::SendResponse (std::shared_ptr<ssl_socket> socket,
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml)
{
@@ -396,91 +331,6 @@
m_Tokens.clear ();
}
-// RouterInfo
-
- void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
- {
- bool first = true;
- for (auto it = params.begin (); it != params.end (); it++)
- {
- LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first);
- auto it1 = m_RouterInfoHandlers.find (it->first);
- if (it1 != m_RouterInfoHandlers.end ())
- {
- if (!first) results << ",";
- else first = false;
- (this->*(it1->second))(results);
- }
- else
- LogPrint (eLogError, "I2PControl: RouterInfo unknown request ", it->first);
- }
- }
-
- void I2PControlService::UptimeHandler (std::ostringstream& results)
- {
- InsertParam (results, "i2p.router.uptime", std::to_string (i2p::context.GetUptime ()*1000LL), false);
- }
-
- void I2PControlService::VersionHandler (std::ostringstream& results)
- {
- InsertParam (results, "i2p.router.version", VERSION);
- }
-
- void I2PControlService::StatusHandler (std::ostringstream& results)
- {
- auto dest = i2p::client::context.GetSharedLocalDestination ();
- InsertParam (results, "i2p.router.status", (dest && dest->IsReady ()) ? "1" : "0");
- }
-
- void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results)
- {
- InsertParam (results, "i2p.router.netdb.knownpeers", i2p::data::netdb.GetNumRouters ());
- }
-
- void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results)
- {
- InsertParam (results, "i2p.router.netdb.activepeers", (int)i2p::transport::transports.GetPeers ().size ());
- }
-
- void I2PControlService::NetStatusHandler (std::ostringstream& results)
- {
- InsertParam (results, "i2p.router.net.status", (int)i2p::context.GetStatus ());
- }
-
- void I2PControlService::TunnelsParticipatingHandler (std::ostringstream& results)
- {
- int transit = i2p::tunnel::tunnels.GetTransitTunnels ().size ();
- InsertParam (results, "i2p.router.net.tunnels.participating", transit);
- }
-
- void I2PControlService::TunnelsSuccessRateHandler (std::ostringstream& results)
- {
- int rate = i2p::tunnel::tunnels.GetTunnelCreationSuccessRate ();
- InsertParam (results, "i2p.router.net.tunnels.successrate", rate);
- }
-
- void I2PControlService::InboundBandwidth1S (std::ostringstream& results)
- {
- double bw = i2p::transport::transports.GetInBandwidth ();
- InsertParam (results, "i2p.router.net.bw.inbound.1s", bw);
- }
-
- void I2PControlService::OutboundBandwidth1S (std::ostringstream& results)
- {
- double bw = i2p::transport::transports.GetOutBandwidth ();
- InsertParam (results, "i2p.router.net.bw.outbound.1s", bw);
- }
-
- void I2PControlService::NetTotalReceivedBytes (std::ostringstream& results)
- {
- InsertParam (results, "i2p.router.net.total.received.bytes", (double)i2p::transport::transports.GetTotalReceivedBytes ());
- }
-
- void I2PControlService::NetTotalSentBytes (std::ostringstream& results)
- {
- InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ());
- }
-
// RouterManager
@@ -532,37 +382,6 @@
i2p::data::netdb.Reseed ();
}
-// network setting
- void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
- {
- for (auto it = params.begin (); it != params.end (); it++)
- {
- LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first);
- auto it1 = m_NetworkSettingHandlers.find (it->first);
- if (it1 != m_NetworkSettingHandlers.end ()) {
- if (it != params.begin ()) results << ",";
- (this->*(it1->second))(it->second.data (), results);
- } else
- LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first);
- }
- }
-
- void I2PControlService::InboundBandwidthLimit (const std::string& value, std::ostringstream& results)
- {
- if (value != "null")
- i2p::context.SetBandwidth (std::atoi(value.c_str()));
- int bw = i2p::context.GetBandwidthLimit();
- InsertParam (results, "i2p.router.net.bw.in", bw);
- }
-
- void I2PControlService::OutboundBandwidthLimit (const std::string& value, std::ostringstream& results)
- {
- if (value != "null")
- i2p::context.SetBandwidth (std::atoi(value.c_str()));
- int bw = i2p::context.GetBandwidthLimit();
- InsertParam (results, "i2p.router.net.bw.out", bw);
- }
-
// certificate
void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path)
{
@@ -611,178 +430,5 @@
}
EVP_PKEY_free (pkey);
}
-
-// ClientServicesInfo
-
- void I2PControlService::ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
- {
- for (auto it = params.begin (); it != params.end (); it++)
- {
- LogPrint (eLogDebug, "I2PControl: ClientServicesInfo request: ", it->first);
- auto it1 = m_ClientServicesInfoHandlers.find (it->first);
- if (it1 != m_ClientServicesInfoHandlers.end ())
- {
- if (it != params.begin ()) results << ",";
- (this->*(it1->second))(results);
- }
- else
- LogPrint (eLogError, "I2PControl: ClientServicesInfo unknown request ", it->first);
- }
- }
-
- void I2PControlService::I2PTunnelInfoHandler (std::ostringstream& results)
- {
- boost::property_tree::ptree pt;
- boost::property_tree::ptree client_tunnels, server_tunnels;
-
- for (auto& it: i2p::client::context.GetClientTunnels ())
- {
- auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
- boost::property_tree::ptree ct;
- ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
- client_tunnels.add_child(it.second->GetName (), ct);
- }
-
- auto& serverTunnels = i2p::client::context.GetServerTunnels ();
- if (!serverTunnels.empty ()) {
- for (auto& it: serverTunnels)
- {
- auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
- boost::property_tree::ptree st;
- st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
- st.put("port", it.second->GetLocalPort ());
- server_tunnels.add_child(it.second->GetName (), st);
- }
- }
-
- auto& clientForwards = i2p::client::context.GetClientForwards ();
- if (!clientForwards.empty ())
- {
- for (auto& it: clientForwards)
- {
- auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
- boost::property_tree::ptree ct;
- ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
- client_tunnels.add_child(it.second->GetName (), ct);
- }
- }
-
- auto& serverForwards = i2p::client::context.GetServerForwards ();
- if (!serverForwards.empty ())
- {
- for (auto& it: serverForwards)
- {
- auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
- boost::property_tree::ptree st;
- st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
- server_tunnels.add_child(it.second->GetName (), st);
- }
- }
-
- pt.add_child("client", client_tunnels);
- pt.add_child("server", server_tunnels);
-
- InsertParam (results, "I2PTunnel", pt);
- }
-
- void I2PControlService::HTTPProxyInfoHandler (std::ostringstream& results)
- {
- boost::property_tree::ptree pt;
-
- auto httpProxy = i2p::client::context.GetHttpProxy ();
- if (httpProxy)
- {
- auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
- pt.put("enabled", true);
- pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
- }
- else
- pt.put("enabled", false);
-
- InsertParam (results, "HTTPProxy", pt);
- }
-
- void I2PControlService::SOCKSInfoHandler (std::ostringstream& results)
- {
- boost::property_tree::ptree pt;
-
- auto socksProxy = i2p::client::context.GetSocksProxy ();
- if (socksProxy)
- {
- auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
- pt.put("enabled", true);
- pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
- }
- else
- pt.put("enabled", false);
-
- InsertParam (results, "SOCKS", pt);
- }
-
- void I2PControlService::SAMInfoHandler (std::ostringstream& results)
- {
- boost::property_tree::ptree pt;
- auto sam = i2p::client::context.GetSAMBridge ();
- if (sam)
- {
- pt.put("enabled", true);
- boost::property_tree::ptree sam_sessions;
- for (auto& it: sam->GetSessions ())
- {
- boost::property_tree::ptree sam_session, sam_session_sockets;
- auto& name = it.second->GetLocalDestination ()->GetNickname ();
- auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
- sam_session.put("name", name);
- sam_session.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
-
- for (const auto& socket: sam->ListSockets(it.first))
- {
- boost::property_tree::ptree stream;
- stream.put("type", socket->GetSocketType ());
- stream.put("peer", socket->GetSocket ().remote_endpoint());
-
- sam_session_sockets.push_back(std::make_pair("", stream));
- }
- sam_session.add_child("sockets", sam_session_sockets);
- sam_sessions.add_child(it.first, sam_session);
- }
-
- pt.add_child("sessions", sam_sessions);
- }
- else
- pt.put("enabled", false);
-
- InsertParam (results, "SAM", pt);
- }
-
- void I2PControlService::BOBInfoHandler (std::ostringstream& results)
- {
- boost::property_tree::ptree pt;
- auto bob = i2p::client::context.GetBOBCommandChannel ();
- if (bob)
- {
- /* TODO more info */
- pt.put("enabled", true);
- }
- else
- pt.put("enabled", false);
-
- InsertParam (results, "BOB", pt);
- }
-
- void I2PControlService::I2CPInfoHandler (std::ostringstream& results)
- {
- boost::property_tree::ptree pt;
- auto i2cp = i2p::client::context.GetI2CPServer ();
- if (i2cp)
- {
- /* TODO more info */
- pt.put("enabled", true);
- }
- else
- pt.put("enabled", false);
-
- InsertParam (results, "I2CP", pt);
- }
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/daemon/I2PControl.h
^
|
@@ -20,6 +20,7 @@
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/property_tree/ptree.hpp>
+#include "I2PControlHandlers.h"
namespace i2p
{
@@ -32,7 +33,7 @@
const char I2P_CONTROL_CERTIFICATE_COMMON_NAME[] = "i2pd.i2pcontrol";
const char I2P_CONTROL_CERTIFICATE_ORGANIZATION[] = "Purple I2P";
- class I2PControlService
+ class I2PControlService: public I2PControlHandlers
{
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
@@ -63,61 +64,24 @@
private:
- void InsertParam (std::ostringstream& ss, const std::string& name, int value) const;
- void InsertParam (std::ostringstream& ss, const std::string& name, double value) const;
- void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes = true) const;
- void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const;
-
// methods
typedef void (I2PControlService::*MethodHandler)(const boost::property_tree::ptree& params, std::ostringstream& results);
void AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
void EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
void I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
- void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
void RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
- void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
- void ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
// I2PControl
typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value);
void PasswordHandler (const std::string& value);
- // RouterInfo
- typedef void (I2PControlService::*RouterInfoRequestHandler)(std::ostringstream& results);
- void UptimeHandler (std::ostringstream& results);
- void VersionHandler (std::ostringstream& results);
- void StatusHandler (std::ostringstream& results);
- void NetDbKnownPeersHandler (std::ostringstream& results);
- void NetDbActivePeersHandler (std::ostringstream& results);
- void NetStatusHandler (std::ostringstream& results);
- void TunnelsParticipatingHandler (std::ostringstream& results);
- void TunnelsSuccessRateHandler (std::ostringstream& results);
- void InboundBandwidth1S (std::ostringstream& results);
- void OutboundBandwidth1S (std::ostringstream& results);
- void NetTotalReceivedBytes (std::ostringstream& results);
- void NetTotalSentBytes (std::ostringstream& results);
-
// RouterManager
typedef void (I2PControlService::*RouterManagerRequestHandler)(std::ostringstream& results);
void ShutdownHandler (std::ostringstream& results);
void ShutdownGracefulHandler (std::ostringstream& results);
void ReseedHandler (std::ostringstream& results);
- // NetworkSetting
- typedef void (I2PControlService::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results);
- void InboundBandwidthLimit (const std::string& value, std::ostringstream& results);
- void OutboundBandwidthLimit (const std::string& value, std::ostringstream& results);
-
- // ClientServicesInfo
- typedef void (I2PControlService::*ClientServicesInfoRequestHandler)(std::ostringstream& results);
- void I2PTunnelInfoHandler (std::ostringstream& results);
- void HTTPProxyInfoHandler (std::ostringstream& results);
- void SOCKSInfoHandler (std::ostringstream& results);
- void SAMInfoHandler (std::ostringstream& results);
- void BOBInfoHandler (std::ostringstream& results);
- void I2CPInfoHandler (std::ostringstream& results);
-
private:
std::string m_Password;
@@ -132,10 +96,7 @@
std::map<std::string, MethodHandler> m_MethodHandlers;
std::map<std::string, I2PControlRequestHandler> m_I2PControlHandlers;
- std::map<std::string, RouterInfoRequestHandler> m_RouterInfoHandlers;
std::map<std::string, RouterManagerRequestHandler> m_RouterManagerHandlers;
- std::map<std::string, NetworkSettingRequestHandler> m_NetworkSettingHandlers;
- std::map<std::string, ClientServicesInfoRequestHandler> m_ClientServicesInfoHandlers;
};
}
}
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/daemon/I2PControlHandlers.cpp
^
|
@@ -0,0 +1,390 @@
+/*
+* Copyright (c) 2013-2022, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*/
+
+#include <iomanip>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/lexical_cast.hpp>
+#include <boost/property_tree/json_parser.hpp>
+
+#include "Log.h"
+#include "RouterContext.h"
+#include "NetDb.hpp"
+#include "Tunnel.h"
+#include "Transports.h"
+#include "version.h"
+#include "ClientContext.h"
+#include "I2PControlHandlers.h"
+
+namespace i2p
+{
+namespace client
+{
+ I2PControlHandlers::I2PControlHandlers ()
+ {
+ // RouterInfo
+ m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlHandlers::UptimeHandler;
+ m_RouterInfoHandlers["i2p.router.version"] = &I2PControlHandlers::VersionHandler;
+ m_RouterInfoHandlers["i2p.router.status"] = &I2PControlHandlers::StatusHandler;
+ m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlHandlers::NetDbKnownPeersHandler;
+ m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlHandlers::NetDbActivePeersHandler;
+ m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlHandlers::InboundBandwidth1S;
+ m_RouterInfoHandlers["i2p.router.net.bw.inbound.15s"] = &I2PControlHandlers::InboundBandwidth15S;
+ m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlHandlers::OutboundBandwidth1S;
+ m_RouterInfoHandlers["i2p.router.net.bw.outbound.15s"] = &I2PControlHandlers::OutboundBandwidth15S;
+ m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlHandlers::NetStatusHandler;
+ m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlHandlers::TunnelsParticipatingHandler;
+ m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = &I2PControlHandlers::TunnelsSuccessRateHandler;
+ m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlHandlers::NetTotalReceivedBytes;
+ m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlHandlers::NetTotalSentBytes;
+
+ // NetworkSetting
+ m_NetworkSettingHandlers["i2p.router.net.bw.in"] = &I2PControlHandlers::InboundBandwidthLimit;
+ m_NetworkSettingHandlers["i2p.router.net.bw.out"] = &I2PControlHandlers::OutboundBandwidthLimit;
+
+ // ClientServicesInfo
+ m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlHandlers::I2PTunnelInfoHandler;
+ m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlHandlers::HTTPProxyInfoHandler;
+ m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlHandlers::SOCKSInfoHandler;
+ m_ClientServicesInfoHandlers["SAM"] = &I2PControlHandlers::SAMInfoHandler;
+ m_ClientServicesInfoHandlers["BOB"] = &I2PControlHandlers::BOBInfoHandler;
+ m_ClientServicesInfoHandlers["I2CP"] = &I2PControlHandlers::I2CPInfoHandler;
+ }
+
+ void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, int value) const
+ {
+ ss << "\"" << name << "\":" << value;
+ }
+
+ void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes) const
+ {
+ ss << "\"" << name << "\":";
+ if (value.length () > 0)
+ {
+ if (quotes)
+ ss << "\"" << value << "\"";
+ else
+ ss << value;
+ }
+ else
+ ss << "null";
+ }
+
+ void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, double value) const
+ {
+ ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value;
+ }
+
+ void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const
+ {
+ std::ostringstream buf;
+ boost::property_tree::write_json (buf, value, false);
+ ss << "\"" << name << "\":" << buf.str();
+ }
+
+// RouterInfo
+
+ void I2PControlHandlers::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
+ {
+ bool first = true;
+ for (auto it = params.begin (); it != params.end (); it++)
+ {
+ LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first);
+ auto it1 = m_RouterInfoHandlers.find (it->first);
+ if (it1 != m_RouterInfoHandlers.end ())
+ {
+ if (!first) results << ",";
+ else first = false;
+ (this->*(it1->second))(results);
+ }
+ else
+ LogPrint (eLogError, "I2PControl: RouterInfo unknown request ", it->first);
+ }
+ }
+
+ void I2PControlHandlers::UptimeHandler (std::ostringstream& results)
+ {
+ InsertParam (results, "i2p.router.uptime", std::to_string (i2p::context.GetUptime ()*1000LL), false);
+ }
+
+ void I2PControlHandlers::VersionHandler (std::ostringstream& results)
+ {
+ InsertParam (results, "i2p.router.version", VERSION);
+ }
+
+ void I2PControlHandlers::StatusHandler (std::ostringstream& results)
+ {
+ auto dest = i2p::client::context.GetSharedLocalDestination ();
+ InsertParam (results, "i2p.router.status", (dest && dest->IsReady ()) ? "1" : "0");
+ }
+
+ void I2PControlHandlers::NetDbKnownPeersHandler (std::ostringstream& results)
+ {
+ InsertParam (results, "i2p.router.netdb.knownpeers", i2p::data::netdb.GetNumRouters ());
+ }
+
+ void I2PControlHandlers::NetDbActivePeersHandler (std::ostringstream& results)
+ {
+ InsertParam (results, "i2p.router.netdb.activepeers", (int)i2p::transport::transports.GetPeers ().size ());
+ }
+
+ void I2PControlHandlers::NetStatusHandler (std::ostringstream& results)
+ {
+ InsertParam (results, "i2p.router.net.status", (int)i2p::context.GetStatus ());
+ }
+
+ void I2PControlHandlers::TunnelsParticipatingHandler (std::ostringstream& results)
+ {
+ int transit = i2p::tunnel::tunnels.GetTransitTunnels ().size ();
+ InsertParam (results, "i2p.router.net.tunnels.participating", transit);
+ }
+
+ void I2PControlHandlers::TunnelsSuccessRateHandler (std::ostringstream& results)
+ {
+ int rate = i2p::tunnel::tunnels.GetTunnelCreationSuccessRate ();
+ InsertParam (results, "i2p.router.net.tunnels.successrate", rate);
+ }
+
+ void I2PControlHandlers::InboundBandwidth1S (std::ostringstream& results)
+ {
+ double bw = i2p::transport::transports.GetInBandwidth ();
+ InsertParam (results, "i2p.router.net.bw.inbound.1s", bw);
+ }
+
+ void I2PControlHandlers::InboundBandwidth15S (std::ostringstream& results)
+ {
+ double bw = i2p::transport::transports.GetInBandwidth15s ();
+ InsertParam (results, "i2p.router.net.bw.inbound.15s", bw);
+ }
+
+ void I2PControlHandlers::OutboundBandwidth1S (std::ostringstream& results)
+ {
+ double bw = i2p::transport::transports.GetOutBandwidth ();
+ InsertParam (results, "i2p.router.net.bw.outbound.1s", bw);
+ }
+
+ void I2PControlHandlers::OutboundBandwidth15S (std::ostringstream& results)
+ {
+ double bw = i2p::transport::transports.GetOutBandwidth15s ();
+ InsertParam (results, "i2p.router.net.bw.outbound.15s", bw);
+ }
+
+ void I2PControlHandlers::NetTotalReceivedBytes (std::ostringstream& results)
+ {
+ InsertParam (results, "i2p.router.net.total.received.bytes", (double)i2p::transport::transports.GetTotalReceivedBytes ());
+ }
+
+ void I2PControlHandlers::NetTotalSentBytes (std::ostringstream& results)
+ {
+ InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ());
+ }
+
+// network setting
+ void I2PControlHandlers::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
+ {
+ for (auto it = params.begin (); it != params.end (); it++)
+ {
+ LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first);
+ auto it1 = m_NetworkSettingHandlers.find (it->first);
+ if (it1 != m_NetworkSettingHandlers.end ()) {
+ if (it != params.begin ()) results << ",";
+ (this->*(it1->second))(it->second.data (), results);
+ } else
+ LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first);
+ }
+ }
+
+ void I2PControlHandlers::InboundBandwidthLimit (const std::string& value, std::ostringstream& results)
+ {
+ if (value != "null")
+ i2p::context.SetBandwidth (std::atoi(value.c_str()));
+ int bw = i2p::context.GetBandwidthLimit();
+ InsertParam (results, "i2p.router.net.bw.in", bw);
+ }
+
+ void I2PControlHandlers::OutboundBandwidthLimit (const std::string& value, std::ostringstream& results)
+ {
+ if (value != "null")
+ i2p::context.SetBandwidth (std::atoi(value.c_str()));
+ int bw = i2p::context.GetBandwidthLimit();
+ InsertParam (results, "i2p.router.net.bw.out", bw);
+ }
+
+// ClientServicesInfo
+
+ void I2PControlHandlers::ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
+ {
+ for (auto it = params.begin (); it != params.end (); it++)
+ {
+ LogPrint (eLogDebug, "I2PControl: ClientServicesInfo request: ", it->first);
+ auto it1 = m_ClientServicesInfoHandlers.find (it->first);
+ if (it1 != m_ClientServicesInfoHandlers.end ())
+ {
+ if (it != params.begin ()) results << ",";
+ (this->*(it1->second))(results);
+ }
+ else
+ LogPrint (eLogError, "I2PControl: ClientServicesInfo unknown request ", it->first);
+ }
+ }
+
+ void I2PControlHandlers::I2PTunnelInfoHandler (std::ostringstream& results)
+ {
+ boost::property_tree::ptree pt;
+ boost::property_tree::ptree client_tunnels, server_tunnels;
+
+ for (auto& it: i2p::client::context.GetClientTunnels ())
+ {
+ auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
+ boost::property_tree::ptree ct;
+ ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
+ client_tunnels.add_child(it.second->GetName (), ct);
+ }
+
+ auto& serverTunnels = i2p::client::context.GetServerTunnels ();
+ if (!serverTunnels.empty ()) {
+ for (auto& it: serverTunnels)
+ {
+ auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
+ boost::property_tree::ptree st;
+ st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
+ st.put("port", it.second->GetLocalPort ());
+ server_tunnels.add_child(it.second->GetName (), st);
+ }
+ }
+
+ auto& clientForwards = i2p::client::context.GetClientForwards ();
+ if (!clientForwards.empty ())
+ {
+ for (auto& it: clientForwards)
+ {
+ auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
+ boost::property_tree::ptree ct;
+ ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
+ client_tunnels.add_child(it.second->GetName (), ct);
+ }
+ }
+
+ auto& serverForwards = i2p::client::context.GetServerForwards ();
+ if (!serverForwards.empty ())
+ {
+ for (auto& it: serverForwards)
+ {
+ auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
+ boost::property_tree::ptree st;
+ st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
+ server_tunnels.add_child(it.second->GetName (), st);
+ }
+ }
+
+ pt.add_child("client", client_tunnels);
+ pt.add_child("server", server_tunnels);
+
+ InsertParam (results, "I2PTunnel", pt);
+ }
+
+ void I2PControlHandlers::HTTPProxyInfoHandler (std::ostringstream& results)
+ {
+ boost::property_tree::ptree pt;
+
+ auto httpProxy = i2p::client::context.GetHttpProxy ();
+ if (httpProxy)
+ {
+ auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
+ pt.put("enabled", true);
+ pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
+ }
+ else
+ pt.put("enabled", false);
+
+ InsertParam (results, "HTTPProxy", pt);
+ }
+
+ void I2PControlHandlers::SOCKSInfoHandler (std::ostringstream& results)
+ {
+ boost::property_tree::ptree pt;
+
+ auto socksProxy = i2p::client::context.GetSocksProxy ();
+ if (socksProxy)
+ {
+ auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
+ pt.put("enabled", true);
+ pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
+ }
+ else
+ pt.put("enabled", false);
+
+ InsertParam (results, "SOCKS", pt);
+ }
+
+ void I2PControlHandlers::SAMInfoHandler (std::ostringstream& results)
+ {
+ boost::property_tree::ptree pt;
+ auto sam = i2p::client::context.GetSAMBridge ();
+ if (sam)
+ {
+ pt.put("enabled", true);
+ boost::property_tree::ptree sam_sessions;
+ for (auto& it: sam->GetSessions ())
+ {
+ boost::property_tree::ptree sam_session, sam_session_sockets;
+ auto& name = it.second->GetLocalDestination ()->GetNickname ();
+ auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
+ sam_session.put("name", name);
+ sam_session.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
+
+ for (const auto& socket: sam->ListSockets(it.first))
+ {
+ boost::property_tree::ptree stream;
+ stream.put("type", socket->GetSocketType ());
+ stream.put("peer", socket->GetSocket ().remote_endpoint());
+
+ sam_session_sockets.push_back(std::make_pair("", stream));
+ }
+ sam_session.add_child("sockets", sam_session_sockets);
+ sam_sessions.add_child(it.first, sam_session);
+ }
+
+ pt.add_child("sessions", sam_sessions);
+ }
+ else
+ pt.put("enabled", false);
+
+ InsertParam (results, "SAM", pt);
+ }
+
+ void I2PControlHandlers::BOBInfoHandler (std::ostringstream& results)
+ {
+ boost::property_tree::ptree pt;
+ auto bob = i2p::client::context.GetBOBCommandChannel ();
+ if (bob)
+ {
+ /* TODO more info */
+ pt.put("enabled", true);
+ }
+ else
+ pt.put("enabled", false);
+
+ InsertParam (results, "BOB", pt);
+ }
+
+ void I2PControlHandlers::I2CPInfoHandler (std::ostringstream& results)
+ {
+ boost::property_tree::ptree pt;
+ auto i2cp = i2p::client::context.GetI2CPServer ();
+ if (i2cp)
+ {
+ /* TODO more info */
+ pt.put("enabled", true);
+ }
+ else
+ pt.put("enabled", false);
+
+ InsertParam (results, "I2CP", pt);
+ }
+}
+}
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/daemon/I2PControlHandlers.h
^
|
@@ -0,0 +1,82 @@
+/*
+* Copyright (c) 2013-2022, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*/
+
+#ifndef I2P_CONTROL_HANDLERS_H__
+#define I2P_CONTROL_HANDLERS_H__
+
+#include <sstream>
+#include <map>
+#include <string>
+#include <boost/property_tree/ptree.hpp>
+
+namespace i2p
+{
+namespace client
+{
+ class I2PControlHandlers
+ {
+ public:
+
+ I2PControlHandlers ();
+
+ // methods
+ // TODO: make protected
+ void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
+ void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
+ void ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
+
+ protected:
+
+ void InsertParam (std::ostringstream& ss, const std::string& name, int value) const;
+ void InsertParam (std::ostringstream& ss, const std::string& name, double value) const;
+ void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes = true) const;
+ void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const;
+
+ private:
+
+ // RouterInfo
+ typedef void (I2PControlHandlers::*RouterInfoRequestHandler)(std::ostringstream& results);
+ void UptimeHandler (std::ostringstream& results);
+ void VersionHandler (std::ostringstream& results);
+ void StatusHandler (std::ostringstream& results);
+ void NetDbKnownPeersHandler (std::ostringstream& results);
+ void NetDbActivePeersHandler (std::ostringstream& results);
+ void NetStatusHandler (std::ostringstream& results);
+ void TunnelsParticipatingHandler (std::ostringstream& results);
+ void TunnelsSuccessRateHandler (std::ostringstream& results);
+ void InboundBandwidth1S (std::ostringstream& results);
+ void InboundBandwidth15S (std::ostringstream& results);
+ void OutboundBandwidth1S (std::ostringstream& results);
+ void OutboundBandwidth15S (std::ostringstream& results);
+ void NetTotalReceivedBytes (std::ostringstream& results);
+ void NetTotalSentBytes (std::ostringstream& results);
+
+ // NetworkSetting
+ typedef void (I2PControlHandlers::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results);
+ void InboundBandwidthLimit (const std::string& value, std::ostringstream& results);
+ void OutboundBandwidthLimit (const std::string& value, std::ostringstream& results);
+
+ // ClientServicesInfo
+ typedef void (I2PControlHandlers::*ClientServicesInfoRequestHandler)(std::ostringstream& results);
+ void I2PTunnelInfoHandler (std::ostringstream& results);
+ void HTTPProxyInfoHandler (std::ostringstream& results);
+ void SOCKSInfoHandler (std::ostringstream& results);
+ void SAMInfoHandler (std::ostringstream& results);
+ void BOBInfoHandler (std::ostringstream& results);
+ void I2CPInfoHandler (std::ostringstream& results);
+
+ private:
+
+ std::map<std::string, RouterInfoRequestHandler> m_RouterInfoHandlers;
+ std::map<std::string, NetworkSettingRequestHandler> m_NetworkSettingHandlers;
+ std::map<std::string, ClientServicesInfoRequestHandler> m_ClientServicesInfoHandlers;
+ };
+}
+}
+
+#endif
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/daemon/UPnP.cpp
^
|
@@ -159,10 +159,11 @@
void UPnP::PortMapping ()
{
- const auto& a = context.GetRouterInfo().GetAddresses();
- for (const auto& address : a)
+ auto a = context.GetRouterInfo().GetAddresses();
+ if (!a) return;
+ for (const auto& address : *a)
{
- if (!address->host.is_v6 () && address->port)
+ if (address && !address->host.is_v6 () && address->port)
TryPortMapping (address);
}
m_Timer.expires_from_now (boost::posix_time::minutes(20)); // every 20 minutes
@@ -210,10 +211,11 @@
void UPnP::CloseMapping ()
{
- const auto& a = context.GetRouterInfo().GetAddresses();
- for (const auto& address : a)
+ auto a = context.GetRouterInfo().GetAddresses();
+ if (!a) return;
+ for (const auto& address : *a)
{
- if (!address->host.is_v6 () && address->port)
+ if (address && !address->host.is_v6 () && address->port)
CloseMapping (address);
}
}
@@ -248,10 +250,10 @@
{
switch (address->transportStyle)
{
- case i2p::data::RouterInfo::eTransportNTCP:
+ case i2p::data::RouterInfo::eTransportNTCP2:
return "TCP";
break;
- case i2p::data::RouterInfo::eTransportSSU:
+ case i2p::data::RouterInfo::eTransportSSU2:
default:
return "UDP";
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/daemon/UnixDaemon.cpp
^
|
@@ -173,7 +173,7 @@
ftruncate(pidFH, 0);
if (write(pidFH, pid, strlen(pid)) < 0)
{
- LogPrint(eLogError, "Daemon: Could not write pidfile ", pidfile, ": ", strerror(errno));
+ LogPrint(eLogCritical, "Daemon: Could not write pidfile ", pidfile, ": ", strerror(errno));
std::cerr << "i2pd: Could not write pidfile " << pidfile << ": " << strerror(errno) << std::endl;
return false;
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/debian/changelog
^
|
@@ -1,3 +1,80 @@
+i2pd (2.50.2) unstable; urgency=medium
+
+ * updated to version 2.50.2/0.9.61
+
+-- orignal <orignal@i2pmail.org> Sat, 06 Jan 2024 16:00:00 +0000
+
+i2pd (2.50.1-1) unstable; urgency=medium
+
+ * updated to version 2.50.1/0.9.61
+
+ -- r4sas <r4sas@i2pmail.org> Sat, 23 Dec 2023 18:30:00 +0000
+
+i2pd (2.50.0-1) unstable; urgency=medium
+
+ * updated to version 2.50.0/0.9.61
+
+ -- orignal <orignal@i2pmail.org> Mon, 18 Dec 2023 16:00:00 +0000
+
+i2pd (2.49.0-1) unstable; urgency=medium
+
+ * updated to version 2.49.0/0.9.60
+
+ -- orignal <orignal@i2pmail.org> Mon, 18 Sep 2023 16:00:00 +0000
+
+i2pd (2.48.0-1) unstable; urgency=high
+
+ * updated to version 2.48.0/0.9.59
+
+ -- orignal <orignal@i2pmail.org> Mon, 12 Jun 2023 16:00:00 +0000
+
+i2pd (2.47.0-1) unstable; urgency=high
+
+ * updated to version 2.47.0/0.9.58
+
+ -- orignal <orignal@i2pmail.org> Sat, 11 Mar 2023 16:00:00 +0000
+
+i2pd (2.46.1-2) unstable; urgency=critical
+
+ * re-pushed release due to new critical bug
+
+ -- r4sas <r4sas@i2pmail.org> Mon, 20 Feb 2023 23:40:00 +0000
+
+i2pd (2.46.1-1) unstable; urgency=high
+
+ * updated to version 2.46.1/0.9.57
+
+ -- r4sas <r4sas@i2pmail.org> Mon, 20 Feb 2023 02:45:00 +0000
+
+i2pd (2.46.0-1) unstable; urgency=high
+
+ * updated to version 2.46.0/0.9.57
+
+ -- orignal <orignal@i2pmail.org> Wed, 15 Feb 2023 19:00:00 +0000
+
+i2pd (2.45.1-1) unstable; urgency=medium
+
+ * updated to version 2.45.1/0.9.57
+
+ -- orignal <orignal@i2pmail.org> Wed, 11 Jan 2023 19:00:00 +0000
+
+i2pd (2.45.0-1) unstable; urgency=high
+
+ * updated to version 2.45.0/0.9.57
+ * compat level 12
+ * standards version 4.3.0
+ * increased nofile limit in service and init.d to 8192
+ * added conffiles
+ * removed #1210 patch
+
+ -- r4sas <r4sas@i2pmail.org> Tue, 3 Jan 2023 18:00:00 +0000
+
+i2pd (2.44.0-1) unstable; urgency=medium
+
+ * updated to version 2.44.0/0.9.56
+
+ -- orignal <orignal@i2pmail.org> Sun, 20 Nov 2022 19:00:00 +0000
+
i2pd (2.43.0-1) unstable; urgency=medium
* updated to version 2.43.0/0.9.55
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/debian/compat
^
|
@@ -1 +1 @@
-9
+12
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/debian/control
^
|
@@ -2,8 +2,8 @@
Section: net
Priority: optional
Maintainer: r4sas <r4sas@i2pmail.org>
-Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.17.2~), gcc (>= 4.7) | clang (>= 3.3), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev
-Standards-Version: 3.9.8
+Build-Depends: debhelper (>= 12~), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev
+Standards-Version: 4.3.0
Homepage: http://i2pd.website/
Vcs-Git: git://github.com/PurpleI2P/i2pd.git
Vcs-Browser: https://github.com/PurpleI2P/i2pd
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/debian/copyright
^
|
@@ -3,18 +3,18 @@
Source: https://github.com/PurpleI2P
Files: *
-Copyright: 2013-2020 PurpleI2P
+Copyright: 2013-2023 PurpleI2P
License: BSD-3-clause
Files: debian/*
Copyright: 2013-2015 Kill Your TV <killyourtv@i2pmail.org>
2014-2016 hagen <hagen@i2pmail.org>
- 2016-2020 R4SAS <r4sas@i2pmail.org>
+ 2016-2023 R4SAS <r4sas@i2pmail.org>
2017-2020 Yangfl <mmyangfl@gmail.com>
License: GPL-2+
License: BSD-3-clause
- Copyright (c) 2013-2017, The PurpleI2P Project
+ Copyright (c) 2013-2023, The PurpleI2P Project
.
All rights reserved.
.
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/debian/i2pd.1
^
|
@@ -64,7 +64,7 @@
The network interface to bind to for IPv6 connections
.TP
\fB\-\-ipv4=\fR
-Enable communication through ipv6 (\fIenabled\fR by default)
+Enable communication through ipv4 (\fIenabled\fR by default)
.TP
\fB\-\-ipv6\fR
Enable communication through ipv6 (\fIdisabled\fR by default)
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/debian/i2pd.default
^
|
@@ -8,4 +8,4 @@
DAEMON_OPTS=""
# If you have problems with hunging i2pd, you can try enable this
-ulimit -n 4096
+ulimit -n 8192
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/debian/i2pd.install
^
|
@@ -1,7 +1,6 @@
i2pd usr/sbin/
contrib/i2pd.conf etc/i2pd/
contrib/tunnels.conf etc/i2pd/
-contrib/subscriptions.txt etc/i2pd/
contrib/certificates/ usr/share/i2pd/
contrib/tunnels.d/README etc/i2pd/tunnels.conf.d/
contrib/apparmor/usr.sbin.i2pd etc/apparmor.d
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/debian/i2pd.links
^
|
@@ -1,5 +1,4 @@
-etc/i2pd/i2pd.conf var/lib/i2pd/i2pd.conf
+etc/i2pd/i2pd.conf var/lib/i2pd/i2pd.conf
etc/i2pd/tunnels.conf var/lib/i2pd/tunnels.conf
-etc/i2pd/subscriptions.txt var/lib/i2pd/subscriptions.txt
etc/i2pd/tunnels.conf.d var/lib/i2pd/tunnels.d
usr/share/i2pd/certificates var/lib/i2pd/certificates
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/debian/patches/01-upnp.patch
^
|
@@ -0,0 +1,17 @@
+Description: Enable UPnP usage in package
+Author: r4sas <r4sas@i2pmail.org>
+
+Reviewed-By: r4sas <r4sas@i2pmail.org>
+Last-Update: 2022-03-23
+
+--- i2pd.orig/Makefile
++++ i2pd/Makefile
+@@ -31,7 +31,7 @@ include filelist.mk
+
+ USE_AESNI := $(or $(USE_AESNI),yes)
+ USE_STATIC := $(or $(USE_STATIC),no)
+-USE_UPNP := $(or $(USE_UPNP),no)
++USE_UPNP := $(or $(USE_UPNP),yes)
+ DEBUG := $(or $(DEBUG),yes)
+
+ # for debugging purposes only, when commit hash needed in trunk builds in i2pd version string
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/debian/patches/series
^
|
@@ -1,2 +1 @@
-01-fix-1210.patch
-02-upnp.patch
+01-upnp.patch
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/debian/rules
^
|
@@ -8,6 +8,6 @@
export DEB_LDFLAGS_MAINT_APPEND =
%:
- dh $@ --parallel
+ dh $@
override_dh_auto_install:
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/debian/watch
^
|
@@ -1,3 +1,4 @@
-version=4 opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%i2pd-$1.tar.gz%" \
+version=4
+opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%i2pd-$1.tar.gz%" \
https://github.com/PurpleI2P/i2pd/tags \
(?:.*?/)?(\d[\d.]*)\.tar\.gz debian uupdate
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Afrikaans.cpp
^
|
@@ -64,10 +64,10 @@
static std::map<std::string, std::vector<std::string>> plurals
{
- {"days", {"dag", "dae"}},
- {"hours", {"uur", "ure"}},
- {"minutes", {"minuut", "minute"}},
- {"seconds", {"seconde", "sekondes"}},
+ {"%d days", {"%d dag", "%d dae"}},
+ {"%d hours", {"%d uur", "%d ure"}},
+ {"%d minutes", {"%d minuut", "%d minute"}},
+ {"%d seconds", {"%d seconde", "%d sekondes"}},
{"", {"", ""}},
};
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Armenian.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2021, The PurpleI2P Project
+* Copyright (c) 2021-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -31,15 +31,16 @@
static std::map<std::string, std::string> strings
{
- {"KiB", "ԿիԲ"},
- {"MiB", "ՄիԲ"},
- {"GiB", "ԳիԲ"},
+ {"%.2f KiB", "%.2f ԿիԲ"},
+ {"%.2f MiB", "%.2f ՄիԲ"},
+ {"%.2f GiB", "%.2f ԳիԲ"},
{"building", "կառուցվում է"},
{"failed", "Անհաջող"},
{"expiring", "Լրանում է"},
{"established", "կարգավոյված է"},
{"unknown", "անհայտ"},
{"exploratory", "հետազոտոկան"},
+ {"Purple I2P Webconsole", "Վեբ-կոնսոլ Purple I2P"},
{"<b>i2pd</b> webconsole", "Վեբ-կոնսոլ <b>i2pd</b>"},
{"Main page", "Գլխավոր էջ"},
{"Router commands", "Երթուղիչի հրահանգներ"},
@@ -57,10 +58,10 @@
{"Unknown", "Անհայտ"},
{"Proxy", "Պրոկսի"},
{"Mesh", "MESH-ցանց"},
- {"Error", "Սխալ"},
{"Clock skew", "Ոչ ճշգրիտ ժամանակ"},
{"Offline", "Օֆլայն"},
{"Symmetric NAT", "Սիմետրիկ NAT"},
+ {"Full cone NAT", "Full cone NAT"},
{"Uptime", "Առկայություն"},
{"Network status", "Ցանցի կարգավիճակ"},
{"Network status v6", "Ցանցի կարգավիճակ v6"},
@@ -68,7 +69,7 @@
{"Family", "Խմբատեսակ"},
{"Tunnel creation success rate", "Հաջողությամբ կառուցված թունելներ"},
{"Received", "Ստացվել է"},
- {"KiB/s", "ԿիԲ/վ"},
+ {"%.2f KiB/s", "%.2f ԿիԲ/վ"},
{"Sent", "Ուղարկվել է"},
{"Transit", "Տարանցում"},
{"Data path", "Տվյալների ուղին"},
@@ -89,12 +90,12 @@
{"Address registration line", "Հասցեի գրանցման տող"},
{"Domain", "Տիրույթ"},
{"Generate", "Գեներացնել"},
- {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b> Նշում. </b> արդյունքի տողը կարող է օգտագործվել միայն 2LD տիրույթներ գրանցելու համար (example.i2p): Ենթատիրույթներ գրանցելու համար խնդրում ենք օգտագործել i2pd-tools գործիքակազմը"},
+ {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b> Նշում. </b> արդյունքի տողը կարող է օգտագործվել միայն 2LD տիրույթներ գրանցելու համար (example.i2p): Ենթատիրույթներ գրանցելու համար խնդրում ենք օգտագործել i2pd-tools գործիքակազմը:"},
{"Address", "Հասցե"},
{"Type", "Տեսակը"},
{"EncType", "Գաղտնագրի տեսակը"},
{"Inbound tunnels", "Մուտքային թունելներ"},
- {"ms", "մլվ"},
+ {"%dms", "%dմլվ"},
{"Outbound tunnels", "Ելքային թունելներ"},
{"Tags", "Թեգեր"},
{"Incoming", "Մուտքային"},
@@ -112,11 +113,10 @@
{"Invalid", "Անվավեր"},
{"Store type", "Պահեստավորման տեսակը"},
{"Expires", "Սպառվում է"},
- {"Non Expired Leases", "Չսպառված Lease-եր"},
+ {"Non Expired Leases", "Չսպառված Lease-եր"},
{"Gateway", "Դարպաս"},
{"TunnelID", "Թունելի ID"},
{"EndDate", "Ավարտ"},
- {"not floodfill", "ոչ floodfill-ներ"},
{"Queue size", "Հերթի չափսը"},
{"Run peer test", "Գործարկել փորձարկումը"},
{"Decline transit tunnels", "Մերժել տարանցիկ թունելներ"},
@@ -146,10 +146,7 @@
{"Destination not found", "Հասցեի վայրը չի գտնվել"},
{"StreamID can't be null", "StreamID-ն չի կարող լինել դատարկ"},
{"Return to destination page", "Վերադառնալ նախորդ էջի հասցե"},
- {"You will be redirected in 5 seconds", "Դուք կտեղափոխվեք 5 վայրկյանից"},
- {"Transit tunnels count must not exceed 65535", "Տարանցիկ թունելների քանակը չպետք է գերազանցի 65535-ը"},
{"Back to commands list", "Վերադառնալ հրահանգների ցուցակ"},
- {"Register at reg.i2p", "Գրանցել reg.i2p-ում"},
{"Description", "Նկարագրություն"},
{"A bit information about service on domain", "Մի փոքր տեղեկատվություն տիրոիյթում գտնվող ծառայության մասին"},
{"Submit", "Ուղարկվել"},
@@ -165,43 +162,35 @@
{"You may try to find this host on jump services below", "Ստորև Դուք կարող եք գտնել այս հոսթը jump ծառայությունների միջոցով"},
{"Invalid request", "Սխալ հարցում"},
{"Proxy unable to parse your request", "Պրոկսին չի կարող հասկանալ Ձեր հարցումը"},
- {"addresshelper is not supported", "addresshelper-ը համատեղելի չէ"},
- {"Host", "Հոսթ"},
- {"added to router's addressbook from helper", "Ավելացված է երթուղիչի հասցեագրքում helper-ի միջոցով"},
- {"Click here to proceed:", "Շարունակելու համար սեղմեք այստեղ"},
- {"Continue", "Շարունակել"},
- {"Addresshelper found", "addresshelper-ը գնտված է"},
- {"already in router's addressbook", "արդեն առկա է երթուղիչի հասցեագրքում"},
- {"Click here to update record:", "Սեղմեկ այստեղ որպեսզի թարվացնեք գրառումը"},
- {"invalid request uri", "Սխալ ձևավորված URI հարցում"},
+ {"Invalid request URI", "Սխալ ձևավորված URI հարցում"},
{"Can't detect destination host from request", "Չհաջողվեց հայնտաբերեկ վայրի հասցեն նշված հարցմամբ"},
{"Outproxy failure", "Սխալ արտաքին պրոքսի"},
- {"bad outproxy settings", "Սխալ արտաքին պրոկսի կարգավորումներ"},
- {"not inside I2P network, but outproxy is not enabled", "Հարցումը I2P ցանցից դուրս է, բայց արտաքին պրոքսին միացված չէ"},
- {"unknown outproxy url", "արտաքին պրոքսիի անհայտ URL"},
- {"cannot resolve upstream proxy", "Չհաջողվեց որոշել վերադաս պրոկսին"},
- {"hostname too long", "Հոսթի անունը չափազանց երկար է"},
- {"cannot connect to upstream socks proxy", "չհաջողվեց միանալ վերադաս socks պրոկսիին"},
- {"Cannot negotiate with socks proxy", "Չհաջողվեց պայմանավորվել վերադաս socks պրոկսիի հետ"},
+ {"Bad outproxy settings", "Սխալ արտաքին պրոկսի կարգավորումներ"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "Հոսթ %s Հարցումը I2P ցանցից դուրս է, բայց արտաքին պրոքսին միացված չէ"},
+ {"Unknown outproxy URL", "Արտաքին պրոքսիի անհայտ URL"},
+ {"Cannot resolve upstream proxy", "Չհաջողվեց որոշել վերադաս պրոկսին"},
+ {"Hostname is too long", "Հոսթի անունը չափազանց երկար է"},
+ {"Cannot connect to upstream SOCKS proxy", "Չհաջողվեց միանալ վերադաս SOCKS պրոկսի սերվերին"},
+ {"Cannot negotiate with SOCKS proxy", "Չհաջողվեց պայմանավորվել վերադաս SOCKS պրոկսիի հետ"},
{"CONNECT error", "Սխալ CONNECT հարցում"},
- {"Failed to Connect", "Միանալ չhաջողվեց"},
- {"socks proxy error", "Սխալ SOCKS պրոկսի"},
- {"failed to send request to upstream", "Չհաջողվեց հարցումն ուղարկել վերադաս պրոկսիին"},
- {"No Reply From socks proxy", "Բացակայում է պատասխանը SOCKS պրոկսի սերվերի կողմից"},
- {"cannot connect", "Հնարավոր չե միանալ"},
- {"http out proxy not implemented", "Արտաքին http պրոկսին դեռ իրականացված չէ"},
- {"cannot connect to upstream http proxy", "Չհաջողվեց միանալ վերադաս http պրոկսի սերվերին"},
+ {"Failed to connect", "Միանալ չhաջողվեց"},
+ {"SOCKS proxy error", "Սխալ SOCKS պրոկսի"},
+ {"Failed to send request to upstream", "Չհաջողվեց հարցումն ուղարկել վերադաս պրոկսիին"},
+ {"No reply from SOCKS proxy", "Բացակայում է պատասխանը SOCKS պրոկսի սերվերի կողմից"},
+ {"Cannot connect", "Հնարավոր չե միանալ"},
+ {"HTTP out proxy not implemented", "Արտաքին HTTP պրոկսին դեռ իրականացված չէ"},
+ {"Cannot connect to upstream HTTP proxy", "Չհաջողվեց միանալ վերադաս HTTP պրոկսի սերվերին"},
{"Host is down", "Հոսթն անհասանելի է"},
- {"Can't create connection to requested host, it may be down. Please try again later.", "Հոսթի հետ կապը հաստատել չհաջողվեց, հնարավոր է այն անջատված է, փորձեք միանալ քիչ ուշ"},
+ {"Can't create connection to requested host, it may be down. Please try again later.", "Հոսթի հետ կապը հաստատել չհաջողվեց, հնարավոր է այն անջատված է, փորձեք միանալ քիչ ուշ:"},
{"", ""},
};
static std::map<std::string, std::vector<std::string>> plurals
{
- {"days", {"օր", "օր"}},
- {"hours", {"ժամ", "ժամ"}},
- {"minutes", {"րոպե", "րոպե"}},
- {"seconds", {"վարկյան", "վարկյան"}},
+ {"%d days", {"%d օր", "%d օր"}},
+ {"%d hours", {"%d ժամ", "%d ժամ"}},
+ {"%d minutes", {"%d րոպե", "%d րոպե"}},
+ {"%d seconds", {"%d վարկյան", "%d վարկյան"}},
{"", {"", ""}},
};
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Chinese.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022, The PurpleI2P Project
+* Copyright (c) 2022-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -13,7 +13,6 @@
#include "I18N.h"
// Simplified Chinese localization file
-// This is an example translation file without strings in it.
namespace i2p
{
@@ -32,21 +31,21 @@
static std::map<std::string, std::string> strings
{
- {"KiB", "KiB"},
- {"MiB", "MiB"},
- {"GiB", "GiB"},
+ {"%.2f KiB", "%.2f KiB"},
+ {"%.2f MiB", "%.2f MiB"},
+ {"%.2f GiB", "%.2f GiB"},
{"building", "正在构建"},
{"failed", "连接失败"},
{"expiring", "即将过期"},
- {"established", "连接已建立"},
+ {"established", "连接成功"},
{"unknown", "未知"},
- {"exploratory", "探测"},
+ {"exploratory", "探索"},
{"Purple I2P Webconsole", "Purple I2P 网页控制台"},
{"<b>i2pd</b> webconsole", "<b>i2pd</b> 网页控制台"},
{"Main page", "主页"},
{"Router commands", "路由命令"},
{"Local Destinations", "本地目标"},
- {"LeaseSets", "租契集"},
+ {"LeaseSets", "租约集"},
{"Tunnels", "隧道"},
{"Transit Tunnels", "中转隧道"},
{"Transports", "传输"},
@@ -58,11 +57,12 @@
{"Firewalled", "受到防火墙限制"},
{"Unknown", "未知"},
{"Proxy", "代理"},
- {"Mesh", "Mesh组网"},
- {"Error", "错误"},
+ {"Mesh", "自组网"},
{"Clock skew", "时钟偏移"},
{"Offline", "离线"},
{"Symmetric NAT", "对称 NAT"},
+ {"Full cone NAT", "全锥型NAT"},
+ {"No Descriptors", "无描述符"},
{"Uptime", "运行时间"},
{"Network status", "IPv4 网络状态"},
{"Network status v6", "IPv6 网络状态"},
@@ -70,7 +70,7 @@
{"Family", "家族"},
{"Tunnel creation success rate", "隧道创建成功率"},
{"Received", "已接收"},
- {"KiB/s", "KiB/s"},
+ {"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "已发送"},
{"Transit", "中转"},
{"Data path", "数据文件路径"},
@@ -91,12 +91,12 @@
{"Address registration line", "地址域名注册"},
{"Domain", "域名"},
{"Generate", "生成"},
- {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>注意:</b> 结果字符串可以用于注册次级域名(例如:example.i2p)。若需注册次级域名,请使用 i2pd-tools。"},
+ {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>注意:</b> 结果字符串只能用于注册二级域名(例如:example.i2p)。若需注册三级域名,请使用 i2pd-tools。"},
{"Address", "地址"},
{"Type", "类型"},
{"EncType", "加密类型"},
{"Inbound tunnels", "入站隧道"},
- {"ms", "毫秒"},
+ {"%dms", "%dms"},
{"Outbound tunnels", "出站隧道"},
{"Tags", "标签"},
{"Incoming", "传入"},
@@ -109,6 +109,7 @@
{"Local Destination", "本地目标"},
{"Streams", "流"},
{"Close stream", "断开流"},
+ {"Such destination is not found", "找不到此目标"},
{"I2CP session not found", "未找到 I2CP 会话"},
{"I2CP is not enabled", "I2CP 未启用"},
{"Invalid", "无效"},
@@ -118,20 +119,21 @@
{"Gateway", "网关"},
{"TunnelID", "隧道 ID"},
{"EndDate", "结束日期"},
- {"not floodfill", "非洪泛"},
+ {"floodfill mode is disabled", "洪泛已禁用"},
{"Queue size", "队列大小"},
- {"Run peer test", "运行群体测试"},
+ {"Run peer test", "运行节点测试"},
+ {"Reload tunnels configuration", "重新载入隧道配置"},
{"Decline transit tunnels", "拒绝中转隧道"},
{"Accept transit tunnels", "允许中转隧道"},
- {"Cancel graceful shutdown", "取消离线"},
- {"Start graceful shutdown", "优雅地离线"},
+ {"Cancel graceful shutdown", "取消平滑关闭"},
+ {"Start graceful shutdown", "平滑关闭"},
{"Force shutdown", "强制停止"},
{"Reload external CSS styles", "重载外部 CSS 样式"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>注意:</b> 此处完成的任何操作都不是永久的,不会更改您的配置文件。"},
{"Logging level", "日志级别"},
{"Transit tunnels limit", "中转隧道限制"},
- {"Change", "更换"},
- {"Change language", "更换语言"},
+ {"Change", "修改"},
+ {"Change language", "更改语言"},
{"no transit tunnels currently built", "目前未构建中转隧道"},
{"SAM disabled", "SAM 已禁用"},
{"no sessions currently running", "没有正在运行的会话"},
@@ -141,15 +143,15 @@
{"Client Forwards", "客户端转发"},
{"Server Forwards", "服务器转发"},
{"Unknown page", "未知页面"},
- {"Invalid token", "无效凭证"},
+ {"Invalid token", "无效令牌"},
{"SUCCESS", "成功"},
{"Stream closed", "流已关闭"},
{"Stream not found or already was closed", "流未找到或已关闭"},
{"Destination not found", "找不到目标"},
{"StreamID can't be null", "StreamID 不能为空"},
{"Return to destination page", "返回目标页面"},
- {"You will be redirected in 5 seconds", "您将在5秒内被重定向"},
- {"Transit tunnels count must not exceed 65535", "中转隧道数量不能超过 65535"},
+ {"You will be redirected in %d seconds", "您将在%d秒内被重定向"},
+ {"Transit tunnels count must not exceed %d", "中转隧道数量限制为 %d"},
{"Back to commands list", "返回命令列表"},
{"Register at reg.i2p", "在 reg.i2p 注册域名"},
{"Description", "描述"},
@@ -157,42 +159,42 @@
{"Submit", "提交"},
{"Domain can't end with .b32.i2p", "域名不能以 .b32.i2p 结尾"},
{"Domain must end with .i2p", "域名必须以 .i2p 结尾"},
- {"Such destination is not found", "找不到此目标"},
{"Unknown command", "未知指令"},
{"Command accepted", "已接受指令"},
{"Proxy error", "代理错误"},
{"Proxy info", "代理信息"},
- {"Proxy error: Host not found", "代理错误:找不到主机"},
- {"Remote host not found in router's addressbook", "在路由的地址簿中找不到远程主机"},
- {"You may try to find this host on jump services below", "您可以尝试在下方的跳转服务上找到这个主机"},
+ {"Proxy error: Host not found", "代理错误:未找到主机"},
+ {"Remote host not found in router's addressbook", "在路由地址簿中未找到远程主机"},
+ {"You may try to find this host on jump services below", "您可以尝试在下方的跳转服务中找到此主机"},
{"Invalid request", "无效请求"},
{"Proxy unable to parse your request", "代理无法解析您的请求"},
- {"addresshelper is not supported", "不支持地址助手"},
- {"Host", "主机"},
- {"added to router's addressbook from helper", "将此地址从地址助手添加到地址簿"},
- {"Click here to proceed:", "点击此处继续:"},
- {"Continue", "继续"},
- {"Addresshelper found", "找到地址助手"},
- {"already in router's addressbook", "已在路由器的地址簿中"},
- {"Click here to update record:", "点击此处更新地址簿记录"},
- {"invalid request uri", "无效的 URL 请求"},
+ {"Addresshelper is not supported", "不支持地址助手"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "主机 %s <font color=red>已在路由地址簿中</font>。<b>请注意:此地址的来源可能是有害的!</b>点击此处更新记录:<a href=\"%s%s%s&update=true\">继续</a>"},
+ {"Addresshelper forced update rejected", "地址助手强制更新被拒绝"},
+ {"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "若要在路由器地址簿中添加主机 <b>%s</b> 请点击这里: <a href=\"%s%s%s\">继续</a>"},
+ {"Addresshelper request", "请求地址助手"},
+ {"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "主机 %s 已通过地址助手添加到路由地址簿中。点击此处继续:<a href=\"%s\">继续</a>"},
+ {"Addresshelper adding", "正在添加地址助手"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "主机 %s <font color=red>已在路由地址簿中</font>。点击此处更新记录:<a href=\"%s%s%s&update=true\">继续</a>"},
+ {"Addresshelper update", "更新地址助手"},
+ {"Invalid request URI", "无效的 URI 请求"},
{"Can't detect destination host from request", "无法从请求中检测到目标主机"},
- {"Outproxy failure", "出口代理失效"},
- {"bad outproxy settings", "错误的出口代理设置"},
- {"not inside I2P network, but outproxy is not enabled", "该地址不在 I2P 网络内,但未启用出口代理"},
- {"unknown outproxy url", "未知的出口代理地址"},
- {"cannot resolve upstream proxy", "无法解析上游代理"},
- {"hostname too long", "主机名过长"},
- {"cannot connect to upstream socks proxy", "无法连接到上游 socks 代理"},
- {"Cannot negotiate with socks proxy", "无法与 socks 代理协商"},
+ {"Outproxy failure", "出口代理故障"},
+ {"Bad outproxy settings", "错误的出口代理设置"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "主机 %s 不在 I2P 网络内,但出口代理未启用"},
+ {"Unknown outproxy URL", "未知的出口代理地址"},
+ {"Cannot resolve upstream proxy", "无法解析上游代理"},
+ {"Hostname is too long", "主机名过长"},
+ {"Cannot connect to upstream SOCKS proxy", "无法连接到上游 SOCKS 代理"},
+ {"Cannot negotiate with SOCKS proxy", "无法与 SOCKS 代理协商"},
{"CONNECT error", "连接错误"},
- {"Failed to Connect", "连接失败"},
- {"socks proxy error", "socks 代理错误"},
- {"failed to send request to upstream", "向上游发送请求失败"},
- {"No Reply From socks proxy", "没有来自 socks 代理的回复"},
- {"cannot connect", "无法连接"},
- {"http out proxy not implemented", "http 出口代理未实现"},
- {"cannot connect to upstream http proxy", "无法连接到上游 http 代理"},
+ {"Failed to connect", "连接失败"},
+ {"SOCKS proxy error", "SOCKS 代理错误"},
+ {"Failed to send request to upstream", "向上游发送请求失败"},
+ {"No reply from SOCKS proxy", "没有来自 SOCKS 代理的回复"},
+ {"Cannot connect", "无法连接"},
+ {"HTTP out proxy not implemented", "HTTP 出口代理未实现"},
+ {"Cannot connect to upstream HTTP proxy", "无法连接到上游 HTTP 代理"},
{"Host is down", "主机已关闭"},
{"Can't create connection to requested host, it may be down. Please try again later.", "无法创建到目标主机的连接。主机可能已下线,请稍后再试。"},
{"", ""},
@@ -200,10 +202,10 @@
static std::map<std::string, std::vector<std::string>> plurals
{
- {"days", {"天"}},
- {"hours", {"时"}},
- {"minutes", {"分"}},
- {"seconds", {"秒"}},
+ {"%d days", {"%d 天"}},
+ {"%d hours", {"%d 小时"}},
+ {"%d minutes", {"%d 分钟"}},
+ {"%d seconds", {"%d 秒"}},
{"", {""}},
};
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Czech.cpp
^
|
@@ -0,0 +1,204 @@
+/*
+* Copyright (c) 2022-2023, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*/
+
+#include <map>
+#include <vector>
+#include <string>
+#include <memory>
+#include "I18N.h"
+
+// Czech localization file
+
+namespace i2p
+{
+namespace i18n
+{
+namespace czech // language namespace
+{
+ // language name in lowercase
+ static std::string language = "czech";
+
+ // See for language plural forms here:
+ // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
+ static int plural (int n) {
+ return (n == 1) ? 0 : (n >= 2 && n <= 4) ? 1 : 2;
+ }
+
+ static std::map<std::string, std::string> strings
+ {
+ {"%.2f KiB", "%.2f KiB"},
+ {"%.2f MiB", "%.2f MiB"},
+ {"%.2f GiB", "%.2f GiB"},
+ {"building", "vytváří se"},
+ {"failed", "selhalo"},
+ {"expiring", "končící"},
+ {"established", "vytvořeno"},
+ {"unknown", "neznámý"},
+ {"exploratory", "průzkumné"},
+ {"Purple I2P Webconsole", "Purple I2P Webkonsole"},
+ {"<b>i2pd</b> webconsole", "<b>i2pd</b> webkonsole"},
+ {"Main page", "Hlavní stránka"},
+ {"Router commands", "Router příkazy"},
+ {"Local Destinations", "Lokální destinace"},
+ {"LeaseSets", "LeaseSety"},
+ {"Tunnels", "Tunely"},
+ {"Transit Tunnels", "Transitní tunely"},
+ {"Transports", "Transporty"},
+ {"I2P tunnels", "I2P tunely"},
+ {"SAM sessions", "SAM relace"},
+ {"ERROR", "CHYBA"},
+ {"OK", "OK"},
+ {"Testing", "Testuji"},
+ {"Firewalled", "Za Firewallem"},
+ {"Unknown", "Neznámý"},
+ {"Proxy", "Proxy"},
+ {"Mesh", "Síť"},
+ {"Clock skew", "Časová nesrovnalost"},
+ {"Offline", "Offline"},
+ {"Symmetric NAT", "Symetrický NAT"},
+ {"Uptime", "Doba provozu"},
+ {"Network status", "Status sítě"},
+ {"Network status v6", "Status sítě v6"},
+ {"Stopping in", "Zastavuji za"},
+ {"Family", "Rodina"},
+ {"Tunnel creation success rate", "Úspěšnost vytváření tunelů"},
+ {"Received", "Přijato"},
+ {"%.2f KiB/s", "%.2f KiB/s"},
+ {"Sent", "Odesláno"},
+ {"Transit", "Tranzit"},
+ {"Data path", "Cesta k data souborům"},
+ {"Hidden content. Press on text to see.", "Skrytý kontent. Pro zobrazení, klikni na text."},
+ {"Router Ident", "Routerová Identita"},
+ {"Router Family", "Rodina routerů"},
+ {"Router Caps", "Omezení Routerů"},
+ {"Version", "Verze"},
+ {"Our external address", "Naše externí adresa"},
+ {"supported", "podporováno"},
+ {"Routers", "Routery"},
+ {"Floodfills", "Floodfilly"},
+ {"Client Tunnels", "Klientské tunely"},
+ {"Services", "Služby"},
+ {"Enabled", "Zapnuto"},
+ {"Disabled", "Vypnuto"},
+ {"Encrypted B33 address", "Šifrovaná adresa B33"},
+ {"Address registration line", "Registrační řádek adresy"},
+ {"Domain", "Doména"},
+ {"Generate", "Vygenerovat"},
+ {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Poznámka:</b> výsledný řetězec může být použit pouze pro registraci 2LD domén (example.i2p). Pro registraci subdomén použijte prosím i2pd-tools."},
+ {"Address", "Adresa"},
+ {"Type", "Typ"},
+ {"EncType", "EncType"},
+ {"Inbound tunnels", "Příchozí tunely"},
+ {"%dms", "%dms"},
+ {"Outbound tunnels", "Odchozí tunely"},
+ {"Tags", "Štítky"},
+ {"Incoming", "Příchozí"},
+ {"Outgoing", "Odchozí"},
+ {"Destination", "Destinace"},
+ {"Amount", "Množství"},
+ {"Incoming Tags", "Příchozí štítky"},
+ {"Tags sessions", "Relace štítků"},
+ {"Status", "Status"},
+ {"Local Destination", "Lokální Destinace"},
+ {"Streams", "Toky"},
+ {"Close stream", "Uzavřít tok"},
+ {"I2CP session not found", "I2CP relace nenalezena"},
+ {"I2CP is not enabled", "I2CP není zapnuto"},
+ {"Invalid", "Neplatný"},
+ {"Store type", "Druh uložení"},
+ {"Expires", "Vyprší"},
+ {"Non Expired Leases", "Nevypršené Leasy"},
+ {"Gateway", "Brána"},
+ {"TunnelID", "ID tunelu"},
+ {"EndDate", "Datum ukončení"},
+ {"Queue size", "Velikost fronty"},
+ {"Run peer test", "Spustit peer test"},
+ {"Decline transit tunnels", "Odmítnout tranzitní tunely"},
+ {"Accept transit tunnels", "Přijmout tranzitní tunely"},
+ {"Cancel graceful shutdown", "Zrušit hladké vypnutí"},
+ {"Start graceful shutdown", "Zahájit hladké vypnutí"},
+ {"Force shutdown", "Vynutit vypnutí"},
+ {"Reload external CSS styles", "Znovu načíst externí CSS"},
+ {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Poznámka:</b> žádná vykonaná akce zde není trvalá a nemění konfigurační soubory."},
+ {"Logging level", "Úroveň logování"},
+ {"Transit tunnels limit", "Limit tranzitních tunelů"},
+ {"Change", "Změnit"},
+ {"Change language", "Změnit jazyk"},
+ {"no transit tunnels currently built", "Žádný tranzitní tunel není momentálně vytvořen"},
+ {"SAM disabled", "SAM vypnutý"},
+ {"no sessions currently running", "Momentálně nejsou spuštěné žádné relace"},
+ {"SAM session not found", "SAM relace nenalezena"},
+ {"SAM Session", "SAM Relace"},
+ {"Server Tunnels", "Server Tunely"},
+ {"Client Forwards", "Přesměrování Klienta"},
+ {"Server Forwards", "Přesměrování Serveru"},
+ {"Unknown page", "Neznámá stránka"},
+ {"Invalid token", "Neplatný token"},
+ {"SUCCESS", "ÚSPĚCH"},
+ {"Stream closed", "Tok uzavřen"},
+ {"Stream not found or already was closed", "Tok nenalezen nebo byl již uzavřen"},
+ {"Destination not found", "Destinace nenalezena"},
+ {"StreamID can't be null", "StreamID nemůže být null"},
+ {"Return to destination page", "Zpět na stránku destinací"},
+ {"Back to commands list", "Zpět na list příkazů"},
+ {"Register at reg.i2p", "Zaregistrovat na reg.i2p"},
+ {"Description", "Popis"},
+ {"A bit information about service on domain", "Trochu informací o službě na doméně"},
+ {"Submit", "Odeslat"},
+ {"Domain can't end with .b32.i2p", "Doména nesmí končit na .b32.i2p"},
+ {"Domain must end with .i2p", "Doména musí končit s .i2p"},
+ {"Such destination is not found", "Takováto destinace nebyla nalezena"},
+ {"Unknown command", "Neznámý příkaz"},
+ {"Command accepted", "Příkaz přijat"},
+ {"Proxy error", "Chyba proxy serveru"},
+ {"Proxy info", "Proxy informace"},
+ {"Proxy error: Host not found", "Chyba proxy serveru: Hostitel nenalezen"},
+ {"Remote host not found in router's addressbook", "Vzdálený hostitel nebyl nalezen v adresáři routeru"},
+ {"You may try to find this host on jump services below", "Můžete se pokusit najít tohoto hostitele na startovacích službách níže"},
+ {"Invalid request", "Neplatný požadavek"},
+ {"Proxy unable to parse your request", "Proxy server nemohl zpracovat váš požadavek"},
+ {"Invalid request URI", "Neplatný URI požadavek"},
+ {"Can't detect destination host from request", "Nelze zjistit cílového hostitele z požadavku"},
+ {"Outproxy failure", "Outproxy selhání"},
+ {"Bad outproxy settings", "Špatné outproxy nastavení"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "Hostitel %s není uvnitř I2P sítě a outproxy není nastavena"},
+ {"Unknown outproxy URL", "Neznámá outproxy URL"},
+ {"Cannot resolve upstream proxy", "Nelze rozluštit upstream proxy server"},
+ {"Hostname is too long", "Název hostitele je příliš dlouhý"},
+ {"Cannot connect to upstream SOCKS proxy", "Nelze se připojit k upstream SOCKS proxy serveru"},
+ {"Cannot negotiate with SOCKS proxy", "Nelze vyjednávat se SOCKS proxy serverem"},
+ {"CONNECT error", "Chyba PŘIPOJENÍ"},
+ {"Failed to connect", "Připojení se nezdařilo"},
+ {"SOCKS proxy error", "Chyba SOCKS proxy serveru"},
+ {"Failed to send request to upstream", "Odeslání žádosti upstream serveru se nezdařilo"},
+ {"No reply from SOCKS proxy", "Žádná odpověď od SOCKS proxy serveru"},
+ {"Cannot connect", "Nelze se připojit"},
+ {"HTTP out proxy not implemented", "HTTP out proxy není implementován"},
+ {"Cannot connect to upstream HTTP proxy", "Nelze se připojit k upstream HTTP proxy serveru"},
+ {"Host is down", "Hostitel je nedostupný"},
+ {"Can't create connection to requested host, it may be down. Please try again later.", "Připojení k požadovanému hostiteli nelze vytvořit, může být nedostupný. Zkuste to, prosím, znovu později."},
+ {"", ""},
+ };
+
+ static std::map<std::string, std::vector<std::string>> plurals
+ {
+ {"%d days", {"%d den", "%d dny", "%d dní", "%d dní"}},
+ {"%d hours", {"%d hodina", "%d hodiny", "%d hodin", "%d hodin"}},
+ {"%d minutes", {"%d minuta", "%d minuty", "%d minut", "%d minut"}},
+ {"%d seconds", {"%d vteřina", "%d vteřiny", "%d vteřin", "%d vteřin"}},
+ {"", {"", "", "", ""}},
+ };
+
+ std::shared_ptr<const i2p::i18n::Locale> GetLocale()
+ {
+ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
+ }
+
+} // language
+} // i18n
+} // i2p
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/French.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022, The PurpleI2P Project
+* Copyright (c) 2022-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -31,9 +31,9 @@
static std::map<std::string, std::string> strings
{
- {"KiB", "Kio"},
- {"MiB", "Mio"},
- {"GiB", "Gio"},
+ {"%.2f KiB", "%.2f Kio"},
+ {"%.2f MiB", "%.2f Mio"},
+ {"%.2f GiB", "%.2f Gio"},
{"building", "En construction"},
{"failed", "échoué"},
{"expiring", "expiré"},
@@ -58,18 +58,20 @@
{"Unknown", "Inconnu"},
{"Proxy", "Proxy"},
{"Mesh", "Maillé"},
- {"Error", "Erreur"},
{"Clock skew", "Horloge décalée"},
{"Offline", "Hors ligne"},
{"Symmetric NAT", "NAT symétrique"},
+ {"Full cone NAT", "NAT à cône complet"},
+ {"No Descriptors", "Aucuns Descripteurs"},
{"Uptime", "Temps de fonctionnement"},
{"Network status", "État du réseau"},
{"Network status v6", "État du réseau v6"},
{"Stopping in", "Arrêt dans"},
{"Family", "Famille"},
{"Tunnel creation success rate", "Taux de succès de création de tunnels"},
+ {"Total tunnel creation success rate", "Taux de réussite de création de tunnel"},
{"Received", "Reçu"},
- {"KiB/s", "kio/s"},
+ {"%.2f KiB/s", "%.2f Kio/s"},
{"Sent", "Envoyé"},
{"Transit", "Transité"},
{"Data path", "Emplacement des données"},
@@ -81,6 +83,7 @@
{"Our external address", "Notre adresse externe"},
{"supported", "supporté"},
{"Routers", "Routeurs"},
+ {"Floodfills", "Remplisseurs"},
{"Client Tunnels", "Tunnels clients"},
{"Services", "Services"},
{"Enabled", "Activé"},
@@ -89,11 +92,13 @@
{"Address registration line", "Ligne d'inscription de l'adresse"},
{"Domain", "Domaine"},
{"Generate", "Générer"},
- {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Note:</b> La chaîne résultante peut seulement être utilisée pour enregistrer les domaines 2LD (exemple.i2p). Pour enregistrer des sous-domaines, veuillez utiliser i2pd-tools."},
+ {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Note :</b> La chaîne résultante peut seulement être utilisée pour enregistrer les domaines 2LD (exemple.i2p). Pour enregistrer des sous-domaines, veuillez utiliser i2pd-tools."},
{"Address", "Adresse"},
{"Type", "Type"},
+ {"EncType", "EncType"},
+ {"Expire LeaseSet", "Expirer le jeu de baux"},
{"Inbound tunnels", "Tunnels entrants"},
- {"ms", "ms"},
+ {"%dms", "%dms"},
{"Outbound tunnels", "Tunnels sortants"},
{"Tags", "Balises"},
{"Incoming", "Entrant"},
@@ -106,6 +111,7 @@
{"Local Destination", "Destination locale"},
{"Streams", "Flux"},
{"Close stream", "Fermer le flux"},
+ {"Such destination is not found", "Cette destination est introuvable"},
{"I2CP session not found", "Session I2CP introuvable"},
{"I2CP is not enabled", "I2CP est désactivé"},
{"Invalid", "Invalide"},
@@ -115,15 +121,17 @@
{"Gateway", "Passerelle"},
{"TunnelID", "ID du tunnel"},
{"EndDate", "Date de fin"},
+ {"floodfill mode is disabled", "le mode de remplissage est désactivé"},
{"Queue size", "Longueur de la file"},
{"Run peer test", "Lancer test des pairs"},
+ {"Reload tunnels configuration", "Recharger la configuration des tunnels"},
{"Decline transit tunnels", "Refuser les tunnels transitoires"},
{"Accept transit tunnels", "Accepter les tunnels transitoires"},
{"Cancel graceful shutdown", "Annuler l'arrêt gracieux"},
{"Start graceful shutdown", "Démarrer l'arrêt gracieux"},
{"Force shutdown", "Forcer l'arrêt"},
{"Reload external CSS styles", "Rafraîchir les styles CSS externes"},
- {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Note:</b> Toute action effectuée ici n'est pas permanente et ne modifie pas vos fichiers de configuration."},
+ {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Note :</b> Toute action effectuée ici n'est pas permanente et ne modifie pas vos fichiers de configuration."},
{"Logging level", "Niveau de journalisation"},
{"Transit tunnels limit", "Limite sur les tunnels transitoires"},
{"Change", "Changer"},
@@ -134,6 +142,8 @@
{"SAM session not found", "session SAM introuvable"},
{"SAM Session", "Session SAM"},
{"Server Tunnels", "Tunnels serveurs"},
+ {"Client Forwards", "Transmission du client"},
+ {"Server Forwards", "Transmission du serveur"},
{"Unknown page", "Page inconnue"},
{"Invalid token", "Jeton invalide"},
{"SUCCESS", "SUCCÈS"},
@@ -142,8 +152,10 @@
{"Destination not found", "Destination introuvable"},
{"StreamID can't be null", "StreamID ne peut pas être vide"},
{"Return to destination page", "Retourner à la page de destination"},
- {"You will be redirected in 5 seconds", "Vous allez être redirigé dans cinq secondes"},
- {"Transit tunnels count must not exceed 65535", "Le nombre de tunnels transitoires ne doit pas dépasser 65535"},
+ {"You will be redirected in %d seconds", "Vous serez redirigé dans %d secondes"},
+ {"LeaseSet expiration time updated", "Temps d'expiration du jeu de baux mis à jour"},
+ {"LeaseSet is not found or already expired", "Le jeu de baux est introuvable ou a déjà expiré"},
+ {"Transit tunnels count must not exceed %d", "Le nombre de tunnels de transit ne doit pas excéder %d"},
{"Back to commands list", "Retour à la liste des commandes"},
{"Register at reg.i2p", "Inscription à reg.i2p"},
{"Description", "Description"},
@@ -151,42 +163,42 @@
{"Submit", "Soumettre"},
{"Domain can't end with .b32.i2p", "Le domaine ne peut pas terminer par .b32.i2p"},
{"Domain must end with .i2p", "Le domaine doit terminer par .i2p"},
- {"Such destination is not found", "Cette destination est introuvable"},
{"Unknown command", "Commande inconnue"},
{"Command accepted", "Commande acceptée"},
{"Proxy error", "Erreur de proxy"},
{"Proxy info", "Information sur le proxy"},
- {"Proxy error: Host not found", "Erreur de proxy: Hôte introuvable"},
+ {"Proxy error: Host not found", "Erreur de proxy : Hôte introuvable"},
{"Remote host not found in router's addressbook", "Hôte distant introuvable dans le carnet d'adresse du routeur"},
{"You may try to find this host on jump services below", "Vous pouvez essayer de trouver cet hôte sur des services de redirection ci-dessous"},
{"Invalid request", "Requête invalide"},
{"Proxy unable to parse your request", "Proxy incapable de comprendre votre requête"},
- {"addresshelper is not supported", "Assistant d'adresse non supporté"},
- {"Host", "Hôte"},
- {"added to router's addressbook from helper", "Ajouté au carnet d'adresse du routeur par l'assistant"},
- {"Click here to proceed:", "Cliquez ici pour continuer:"},
- {"Continue", "Continuer"},
- {"Addresshelper found", "Assistant d'adresse trouvé"},
- {"already in router's addressbook", "déjà dans le carnet d'adresses du routeur"},
- {"Click here to update record:", "Cliquez ici pour mettre à jour le carnet d'adresse:"},
- {"invalid request uri", "uri de la requête invalide"},
+ {"Addresshelper is not supported", "Assistant d'adresse non supporté"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'hôte %s est <font color=red>déjà dans le carnet d'adresses du routeur</font>. <b>Attention : la source de cette URL peut être nuisible !</b> Cliquez ici pour mettre à jour l'enregistrement : <a href=\"%s%s%s&update=true\">Continuer</a>."},
+ {"Addresshelper forced update rejected", "Mise à jour forcée des assistants d'adresses rejetée"},
+ {"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Pour ajouter l'hôte <b>%s</b> au carnet d'adresses du routeur, cliquez ici : <a href=\"%s%s%s\">Continuer</a>."},
+ {"Addresshelper request", "Demande à l'assistant d'adresse"},
+ {"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "L'hôte %s a été ajouté au carnet d'adresses du routeur depuis l'assistant. Cliquez ici pour continuer : <a href=\"%s\">Continuer</a>."},
+ {"Addresshelper adding", "Ajout de l'assistant d'adresse"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'hôte %s est <font color=red>déjà dans le carnet d'adresses du routeur</font>. Cliquez ici pour mettre à jour le dossier : <a href=\"%s%s%s&update=true\">Continuer</a>."},
+ {"Addresshelper update", "Mise à jour de l'assistant d'adresse"},
+ {"Invalid request URI", "URI de la requête invalide"},
{"Can't detect destination host from request", "Impossible de détecter l'hôte de destination à partir de la requête"},
{"Outproxy failure", "Échec de proxy de sortie"},
- {"bad outproxy settings", "Mauvaise configuration du proxy de sortie"},
- {"not inside I2P network, but outproxy is not enabled", "pas dans le réseau I2P, mais le proxy de sortie n'est pas activé"},
- {"unknown outproxy url", "URL du proxy de sortie inconnu"},
- {"cannot resolve upstream proxy", "impossible de résoudre l'adresse du proxy en amont"},
- {"hostname too long", "nom d'hôte trop long"},
- {"cannot connect to upstream socks proxy", "impossible de se connecter au proxy socks en amont"},
- {"Cannot negotiate with socks proxy", "Impossible de négocier avec le proxy socks"},
+ {"Bad outproxy settings", "Mauvaise configuration du proxy de sortie"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "Hôte %s pas dans le réseau I2P, mais le proxy de sortie n'est pas activé"},
+ {"Unknown outproxy URL", "URL du proxy de sortie inconnu"},
+ {"Cannot resolve upstream proxy", "Impossible de résoudre l'adresse du proxy en amont"},
+ {"Hostname is too long", "Nom d'hôte trop long"},
+ {"Cannot connect to upstream SOCKS proxy", "Impossible de se connecter au proxy SOCKS en amont"},
+ {"Cannot negotiate with SOCKS proxy", "Impossible de négocier avec le proxy SOCKS"},
{"CONNECT error", "Erreur de connexion"},
- {"Failed to Connect", "Échec de connexion"},
- {"socks proxy error", "Erreur de proxy socks"},
- {"failed to send request to upstream", "Erreur lors de l'envoie de la requête en amont"},
- {"No Reply From socks proxy", "Pas de réponse du proxy socks"},
- {"cannot connect", "impossible de connecter"},
- {"http out proxy not implemented", "Proxy de sortie HTTP non implémenté"},
- {"cannot connect to upstream http proxy", "impossible de se connecter au proxy HTTP en amont"},
+ {"Failed to connect", "Échec de connexion"},
+ {"SOCKS proxy error", "Erreur de proxy SOCKS"},
+ {"Failed to send request to upstream", "Erreur lors de l'envoie de la requête en amont"},
+ {"No reply from SOCKS proxy", "Pas de réponse du proxy SOCKS"},
+ {"Cannot connect", "Impossible de connecter"},
+ {"HTTP out proxy not implemented", "Proxy de sortie HTTP non implémenté"},
+ {"Cannot connect to upstream HTTP proxy", "Impossible de se connecter au proxy HTTP en amont"},
{"Host is down", "Hôte hors service"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Impossible d'établir une connexion avec l'hôte, il est peut-être hors service. Veuillez réessayer plus tard."},
{"", ""},
@@ -194,10 +206,10 @@
static std::map<std::string, std::vector<std::string>> plurals
{
- {"days", {"jour", "jours"}},
- {"hours", {"heure", "heures"}},
- {"minutes", {"minute", "minutes"}},
- {"seconds", {"seconde", "secondes"}},
+ {"%d days", {"%d jour", "%d jours"}},
+ {"%d hours", {"%d heure", "%d heures"}},
+ {"%d minutes", {"%d minute", "%d minutes"}},
+ {"%d seconds", {"%d seconde", "%d secondes"}},
{"", {"", ""}},
};
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/German.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022, The PurpleI2P Project
+* Copyright (c) 2022-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -31,16 +31,16 @@
static std::map<std::string, std::string> strings
{
- {"Purple I2P Webconsole", "Purple-I2P-Webkonsole"},
- {"KiB", "KiB"},
- {"MiB", "MiB"},
- {"GiB", "GiB"},
+ {"%.2f KiB", "%.2f KiB"},
+ {"%.2f MiB", "%.2f MiB"},
+ {"%.2f GiB", "%.2f GiB"},
{"building", "In Bau"},
{"failed", "fehlgeschlagen"},
{"expiring", "läuft ab"},
{"established", "hergestellt"},
{"unknown", "Unbekannt"},
{"exploratory", "erforschend"},
+ {"Purple I2P Webconsole", "Purple I2P-Webkonsole"},
{"<b>i2pd</b> webconsole", "<b>i2pd</b>-Webkonsole"},
{"Main page", "Startseite"},
{"Router commands", "Routerbefehle"},
@@ -49,8 +49,8 @@
{"Tunnels", "Tunnel"},
{"Transit Tunnels", "Transittunnel"},
{"Transports", "Transporte"},
- {"I2P tunnels", "I2P-Tunnel"},
- {"SAM sessions", "SAM-Sitzungen"},
+ {"I2P tunnels", "I2P Tunnel"},
+ {"SAM sessions", "SAM Sitzungen"},
{"ERROR", "FEHLER"},
{"OK", "OK"},
{"Testing", "Testen"},
@@ -58,10 +58,10 @@
{"Unknown", "Unbekannt"},
{"Proxy", "Proxy"},
{"Mesh", "Mesh"},
- {"Error", "Fehler"},
{"Clock skew", "Zeitabweichung"},
{"Offline", "Offline"},
{"Symmetric NAT", "Symmetrisches NAT"},
+ {"No Descriptors", "Keine Beschreibungen"},
{"Uptime", "Laufzeit"},
{"Network status", "Netzwerkstatus"},
{"Network status v6", "Netzwerkstatus v6"},
@@ -69,7 +69,7 @@
{"Family", "Familie"},
{"Tunnel creation success rate", "Erfolgsrate der Tunnelerstellung"},
{"Received", "Eingegangen"},
- {"KiB/s", "KiB/s"},
+ {"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "Gesendet"},
{"Transit", "Transit"},
{"Data path", "Datenpfad"},
@@ -95,7 +95,7 @@
{"Type", "Typ"},
{"EncType", "Verschlüsselungstyp"},
{"Inbound tunnels", "Eingehende Tunnel"},
- {"ms", "ms"},
+ {"%dms", "%dms"},
{"Outbound tunnels", "Ausgehende Tunnel"},
{"Tags", "Tags"},
{"Incoming", "Eingehend"},
@@ -117,9 +117,10 @@
{"Gateway", "Gateway"},
{"TunnelID", "TunnelID"},
{"EndDate", "Enddatum"},
- {"not floodfill", "kein Floodfill"},
+ {"floodfill mode is disabled", "Floodfill Modus ist deaktiviert"},
{"Queue size", "Größe der Warteschlange"},
{"Run peer test", "Peer-Test durchführen"},
+ {"Reload tunnels configuration", "Tunnel Konfiguration neu laden"},
{"Decline transit tunnels", "Transittunnel ablehnen"},
{"Accept transit tunnels", "Transittunnel akzeptieren"},
{"Cancel graceful shutdown", "Beende das kontrollierte Herunterfahren"},
@@ -147,8 +148,8 @@
{"Destination not found", "Ziel nicht gefunden"},
{"StreamID can't be null", "StreamID kann nicht null sein"},
{"Return to destination page", "Zurück zur Ziel-Seite"},
- {"You will be redirected in 5 seconds", "Du wirst in 5 Sekunden weitergeleitet"},
- {"Transit tunnels count must not exceed 65535", "Es darf maximal 65535 Transittunnel geben"},
+ {"You will be redirected in %d seconds", "Du wirst umgeleitet in %d Sekunden"},
+ {"Transit tunnels count must not exceed %d", "Die Anzahl der Transittunnel darf nicht über %d gehen"},
{"Back to commands list", "Zurück zur Befehlsliste"},
{"Register at reg.i2p", "Auf reg.i2p registrieren"},
{"Description", "Beschreibung"},
@@ -166,32 +167,33 @@
{"You may try to find this host on jump services below", "Vielleicht kannst du diesen Host auf einem der nachfolgenden Jump-Services finden"},
{"Invalid request", "Ungültige Anfrage"},
{"Proxy unable to parse your request", "Proxy konnte die Anfrage nicht verarbeiten"},
- {"addresshelper is not supported", "Addresshelfer wird nicht unterstützt"},
- {"Host", "Host"},
- {"added to router's addressbook from helper", "vom Helfer zum Router-Adressbuch hinzugefügt"},
- {"Click here to proceed:", "Klicke hier um fortzufahren:"},
- {"Continue", "Fortsetzen"},
- {"Addresshelper found", "Adresshelfer gefunden"},
- {"already in router's addressbook", "bereits im Adressbuch des Routers"},
- {"Click here to update record:", "Klicke hier, um den Eintrag zu aktualisieren:"},
- {"invalid request uri", "ungültige Anfrage-URI"},
+ {"Addresshelper is not supported", "Adresshelfer wird nicht unterstützt"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Host %s ist <font color=red>bereits im Adressbuch des Routers</font>. <b>Vorsicht: Die Quelle dieser URL kann schädlich sein!</b> Klicken Sie hier, um den Datensatz zu aktualisieren: <a href=\"%s%s%s&update=true\">Weiter</a>."},
+ {"Addresshelper forced update rejected", "Adresshelfer gezwungene Aktualisierung abgelehnt"},
+ {"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Um den Host <b>%s</b> im Adressbuch des Routers hinzuzufügen, klicken Sie hier: <a href=\"%s%s%s\">Weiter</a>."},
+ {"Addresshelper request", "Adresshelfer gefunden"},
+ {"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Host %s wurde vom Helfer zum Adressbuch des Routers hinzugefügt. Klicken Sie hier, um fortzufahren: <a href=\"%s\">Weiter</a>."},
+ {"Addresshelper adding", "Adresshelfer hinzufügen"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Host %s ist <font color=red>bereits im Adressbuch des Routers</font>. Klicken Sie hier, um den Eintrag zu aktualisieren: <a href=\"%s%s%s&update=true\">Weiter</a>."},
+ {"Addresshelper update", "Adresshelfer aktualisieren"},
+ {"Invalid request URI", "Ungültige Anfrage-URI"},
{"Can't detect destination host from request", "Kann den Ziel-Host von der Anfrage nicht erkennen"},
{"Outproxy failure", "Outproxy-Fehler"},
- {"bad outproxy settings", "ungültige Outproxy-Einstellungen"},
- {"not inside I2P network, but outproxy is not enabled", "außerhalb des I2P-Netzwerks, aber Outproxy ist nicht aktiviert"},
- {"unknown outproxy url", "unbekannte Outproxy-URL"},
- {"cannot resolve upstream proxy", "kann den Upstream-Proxy nicht auflösen"},
- {"hostname too long", "Hostname zu lang"},
- {"cannot connect to upstream socks proxy", "Kann keine Verbindung zum Upstream-Socks-Proxy herstellen"},
- {"Cannot negotiate with socks proxy", "Kann nicht mit Socks-Proxy verhandeln"},
+ {"Bad outproxy settings", "Ungültige Outproxy-Einstellungen"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "Host %s außerhalb des I2P-Netzwerks, aber Outproxy ist nicht aktiviert"},
+ {"Unknown outproxy URL", "Unbekannte Outproxy-URL"},
+ {"Cannot resolve upstream proxy", "Kann den Upstream-Proxy nicht auflösen"},
+ {"Hostname is too long", "Hostname zu lang"},
+ {"Cannot connect to upstream SOCKS proxy", "Kann keine Verbindung zum Upstream-SOCKS-Proxy herstellen"},
+ {"Cannot negotiate with SOCKS proxy", "Kann nicht mit SOCKS-Proxy verhandeln"},
{"CONNECT error", "CONNECT-Fehler"},
- {"Failed to Connect", "Verbindung konnte nicht hergestellt werden"},
- {"socks proxy error", "Socks-Proxy-Fehler"},
- {"failed to send request to upstream", "Anfrage an den Upstream zu senden ist gescheitert"},
- {"No Reply From socks proxy", "Keine Antwort vom Socks-Proxy"},
- {"cannot connect", "kann nicht verbinden"},
- {"http out proxy not implemented", "HTTP-Outproxy nicht implementiert"},
- {"cannot connect to upstream http proxy", "Kann nicht zu Upstream-HTTP-Proxy verbinden"},
+ {"Failed to connect", "Verbindung konnte nicht hergestellt werden"},
+ {"SOCKS proxy error", "SOCKS-Proxy-Fehler"},
+ {"Failed to send request to upstream", "Anfrage an den Upstream zu senden ist gescheitert"},
+ {"No reply from SOCKS proxy", "Keine Antwort vom SOCKS-Proxy"},
+ {"Cannot connect", "Kann nicht verbinden"},
+ {"HTTP out proxy not implemented", "HTTP-Outproxy nicht implementiert"},
+ {"Cannot connect to upstream HTTP proxy", "Kann nicht zu Upstream-HTTP-Proxy verbinden"},
{"Host is down", "Host ist offline"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Konnte keine Verbindung zum angefragten Host aufbauen, vielleicht ist er offline. Versuche es später noch mal."},
{"", ""},
@@ -199,10 +201,10 @@
static std::map<std::string, std::vector<std::string>> plurals
{
- {"days", {"Tag", "Tage"}},
- {"hours", {"Stunde", "Stunden"}},
- {"minutes", {"Minute", "Minuten"}},
- {"seconds", {"Sekunde", "Sekunden"}},
+ {"%d days", {"%d Tag", "%d Tage"}},
+ {"%d hours", {"%d Stunde", "%d Stunden"}},
+ {"%d minutes", {"%d Minute", "%d Minuten"}},
+ {"%d seconds", {"%d Sekunde", "%d Sekunden"}},
{"", {"", ""}},
};
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/I18N.cpp
^
|
@@ -0,0 +1,43 @@
+/*
+* Copyright (c) 2021-2023, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*/
+
+#include <clocale>
+#include "ClientContext.h"
+#include "I18N_langs.h"
+#include "I18N.h"
+
+namespace i2p
+{
+namespace i18n
+{
+ void SetLanguage(const std::string &lang)
+ {
+ const auto it = i2p::i18n::languages.find(lang);
+ if (it == i2p::i18n::languages.end()) // fallback
+ {
+ i2p::client::context.SetLanguage (i2p::i18n::english::GetLocale());
+ setlocale(LC_NUMERIC, "english");
+ }
+ else
+ {
+ i2p::client::context.SetLanguage (it->second.LocaleFunc());
+ setlocale(LC_NUMERIC, lang.c_str()); // set decimal point based on language
+ }
+ }
+
+ std::string translate (const std::string& arg)
+ {
+ return i2p::client::context.GetLanguage ()->GetString (arg);
+ }
+
+ std::string translate (const std::string& arg, const std::string& arg2, const int& n)
+ {
+ return i2p::client::context.GetLanguage ()->GetPlural (arg, arg2, n);
+ }
+} // i18n
+} // i2p
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/I18N.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2021-2022, The PurpleI2P Project
+* Copyright (c) 2021-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -9,37 +9,127 @@
#ifndef __I18N_H__
#define __I18N_H__
-#include "ClientContext.h"
+#include <string>
+#include <map>
+#include <utility>
+#include <functional>
namespace i2p
{
namespace i18n
{
- inline void SetLanguage(const std::string &lang)
+ class Locale
{
- const auto it = i2p::i18n::languages.find(lang);
- if (it == i2p::i18n::languages.end()) // fallback
- i2p::client::context.SetLanguage (i2p::i18n::english::GetLocale());
- else
- i2p::client::context.SetLanguage (it->second.LocaleFunc());
- }
-
- inline std::string translate (const std::string& arg)
- {
- return i2p::client::context.GetLanguage ()->GetString (arg);
- }
-
- inline std::string translate (const std::string& arg, const std::string& arg2, const int& n)
- {
- return i2p::client::context.GetLanguage ()->GetPlural (arg, arg2, n);
- }
+ public:
+ Locale (
+ const std::string& language,
+ const std::map<std::string, std::string>& strings,
+ const std::map<std::string, std::vector<std::string>>& plurals,
+ std::function<int(int)> formula
+ ): m_Language (language), m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { };
+
+ // Get activated language name for webconsole
+ std::string GetLanguage() const
+ {
+ return m_Language;
+ }
+
+ std::string GetString (const std::string& arg) const
+ {
+ const auto it = m_Strings.find(arg);
+ if (it == m_Strings.end())
+ {
+ return arg;
+ }
+ else
+ {
+ return it->second;
+ }
+ }
+
+ std::string GetPlural (const std::string& arg, const std::string& arg2, const int& n) const
+ {
+ const auto it = m_Plurals.find(arg2);
+ if (it == m_Plurals.end()) // not found, fallback to english
+ {
+ return n == 1 ? arg : arg2;
+ }
+ else
+ {
+ int form = m_Formula(n);
+ return it->second[form];
+ }
+ }
+
+ private:
+ const std::string m_Language;
+ const std::map<std::string, std::string> m_Strings;
+ const std::map<std::string, std::vector<std::string>> m_Plurals;
+ std::function<int(int)> m_Formula;
+ };
+
+ void SetLanguage(const std::string &lang);
+ std::string translate (const std::string& arg);
+ std::string translate (const std::string& arg, const std::string& arg2, const int& n);
} // i18n
} // i2p
-template<typename... TArgs>
-std::string tr (TArgs&&... args)
+/**
+ * @brief Get translation of string
+ * @param arg String with message
+ */
+template<typename TValue>
+std::string tr (TValue&& arg)
+{
+ return i2p::i18n::translate(std::forward<TValue>(arg));
+}
+
+/**
+ * @brief Get translation of string and format it
+ * @param arg String with message
+ * @param args Array of arguments for string formatting
+*/
+template<typename TValue, typename... TArgs>
+std::string tr (TValue&& arg, TArgs&&... args)
+{
+ std::string tr_str = i2p::i18n::translate(std::forward<TValue>(arg));
+
+ size_t size = std::snprintf(NULL, 0, tr_str.c_str(), std::forward<TArgs>(args)...);
+ std::string str(size, 0);
+ std::snprintf(&str.front(), size + 1, tr_str.c_str(), std::forward<TArgs>(args)...);
+
+ return str;
+}
+
+/**
+ * @brief Get translation of string with plural forms
+ * @param arg String with message in singular form
+ * @param arg2 String with message in plural form
+ * @param n Integer, used for selection of form
+ */
+template<typename TValue, typename TValue2>
+std::string ntr (TValue&& arg, TValue2&& arg2, int& n)
{
- return i2p::i18n::translate(std::forward<TArgs>(args)...);
+ return i2p::i18n::translate(std::forward<TValue>(arg), std::forward<TValue2>(arg2), std::forward<int>(n));
+}
+
+/**
+ * @brief Get translation of string with plural forms and format it
+ * @param arg String with message in singular form
+ * @param arg2 String with message in plural form
+ * @param n Integer, used for selection of form
+ * @param args Array of arguments for string formatting
+ */
+template<typename TValue, typename TValue2, typename... TArgs>
+std::string ntr (TValue&& arg, TValue2&& arg2, int& n, TArgs&&... args)
+{
+ std::string tr_str = i2p::i18n::translate(std::forward<TValue>(arg), std::forward<TValue2>(arg2), std::forward<int>(n));
+
+ size_t size = std::snprintf(NULL, 0, tr_str.c_str(), std::forward<TArgs>(args)...);
+ std::string str(size, 0);
+ std::snprintf(&str.front(), size + 1, tr_str.c_str(), std::forward<TArgs>(args)...);
+
+ return str;
}
#endif // __I18N_H__
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/I18N_langs.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2021-2022, The PurpleI2P Project
+* Copyright (c) 2021-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -9,60 +9,12 @@
#ifndef __I18N_LANGS_H__
#define __I18N_LANGS_H__
+#include "I18N.h"
+
namespace i2p
{
namespace i18n
{
- class Locale
- {
- public:
- Locale (
- const std::string& language,
- const std::map<std::string, std::string>& strings,
- const std::map<std::string, std::vector<std::string>>& plurals,
- std::function<int(int)> formula
- ): m_Language (language), m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { };
-
- // Get activated language name for webconsole
- std::string GetLanguage() const
- {
- return m_Language;
- }
-
- std::string GetString (const std::string& arg) const
- {
- const auto it = m_Strings.find(arg);
- if (it == m_Strings.end())
- {
- return arg;
- }
- else
- {
- return it->second;
- }
- }
-
- std::string GetPlural (const std::string& arg, const std::string& arg2, const int& n) const
- {
- const auto it = m_Plurals.find(arg2);
- if (it == m_Plurals.end()) // not found, fallback to english
- {
- return n == 1 ? arg : arg2;
- }
- else
- {
- int form = m_Formula(n);
- return it->second[form];
- }
- }
-
- private:
- const std::string m_Language;
- const std::map<std::string, std::string> m_Strings;
- const std::map<std::string, std::vector<std::string>> m_Plurals;
- std::function<int(int)> m_Formula;
- };
-
struct langData
{
std::string LocaleName; // localized name
@@ -71,16 +23,23 @@
};
// Add localization here with language name as namespace
- namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
- namespace armenian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
- namespace chinese { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
- namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
- namespace french { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
- namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
- namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
- namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
- namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
- namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace armenian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace chinese { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace czech { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace french { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace italian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace polish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace portuguese { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace spanish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace swedish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace turkish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
+ namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
/**
* That map contains international language name lower-case, name in it's language and it's code
@@ -88,14 +47,21 @@
static std::map<std::string, langData> languages
{
{ "afrikaans", {"Afrikaans", "af", i2p::i18n::afrikaans::GetLocale} },
- { "armenian", {"հայերէն", "hy", i2p::i18n::armenian::GetLocale} },
+ { "armenian", {"hայերէն", "hy", i2p::i18n::armenian::GetLocale} },
{ "chinese", {"简体字", "zh-CN", i2p::i18n::chinese::GetLocale} },
+ { "czech", {"čeština", "cs", i2p::i18n::czech::GetLocale} },
{ "english", {"English", "en", i2p::i18n::english::GetLocale} },
{ "french", {"Français", "fr", i2p::i18n::french::GetLocale} },
{ "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} },
- { "russian", {"русский язык", "ru", i2p::i18n::russian::GetLocale} },
- { "turkmen", {"türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} },
- { "ukrainian", {"украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale} },
+ { "italian", {"Italiano", "it", i2p::i18n::italian::GetLocale} },
+ { "polish", {"Polski", "pl", i2p::i18n::polish::GetLocale} },
+ { "portuguese", {"Português", "pt", i2p::i18n::portuguese::GetLocale} },
+ { "russian", {"Русский язык", "ru", i2p::i18n::russian::GetLocale} },
+ { "spanish", {"Español", "es", i2p::i18n::spanish::GetLocale} },
+ { "swedish", {"Svenska", "sv", i2p::i18n::swedish::GetLocale} },
+ { "turkish", {"Türk dili", "tr", i2p::i18n::turkish::GetLocale} },
+ { "turkmen", {"Türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} },
+ { "ukrainian", {"Украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale} },
{ "uzbek", {"Oʻzbek", "uz", i2p::i18n::uzbek::GetLocale} },
};
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Italian.cpp
^
|
@@ -0,0 +1,223 @@
+/*
+* Copyright (c) 2022-2023, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*/
+
+#include <map>
+#include <vector>
+#include <string>
+#include <memory>
+#include "I18N.h"
+
+// Italian localization file
+
+namespace i2p
+{
+namespace i18n
+{
+namespace italian // language namespace
+{
+ // language name in lowercase
+ static std::string language = "italian";
+
+ // See for language plural forms here:
+ // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
+ static int plural (int n) {
+ return n != 1 ? 1 : 0;
+ }
+
+ static std::map<std::string, std::string> strings
+ {
+ {"%.2f KiB", "%.2f KiB"},
+ {"%.2f MiB", "%.2f MiB"},
+ {"%.2f GiB", "%.2f GiB"},
+ {"building", "in costruzione"},
+ {"failed", "fallito"},
+ {"expiring", "in scadenza"},
+ {"established", "stabilita"},
+ {"unknown", "sconosciuto"},
+ {"exploratory", "esplorativo"},
+ {"Purple I2P Webconsole", "Terminale web Purple I2P"},
+ {"<b>i2pd</b> webconsole", "Terminal web <b>i2pd</b>"},
+ {"Main page", "Pagina principale"},
+ {"Router commands", "Comandi router"},
+ {"Local Destinations", "Destinazioni locali"},
+ {"LeaseSets", "LeaseSets"},
+ {"Tunnels", "Tunnel"},
+ {"Transit Tunnels", "Tunnel di transito"},
+ {"Transports", "Trasporti"},
+ {"I2P tunnels", "Tunnel I2P"},
+ {"SAM sessions", "Sessioni SAM"},
+ {"ERROR", "ERRORE"},
+ {"OK", "OK"},
+ {"Testing", "Testando"},
+ {"Firewalled", "Protetto da firewall"},
+ {"Unknown", "Sconosciuto"},
+ {"Proxy", "Proxy"},
+ {"Mesh", "Mesh"},
+ {"Clock skew", "Orologio disallineato"},
+ {"Offline", "Disconnesso"},
+ {"Symmetric NAT", "NAT simmetrico"},
+ {"Full cone NAT", "Cono completo NAT"},
+ {"No Descriptors", "Nessun descrittore"},
+ {"Uptime", "In funzione da"},
+ {"Network status", "Stato della rete"},
+ {"Network status v6", "Stato della rete v6"},
+ {"Stopping in", "Arresto in"},
+ {"Family", "Famiglia"},
+ {"Tunnel creation success rate", "Percentuale di tunnel creati con successo"},
+ {"Total tunnel creation success rate", "Percentuale di successo totale nella creazione del tunnel"},
+ {"Received", "Ricevuti"},
+ {"%.2f KiB/s", "%.2f KiB/s"},
+ {"Sent", "Inviati"},
+ {"Transit", "Transitati"},
+ {"Data path", "Percorso dati"},
+ {"Hidden content. Press on text to see.", "Contenuto nascosto. Premi sul testo per vedere."},
+ {"Router Ident", "Identificativo del router"},
+ {"Router Family", "Famiglia del router"},
+ {"Router Caps", "Limiti del router"},
+ {"Version", "Versione"},
+ {"Our external address", "Il nostro indirizzo esterno"},
+ {"supported", "supportato"},
+ {"Routers", "Router"},
+ {"Floodfills", "Floodfill"},
+ {"Client Tunnels", "Tunnel client"},
+ {"Services", "Servizi"},
+ {"Enabled", "Abilitato"},
+ {"Disabled", "Disabilitato"},
+ {"Encrypted B33 address", "Indirizzo criptato B33"},
+ {"Address registration line", "Linea di registrazione indirizzo"},
+ {"Domain", "Dominio"},
+ {"Generate", "Genera"},
+ {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Nota:</b> la stringa risultante può essere utilizzata solo per registrare domini 2LD (example.i2p). Per registrare i sottodomini, si prega di utilizzare i2pd-tools."},
+ {"Address", "Indirizzo"},
+ {"Type", "Tipologia"},
+ {"EncType", "Tipo di crittografia"},
+ {"Expire LeaseSet", "Scadenza LeaseSet"},
+ {"Inbound tunnels", "Tunnel in entrata"},
+ {"%dms", "%dms"},
+ {"Outbound tunnels", "Tunnel in uscita"},
+ {"Tags", "Tag"},
+ {"Incoming", "In entrata"},
+ {"Outgoing", "In uscita"},
+ {"Destination", "Destinazione"},
+ {"Amount", "Quantità"},
+ {"Incoming Tags", "Tag in entrata"},
+ {"Tags sessions", "Sessioni dei tag"},
+ {"Status", "Stato"},
+ {"Local Destination", "Destinazione locale"},
+ {"Streams", "Flussi"},
+ {"Close stream", "Interrompi il flusso"},
+ {"Such destination is not found", "Questa destinazione non è stata trovata"},
+ {"I2CP session not found", "Sessione I2CP non trovata"},
+ {"I2CP is not enabled", "I2CP non è abilitato"},
+ {"Invalid", "Invalido"},
+ {"Store type", "Tipologia di archivio"},
+ {"Expires", "Scade"},
+ {"Non Expired Leases", "Lease non scaduti"},
+ {"Gateway", "Gateway"},
+ {"TunnelID", "TunnelID"},
+ {"EndDate", "Data di fine"},
+ {"floodfill mode is disabled", "la modalità floodfill è disabilitata"},
+ {"Queue size", "Dimensione della coda"},
+ {"Run peer test", "Esegui il test dei peer"},
+ {"Reload tunnels configuration", "Ricarica la configurazione dei tunnel"},
+ {"Decline transit tunnels", "Rifiuta tunnel di transito"},
+ {"Accept transit tunnels", "Accetta tunnel di transito"},
+ {"Cancel graceful shutdown", "Annulla l'interruzione controllata"},
+ {"Start graceful shutdown", "Avvia l'interruzione controllata"},
+ {"Force shutdown", "Forza l'arresto"},
+ {"Reload external CSS styles", "Ricarica gli stili CSS esterni"},
+ {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Nota:</b> qualsiasi azione effettuata qui non è persistente e non modifica i file di configurazione."},
+ {"Logging level", "Livello di log"},
+ {"Transit tunnels limit", "Limite di tunnel di transito"},
+ {"Change", "Modifica"},
+ {"Change language", "Modifica linguaggio"},
+ {"no transit tunnels currently built", "Attualmente non ci sono tunnel di transito instaurati"},
+ {"SAM disabled", "SAM disabilitato"},
+ {"no sessions currently running", "Attualmente non ci sono sessioni attive"},
+ {"SAM session not found", "Sessione SAM non trovata"},
+ {"SAM Session", "Sessione SAM"},
+ {"Server Tunnels", "Tunnel server"},
+ {"Client Forwards", "Client di inoltro"},
+ {"Server Forwards", "Server di inoltro"},
+ {"Unknown page", "Pagina sconosciuta"},
+ {"Invalid token", "Token non valido"},
+ {"SUCCESS", "SUCCESSO"},
+ {"Stream closed", "Flusso terminato"},
+ {"Stream not found or already was closed", "Il flusso non è stato trovato oppure è già stato terminato"},
+ {"Destination not found", "Destinazione non trovata"},
+ {"StreamID can't be null", "Lo StreamID non può essere null"},
+ {"Return to destination page", "Ritorna alla pagina di destinazione"},
+ {"You will be redirected in %d seconds", "Sarai reindirizzato tra %d secondi"},
+ {"LeaseSet expiration time updated", "Tempo di scadenza LeaseSet aggiornato"},
+ {"LeaseSet is not found or already expired", "LeaseSet non trovato o già scaduto"},
+ {"Transit tunnels count must not exceed %d", "Il conteggio dei tunnel di transito non deve superare %d"},
+ {"Back to commands list", "Ritorna alla lista dei comandi"},
+ {"Register at reg.i2p", "Registra a reg.i2p"},
+ {"Description", "Descrizione"},
+ {"A bit information about service on domain", "Alcune informazioni riguardo il servizio sul dominio"},
+ {"Submit", "Invia"},
+ {"Domain can't end with .b32.i2p", "I domini non possono terminare con .b32.i2p"},
+ {"Domain must end with .i2p", "I domini devono terminare con .i2p"},
+ {"Unknown command", "Comando sconosciuto"},
+ {"Command accepted", "Comando accettato"},
+ {"Proxy error", "Errore del proxy"},
+ {"Proxy info", "Informazioni del proxy"},
+ {"Proxy error: Host not found", "Errore del proxy: Host non trovato"},
+ {"Remote host not found in router's addressbook", "L'host remoto non è stato trovato nella rubrica del router"},
+ {"You may try to find this host on jump services below", "Si può provare a trovare questo host sui servizi di salto qui sotto"},
+ {"Invalid request", "Richiesta non valida"},
+ {"Proxy unable to parse your request", "Il proxy non è in grado di elaborare la tua richiesta"},
+ {"Addresshelper is not supported", "Addresshelper non è supportato"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'host %s è <font color=red>già nella rubrica del router</font>. <b>Attenzione: la fonte di questo URL potrebbe essere dannosa!</b> Fai clic qui per aggiornare il record: <a href=\"%s%s%s&update=true\">Continua</a>."},
+ {"Addresshelper forced update rejected", "Aggiornamento forzato dell'helper degli indirizzi rifiutato"},
+ {"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Per aggiungere host <b>%s</b> nella rubrica del router, clicca qui: <a href=\"%s%s%s\">Continua</a>."},
+ {"Addresshelper request", "Richiesta di indirizzo helper"},
+ {"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "L'host %s viene aggiunto alla rubrica del router dall'helper. Fai clic qui per procedere: <a href=\"%s\">Continua</a>."},
+ {"Addresshelper adding", "Aggiunta di Addresshelper"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'host %s è <font color=red>già nella rubrica del router</font>. Clicca qui per aggiornare il record: <a href=\"%s%s%s&update=true\">Continua</a>."},
+ {"Addresshelper update", "Aggiornamento dell'helper degli indirizzi"},
+ {"Invalid request URI", "URI della richiesta non valido"},
+ {"Can't detect destination host from request", "Impossibile determinare l'host di destinazione dalla richiesta"},
+ {"Outproxy failure", "Fallimento del proxy di uscita"},
+ {"Bad outproxy settings", "Impostazioni errate del proxy di uscita"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "Host %s non all'interno della rete I2P, ma il proxy di uscita non è abilitato"},
+ {"Unknown outproxy URL", "URL del proxy di uscita sconosciuto"},
+ {"Cannot resolve upstream proxy", "Impossibile identificare il flusso a monte del proxy"},
+ {"Hostname is too long", "Il nome dell'host è troppo lungo"},
+ {"Cannot connect to upstream SOCKS proxy", "Impossibile connettersi al flusso a monte del proxy SOCKS"},
+ {"Cannot negotiate with SOCKS proxy", "Impossibile negoziare con il proxy SOCKS"},
+ {"CONNECT error", "Errore di connessione"},
+ {"Failed to connect", "Connessione fallita"},
+ {"SOCKS proxy error", "Errore del proxy SOCKS"},
+ {"Failed to send request to upstream", "Invio della richiesta a monte non riuscito"},
+ {"No reply from SOCKS proxy", "Nessuna risposta dal proxy SOCKS"},
+ {"Cannot connect", "Impossibile connettersi"},
+ {"HTTP out proxy not implemented", "Proxy HTTP di uscita non implementato"},
+ {"Cannot connect to upstream HTTP proxy", "Impossibile connettersi al flusso a monte del proxy HTTP"},
+ {"Host is down", "L'host è offline"},
+ {"Can't create connection to requested host, it may be down. Please try again later.", "Impossibile creare la connessione all'host richiesto, probabilmente è offline. Riprova più tardi."},
+ {"", ""},
+ };
+
+ static std::map<std::string, std::vector<std::string>> plurals
+ {
+ {"%d days", {"%d giorno", "%d giorni"}},
+ {"%d hours", {"%d ora", "%d ore"}},
+ {"%d minutes", {"%d minuto", "%d minuti"}},
+ {"%d seconds", {"%d secondo", "%d secondi"}},
+ {"", {"", ""}},
+ };
+
+ std::shared_ptr<const i2p::i18n::Locale> GetLocale()
+ {
+ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
+ }
+
+} // language
+} // i18n
+} // i2p
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Polish.cpp
^
|
@@ -0,0 +1,59 @@
+/*
+* Copyright (c) 2023, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*/
+
+#include <map>
+#include <vector>
+#include <string>
+#include <memory>
+#include "I18N.h"
+
+// Polish localization file
+
+namespace i2p
+{
+namespace i18n
+{
+namespace polish // language namespace
+{
+ // language name in lowercase
+ static std::string language = "polish";
+
+ // See for language plural forms here:
+ // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
+ static int plural (int n) {
+ return (n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
+ }
+
+ static std::map<std::string, std::string> strings
+ {
+ {"building", "Kompilowanie"},
+ {"failed", "nieudane"},
+ {"expiring", "wygasający"},
+ {"established", "ustanowiony"},
+ {"Main page", "Strona główna"},
+ {"Router commands", "Komendy routera"},
+ {"Tunnels", "Tunele"},
+ {"OK", "Ok"},
+ {"Uptime", "Czas pracy"},
+ {"Sent", "Wysłane"},
+ {"", ""},
+ };
+
+ static std::map<std::string, std::vector<std::string>> plurals
+ {
+ {"", {"", "", ""}},
+ };
+
+ std::shared_ptr<const i2p::i18n::Locale> GetLocale()
+ {
+ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
+ }
+
+} // language
+} // i18n
+} // i2p
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Portuguese.cpp
^
|
@@ -0,0 +1,223 @@
+/*
+* Copyright (c) 2023, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*/
+
+#include <map>
+#include <vector>
+#include <string>
+#include <memory>
+#include "I18N.h"
+
+// Portuguese localization file
+
+namespace i2p
+{
+namespace i18n
+{
+namespace portuguese // language namespace
+{
+ // language name in lowercase
+ static std::string language = "portuguese";
+
+ // See for language plural forms here:
+ // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
+ static int plural (int n) {
+ return n != 1 ? 1 : 0;
+ }
+
+ static std::map<std::string, std::string> strings
+ {
+ {"%.2f KiB", "%.2f KiB"},
+ {"%.2f MiB", "%.2f MiB"},
+ {"%.2f GiB", "%.2f GiB"},
+ {"building", "construindo"},
+ {"failed", "falhou"},
+ {"expiring", "expirando"},
+ {"established", "estabelecido"},
+ {"unknown", "desconhecido"},
+ {"exploratory", "exploratório"},
+ {"Purple I2P Webconsole", "Webconsole Purple I2P"},
+ {"<b>i2pd</b> webconsole", "webconsole <b>i2pd</b>"},
+ {"Main page", "Página Principal"},
+ {"Router commands", "Comandos do Roteador"},
+ {"Local Destinations", "Destinos Locais"},
+ {"LeaseSets", "LeaseSets"},
+ {"Tunnels", "Túneis"},
+ {"Transit Tunnels", "Túneis de Trânsito"},
+ {"Transports", "Transportes"},
+ {"I2P tunnels", "Túneis I2P"},
+ {"SAM sessions", "Sessões do SAM"},
+ {"ERROR", "ERRO"},
+ {"OK", "OK"},
+ {"Testing", "Testando"},
+ {"Firewalled", "Sob Firewall"},
+ {"Unknown", "Desconhecido"},
+ {"Proxy", "Proxy"},
+ {"Mesh", "Malha"},
+ {"Clock skew", "Defasagem do Relógio"},
+ {"Offline", "Desligado"},
+ {"Symmetric NAT", "NAT Simétrico"},
+ {"Full cone NAT", "Full cone NAT"},
+ {"No Descriptors", "Sem Descritores"},
+ {"Uptime", "Tempo Ativo"},
+ {"Network status", "Estado da rede"},
+ {"Network status v6", "Estado da rede v6"},
+ {"Stopping in", "Parando em"},
+ {"Family", "Família"},
+ {"Tunnel creation success rate", "Taxa de sucesso na criação de túneis"},
+ {"Total tunnel creation success rate", "Taxa total de sucesso na criação de túneis"},
+ {"Received", "Recebido"},
+ {"%.2f KiB/s", "%.2f KiB/s"},
+ {"Sent", "Enviado"},
+ {"Transit", "Trânsito"},
+ {"Data path", "Diretório dos dados"},
+ {"Hidden content. Press on text to see.", "Conteúdo oculto. Clique no texto para revelar."},
+ {"Router Ident", "Identidade do Roteador"},
+ {"Router Family", "Família do Roteador"},
+ {"Router Caps", "Limites do Roteador"},
+ {"Version", "Versão"},
+ {"Our external address", "Nosso endereço externo"},
+ {"supported", "suportado"},
+ {"Routers", "Roteadores"},
+ {"Floodfills", "Modo Inundação"},
+ {"Client Tunnels", "Túneis de Clientes"},
+ {"Services", "Serviços"},
+ {"Enabled", "Ativado"},
+ {"Disabled", "Desativado"},
+ {"Encrypted B33 address", "Endereço B33 criptografado"},
+ {"Address registration line", "Linha de cadastro de endereço"},
+ {"Domain", "Domínio"},
+ {"Generate", "Gerar"},
+ {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b> Nota: </b>A string resultante só pode ser usada para registrar domínios 2LD (exemplo.i2p). Para registrar subdomínios por favor utilize o i2pd-tools."},
+ {"Address", "Endereço"},
+ {"Type", "Tipo"},
+ {"EncType", "Tipo de Criptografia"},
+ {"Expire LeaseSet", "Expirar LeaseSet"},
+ {"Inbound tunnels", "Túneis de Entrada"},
+ {"%dms", "%dms"},
+ {"Outbound tunnels", "Túneis de Saída"},
+ {"Tags", "Etiquetas"},
+ {"Incoming", "Entradas"},
+ {"Outgoing", "Saídas"},
+ {"Destination", "Destinos"},
+ {"Amount", "Quantidade"},
+ {"Incoming Tags", "Etiquetas de Entrada"},
+ {"Tags sessions", "Sessões de etiquetas"},
+ {"Status", "Estado"},
+ {"Local Destination", "Destinos Locais"},
+ {"Streams", "Fluxos"},
+ {"Close stream", "Fechar fluxo"},
+ {"Such destination is not found", "Tal destino não foi encontrado"},
+ {"I2CP session not found", "Sessão do I2CP não encontrada"},
+ {"I2CP is not enabled", "I2CP não está ativado"},
+ {"Invalid", "Inválido"},
+ {"Store type", "Tipo de armazenamento"},
+ {"Expires", "Expira em"},
+ {"Non Expired Leases", "Sessões não expiradas"},
+ {"Gateway", "Gateway"},
+ {"TunnelID", "TunnelID"},
+ {"EndDate", "Data final"},
+ {"floodfill mode is disabled", "Mode de inundação está desativado"},
+ {"Queue size", "Tamanho da fila"},
+ {"Run peer test", "Executar teste de peers"},
+ {"Reload tunnels configuration", "Recarregar a configuração dos túneis"},
+ {"Decline transit tunnels", "Negar túneis de trânsito"},
+ {"Accept transit tunnels", "Aceitar túneis de trânsito"},
+ {"Cancel graceful shutdown", "Cancelar desligamento gracioso"},
+ {"Start graceful shutdown", "Iniciar desligamento gracioso"},
+ {"Force shutdown", "Forçar desligamento"},
+ {"Reload external CSS styles", "Recarregar estilos CSS externos"},
+ {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b> Nota: </b> Qualquer ação feita aqui não será permanente e não altera os seus arquivos de configuração."},
+ {"Logging level", "Nível de registro"},
+ {"Transit tunnels limit", "Limite de túneis de trânsito"},
+ {"Change", "Mudar"},
+ {"Change language", "Trocar idioma"},
+ {"no transit tunnels currently built", "Nenhum túnel de trânsito construido no momento"},
+ {"SAM disabled", "SAM desativado"},
+ {"no sessions currently running", "Nenhuma sessão funcionando no momento"},
+ {"SAM session not found", "Nenhuma sessão do SAM encontrada"},
+ {"SAM Session", "Sessão do SAM"},
+ {"Server Tunnels", "Túneis de Servidor"},
+ {"Client Forwards", "Túneis de Cliente"},
+ {"Server Forwards", "Encaminhamentos de Servidor"},
+ {"Unknown page", "Página desconhecida"},
+ {"Invalid token", "Token Inválido"},
+ {"SUCCESS", "SUCESSO"},
+ {"Stream closed", "Fluxo fechado"},
+ {"Stream not found or already was closed", "Fluxo não encontrado ou já encerrado"},
+ {"Destination not found", "Destino não encontrado"},
+ {"StreamID can't be null", "StreamID não pode ser nulo"},
+ {"Return to destination page", "Retornar para à página de destino"},
+ {"You will be redirected in %d seconds", "Você será redirecionado em %d segundos"},
+ {"LeaseSet expiration time updated", "Tempo de validade do LeaseSet atualizado"},
+ {"LeaseSet is not found or already expired", "LeaseSet não foi encontrado ou já expirou"},
+ {"Transit tunnels count must not exceed %d", "A contagem de túneis de trânsito não deve exceder %d"},
+ {"Back to commands list", "Voltar para a lista de comandos"},
+ {"Register at reg.i2p", "Registrar na reg.i2p"},
+ {"Description", "Descrição"},
+ {"A bit information about service on domain", "Algumas informações sobre o serviço no domínio"},
+ {"Submit", "Enviar"},
+ {"Domain can't end with .b32.i2p", "O domínio não pode terminar com .b32.i2p"},
+ {"Domain must end with .i2p", "O domínio não pode terminar com .i2p"},
+ {"Unknown command", "Comando desconhecido"},
+ {"Command accepted", "Comando aceito"},
+ {"Proxy error", "Erro no proxy"},
+ {"Proxy info", "Informações do proxy"},
+ {"Proxy error: Host not found", "Erro no proxy: Host não encontrado"},
+ {"Remote host not found in router's addressbook", "O host remoto não foi encontrado no livro de endereços do roteador"},
+ {"You may try to find this host on jump services below", "Você pode tentar encontrar este host nos jump services abaixo"},
+ {"Invalid request", "Requisição inválida"},
+ {"Proxy unable to parse your request", "O proxy foi incapaz de processar a sua requisição"},
+ {"Addresshelper is not supported", "O Auxiliar de Endereços não é suportado"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "O host %s já <font color=red>está no catálogo de endereços do roteador</font>. <b>Cuidado: a fonte desta URL pode ser perigosa!</b> Clique aqui para atualizar o registro: <a href=\"%s%s%s&update=true\">Continuar</a>."},
+ {"Addresshelper forced update rejected", "A atualização forçada do Auxiliar de Endereços foi rejeitada"},
+ {"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Para adicionar o host <b> %s </b> ao catálogo de endereços do roteador, clique aqui: <a href='%s%s%s'>Continuar </a>."},
+ {"Addresshelper request", "Requisição do Auxiliar de Endereços"},
+ {"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "O host %s foi adicionado ao catálogo de endereços do roteador por um auxiliar. Clique aqui para proceder: <a href='%s'> Continuar </a>."},
+ {"Addresshelper adding", "Auxiliar de Endereço adicionando"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "O host %s já <font color=red>está no catálogo de endereços do roteador </font>. Clique aqui para atualizar o registro: <a href=\"%s%s%s&update=true\">Continuar</a>."},
+ {"Addresshelper update", "Atualização do Auxiliar de Endereços"},
+ {"Invalid request URI", "A URI de requisição é inválida"},
+ {"Can't detect destination host from request", "Incapaz de detectar o host de destino da requisição"},
+ {"Outproxy failure", "Falha no outproxy"},
+ {"Bad outproxy settings", "Configurações ruins de outproxy"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "O host %s não está dentro da rede I2P, mas o outproxy não está ativado"},
+ {"Unknown outproxy URL", "URL de outproxy desconhecida"},
+ {"Cannot resolve upstream proxy", "Não é possível resolver o proxy de entrada"},
+ {"Hostname is too long", "O hostname é muito longo"},
+ {"Cannot connect to upstream SOCKS proxy", "Não é possível se conectar ao proxy SOCKS de entrada"},
+ {"Cannot negotiate with SOCKS proxy", "Não é possível negociar com o proxy SOCKS"},
+ {"CONNECT error", "Erro de CONEXÃO"},
+ {"Failed to connect", "Falha ao conectar"},
+ {"SOCKS proxy error", "Erro no proxy SOCKS"},
+ {"Failed to send request to upstream", "Falha ao enviar requisição para o fluxo de entrada"},
+ {"No reply from SOCKS proxy", "Sem resposta do proxy SOCKS"},
+ {"Cannot connect", "Impossível conectar"},
+ {"HTTP out proxy not implemented", "proxy de saída HTTP não implementado"},
+ {"Cannot connect to upstream HTTP proxy", "Não é possível conectar ao proxy HTTP de entrada"},
+ {"Host is down", "Host está desligado"},
+ {"Can't create connection to requested host, it may be down. Please try again later.", "Não é possível se conectar ao host requisitado, talvez ele esteja for do ar. Por favor, tente novamente mais tarde."},
+ {"", ""},
+ };
+
+ static std::map<std::string, std::vector<std::string>> plurals
+ {
+ {"%d days", {"%d Dia", "%d Dias"}},
+ {"%d hours", {"%d hora", "%d horas"}},
+ {"%d minutes", {"%d minuto", "%d minutos"}},
+ {"%d seconds", {"%d Segundo", "%d segundos"}},
+ {"", {"", ""}},
+ };
+
+ std::shared_ptr<const i2p::i18n::Locale> GetLocale()
+ {
+ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
+ }
+
+} // language
+} // i18n
+} // i2p
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Russian.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2021, The PurpleI2P Project
+* Copyright (c) 2021-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -31,15 +31,16 @@
static std::map<std::string, std::string> strings
{
- {"KiB", "КиБ"},
- {"MiB", "МиБ"},
- {"GiB", "ГиБ"},
+ {"%.2f KiB", "%.2f КиБ"},
+ {"%.2f MiB", "%.2f МиБ"},
+ {"%.2f GiB", "%.2f ГиБ"},
{"building", "строится"},
{"failed", "неудачный"},
{"expiring", "истекает"},
{"established", "работает"},
{"unknown", "неизвестно"},
{"exploratory", "исследовательский"},
+ {"Purple I2P Webconsole", "Веб-консоль Purple I2P"},
{"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"},
{"Main page", "Главная"},
{"Router commands", "Команды роутера"},
@@ -57,18 +58,20 @@
{"Unknown", "Неизвестно"},
{"Proxy", "Прокси"},
{"Mesh", "MESH-сеть"},
- {"Error", "Ошибка"},
{"Clock skew", "Не точное время"},
{"Offline", "Оффлайн"},
{"Symmetric NAT", "Симметричный NAT"},
+ {"Full cone NAT", "Full cone NAT"},
+ {"No Descriptors", "Нет дескрипторов"},
{"Uptime", "В сети"},
{"Network status", "Сетевой статус"},
{"Network status v6", "Сетевой статус v6"},
{"Stopping in", "Остановка через"},
{"Family", "Семейство"},
{"Tunnel creation success rate", "Успешно построенных туннелей"},
+ {"Total tunnel creation success rate", "Общий процент успешно построенных туннелей"},
{"Received", "Получено"},
- {"KiB/s", "КиБ/с"},
+ {"%.2f KiB/s", "%.2f КиБ/с"},
{"Sent", "Отправлено"},
{"Transit", "Транзит"},
{"Data path", "Путь к данным"},
@@ -93,8 +96,9 @@
{"Address", "Адрес"},
{"Type", "Тип"},
{"EncType", "ТипШифр"},
+ {"Expire LeaseSet", "Просрочить Лизсет"},
{"Inbound tunnels", "Входящие туннели"},
- {"ms", "мс"},
+ {"%dms", "%dмс"},
{"Outbound tunnels", "Исходящие туннели"},
{"Tags", "Теги"},
{"Incoming", "Входящие"},
@@ -107,6 +111,7 @@
{"Local Destination", "Локальное назначение"},
{"Streams", "Стримы"},
{"Close stream", "Закрыть стрим"},
+ {"Such destination is not found", "Такая точка назначения не найдена"},
{"I2CP session not found", "I2CP сессия не найдена"},
{"I2CP is not enabled", "I2CP не включен"},
{"Invalid", "Некорректный"},
@@ -116,9 +121,10 @@
{"Gateway", "Шлюз"},
{"TunnelID", "ID туннеля"},
{"EndDate", "Заканчивается"},
- {"not floodfill", "не флудфил"},
+ {"floodfill mode is disabled", "режим флудфила отключен"},
{"Queue size", "Размер очереди"},
{"Run peer test", "Запустить тестирование"},
+ {"Reload tunnels configuration", "Перезагрузить конфигурацию туннелей"},
{"Decline transit tunnels", "Отклонять транзитные туннели"},
{"Accept transit tunnels", "Принимать транзитные туннели"},
{"Cancel graceful shutdown", "Отменить плавную остановку"},
@@ -146,8 +152,10 @@
{"Destination not found", "Точка назначения не найдена"},
{"StreamID can't be null", "StreamID не может быть пустым"},
{"Return to destination page", "Вернуться на страницу точки назначения"},
- {"You will be redirected in 5 seconds", "Вы будете переадресованы через 5 секунд"},
- {"Transit tunnels count must not exceed 65535", "Число транзитных туннелей не должно превышать 65535"},
+ {"You will be redirected in %d seconds", "Вы будете переадресованы через %d секунд"},
+ {"LeaseSet expiration time updated", "Время действия LeaseSet обновлено"},
+ {"LeaseSet is not found or already expired", "Лизсет не найден или время действия уже истекло"},
+ {"Transit tunnels count must not exceed %d", "Число транзитных туннелей не должно превышать %d"},
{"Back to commands list", "Вернуться к списку команд"},
{"Register at reg.i2p", "Зарегистрировать на reg.i2p"},
{"Description", "Описание"},
@@ -155,7 +163,6 @@
{"Submit", "Отправить"},
{"Domain can't end with .b32.i2p", "Домен не может заканчиваться на .b32.i2p"},
{"Domain must end with .i2p", "Домен должен заканчиваться на .i2p"},
- {"Such destination is not found", "Такая точка назначения не найдена"},
{"Unknown command", "Неизвестная команда"},
{"Command accepted", "Команда принята"},
{"Proxy error", "Ошибка прокси"},
@@ -165,32 +172,33 @@
{"You may try to find this host on jump services below", "Вы можете попробовать найти узел через джамп сервисы ниже"},
{"Invalid request", "Некорректный запрос"},
{"Proxy unable to parse your request", "Прокси не может разобрать ваш запрос"},
- {"addresshelper is not supported", "addresshelper не поддерживается"},
- {"Host", "Узел"},
- {"added to router's addressbook from helper", "добавлен в адресную книгу роутера через хелпер"},
- {"Click here to proceed:", "Нажмите здесь, чтобы продолжить:"},
- {"Continue", "Продолжить"},
- {"Addresshelper found", "Найден addresshelper"},
- {"already in router's addressbook", "уже в адресной книге роутера"},
- {"Click here to update record:", "Нажмите здесь, чтобы обновить запись:"},
- {"invalid request uri", "некорректный URI запроса"},
+ {"Addresshelper is not supported", "Addresshelper не поддерживается"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Узел %s <font color=red>уже в адресной книге роутера</font>. <b>Будьте осторожны: источник данной ссылки может быть вредоносным!</b> Нажмите здесь, чтобы обновить запись: <a href=\"%s%s%s&update=true\">Продолжить</a>."},
+ {"Addresshelper forced update rejected", "Принудительное обновление через Addresshelper отклонено"},
+ {"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Чтобы добавить узел <b>%s</b> в адресную книгу роутера, нажмите здесь: <a href=\"%s%s%s\">Продолжить</a>."},
+ {"Addresshelper request", "Запрос добавления Addresshelper"},
+ {"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Узел %s добавлен в адресную книгу роутера через хелпер. Нажмите здесь, чтобы продолжить: <a href=\"%s\">Продолжить</a>."},
+ {"Addresshelper adding", "Добавление Addresshelper"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Узел %s <font color=red>уже в адресной книге роутера</font>. Нажмите здесь, чтобы обновить запись: <a href=\"%s%s%s&update=true\">Продолжить</a>."},
+ {"Addresshelper update", "Обновление записи через Addresshelper"},
+ {"Invalid request URI", "Некорректный URI запроса"},
{"Can't detect destination host from request", "Не удалось определить адрес назначения из запроса"},
{"Outproxy failure", "Ошибка внешнего прокси"},
- {"bad outproxy settings", "некорректные настройки внешнего прокси"},
- {"not inside I2P network, but outproxy is not enabled", "не в I2P сети, но внешний прокси не включен"},
- {"unknown outproxy url", "неизвестный URL внешнего прокси"},
- {"cannot resolve upstream proxy", "не удается определить вышестоящий прокси"},
- {"hostname too long", "имя хоста слишком длинное"},
- {"cannot connect to upstream socks proxy", "не удается подключиться к вышестоящему SOCKS прокси"},
- {"Cannot negotiate with socks proxy", "Не удается договориться с вышестоящим SOCKS прокси"},
+ {"Bad outproxy settings", "Некорректные настройки внешнего прокси"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "Узел %s не в I2P сети, но внешний прокси не включен"},
+ {"Unknown outproxy URL", "Неизвестный URL внешнего прокси"},
+ {"Cannot resolve upstream proxy", "Не удается определить вышестоящий прокси"},
+ {"Hostname is too long", "Имя хоста слишком длинное"},
+ {"Cannot connect to upstream SOCKS proxy", "Не удалось подключиться к вышестоящему SOCKS прокси серверу"},
+ {"Cannot negotiate with SOCKS proxy", "Не удается договориться с вышестоящим SOCKS прокси"},
{"CONNECT error", "Ошибка CONNECT запроса"},
- {"Failed to Connect", "Не удалось подключиться"},
- {"socks proxy error", "ошибка SOCKS прокси"},
- {"failed to send request to upstream", "не удалось отправить запрос вышестоящему прокси"},
- {"No Reply From socks proxy", "Нет ответа от SOCKS прокси сервера"},
- {"cannot connect", "не удалось подключиться"},
- {"http out proxy not implemented", "поддержка внешнего HTTP прокси сервера не реализована"},
- {"cannot connect to upstream http proxy", "не удалось подключиться к вышестоящему HTTP прокси серверу"},
+ {"Failed to connect", "Не удалось соединиться"},
+ {"SOCKS proxy error", "Ошибка SOCKS прокси"},
+ {"Failed to send request to upstream", "Не удалось отправить запрос вышестоящему прокси серверу"},
+ {"No reply from SOCKS proxy", "Нет ответа от SOCKS прокси сервера"},
+ {"Cannot connect", "Не удалось подключиться"},
+ {"HTTP out proxy not implemented", "Поддержка внешнего HTTP прокси сервера не реализована"},
+ {"Cannot connect to upstream HTTP proxy", "Не удалось подключиться к вышестоящему HTTP прокси серверу"},
{"Host is down", "Узел недоступен"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Не удалось установить соединение к запрошенному узлу, возможно он не в сети. Попробуйте повторить запрос позже."},
{"", ""},
@@ -198,10 +206,10 @@
static std::map<std::string, std::vector<std::string>> plurals
{
- {"days", {"день", "дня", "дней"}},
- {"hours", {"час", "часа", "часов"}},
- {"minutes", {"минуту", "минуты", "минут"}},
- {"seconds", {"секунду", "секунды", "секунд"}},
+ {"%d days", {"%d день", "%d дня", "%d дней"}},
+ {"%d hours", {"%d час", "%d часа", "%d часов"}},
+ {"%d minutes", {"%d минуту", "%d минуты", "%d минут"}},
+ {"%d seconds", {"%d секунду", "%d секунды", "%d секунд"}},
{"", {"", "", ""}},
};
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Spanish.cpp
^
|
@@ -0,0 +1,204 @@
+/*
+* Copyright (c) 2022-2023, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*/
+
+#include <map>
+#include <vector>
+#include <string>
+#include <memory>
+#include "I18N.h"
+
+// Spanish localization file
+
+namespace i2p
+{
+namespace i18n
+{
+namespace spanish // language namespace
+{
+ // language name in lowercase
+ static std::string language = "spanish";
+
+ // See for language plural forms here:
+ // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
+ static int plural (int n) {
+ return n != 1 ? 1 : 0;
+ }
+
+ static std::map<std::string, std::string> strings
+ {
+ {"%.2f KiB", "%.2f KiB"},
+ {"%.2f MiB", "%.2f MiB"},
+ {"%.2f GiB", "%.2f GiB"},
+ {"building", "pendiente"},
+ {"failed", "fallido"},
+ {"expiring", "expiró"},
+ {"established", "establecido"},
+ {"unknown", "desconocido"},
+ {"exploratory", "exploratorio"},
+ {"Purple I2P Webconsole", "Consola web de Purple I2P"},
+ {"<b>i2pd</b> webconsole", "Consola web de <b>i2pd</b>"},
+ {"Main page", "Inicio"},
+ {"Router commands", "Comandos de enrutador"},
+ {"Local Destinations", "Destinos locales"},
+ {"LeaseSets", "LeaseSets"},
+ {"Tunnels", "Túneles"},
+ {"Transit Tunnels", "Túneles de Tránsito"},
+ {"Transports", "Transportes"},
+ {"I2P tunnels", "Túneles I2P"},
+ {"SAM sessions", "Sesiones SAM"},
+ {"ERROR", "ERROR"},
+ {"OK", "VALE"},
+ {"Testing", "Probando"},
+ {"Firewalled", "Con cortafuegos"},
+ {"Unknown", "Desconocido"},
+ {"Proxy", "Proxy"},
+ {"Mesh", "Malla"},
+ {"Clock skew", "Reloj desfasado"},
+ {"Offline", "Desconectado"},
+ {"Symmetric NAT", "NAT simétrico"},
+ {"Uptime", "Tiempo en línea"},
+ {"Network status", "Estado de red"},
+ {"Network status v6", "Estado de red v6"},
+ {"Stopping in", "Parando en"},
+ {"Family", "Familia"},
+ {"Tunnel creation success rate", "Tasa de éxito de creación de túneles"},
+ {"Received", "Recibido"},
+ {"%.2f KiB/s", "%.2f KiB/s"},
+ {"Sent", "Enviado"},
+ {"Transit", "Tránsito"},
+ {"Data path", "Ruta de datos"},
+ {"Hidden content. Press on text to see.", "Contenido oculto. Presione para ver."},
+ {"Router Ident", "Ident del Enrutador"},
+ {"Router Family", "Familia de enrutador"},
+ {"Router Caps", "Atributos del Enrutador"},
+ {"Version", "Versión"},
+ {"Our external address", "Nuestra dirección externa"},
+ {"supported", "soportado"},
+ {"Routers", "Enrutadores"},
+ {"Floodfills", "Inundaciones"},
+ {"Client Tunnels", "Túneles de cliente"},
+ {"Services", "Servicios"},
+ {"Enabled", "Activado"},
+ {"Disabled", "Desactivado"},
+ {"Encrypted B33 address", "Dirección encriptada B33"},
+ {"Address registration line", "Línea para registrar direcciones"},
+ {"Domain", "Dominio"},
+ {"Generate", "Generar"},
+ {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Nota:</b> la cadena resultante solo se puede usar para registrar dominios 2LD (ejemplo.i2p). Para registrar subdominios, por favor utilice i2pd-tools."},
+ {"Address", "Dirección"},
+ {"Type", "Tipo"},
+ {"EncType", "TipoEncrip"},
+ {"Inbound tunnels", "Túneles entrantes"},
+ {"%dms", "%dms"},
+ {"Outbound tunnels", "Túneles salientes"},
+ {"Tags", "Etiquetas"},
+ {"Incoming", "Entrante"},
+ {"Outgoing", "Saliente"},
+ {"Destination", "Destino"},
+ {"Amount", "Cantidad"},
+ {"Incoming Tags", "Etiquetas entrantes"},
+ {"Tags sessions", "Sesiones de etiquetas"},
+ {"Status", "Estado"},
+ {"Local Destination", "Destino Local"},
+ {"Streams", "Flujos"},
+ {"Close stream", "Cerrar flujo"},
+ {"I2CP session not found", "Sesión I2CP no encontrada"},
+ {"I2CP is not enabled", "I2CP no está activado"},
+ {"Invalid", "Inválido"},
+ {"Store type", "Tipo de almacenamiento"},
+ {"Expires", "Caduca"},
+ {"Non Expired Leases", "Sesiones No Expiradas"},
+ {"Gateway", "Puerta de enlace"},
+ {"TunnelID", "TunnelID"},
+ {"EndDate", "FechaVenc"},
+ {"Queue size", "Tamaño de cola"},
+ {"Run peer test", "Ejecutar prueba de par"},
+ {"Decline transit tunnels", "Rechazar túneles de tránsito"},
+ {"Accept transit tunnels", "Aceptar túneles de tránsito"},
+ {"Cancel graceful shutdown", "Cancelar apagado con gracia"},
+ {"Start graceful shutdown", "Iniciar apagado con gracia"},
+ {"Force shutdown", "Forzar apagado"},
+ {"Reload external CSS styles", "Recargar estilos CSS externos"},
+ {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Nota:</b> cualquier acción hecha aquí no es persistente y no cambia tus archivos de configuración."},
+ {"Logging level", "Nivel de registro de errores"},
+ {"Transit tunnels limit", "Límite de túneles de tránsito"},
+ {"Change", "Cambiar"},
+ {"Change language", "Cambiar idioma"},
+ {"no transit tunnels currently built", "no hay túneles de tránsito actualmente construidos"},
+ {"SAM disabled", "SAM desactivado"},
+ {"no sessions currently running", "no hay sesiones ejecutándose ahora"},
+ {"SAM session not found", "Sesión SAM no encontrada"},
+ {"SAM Session", "Sesión SAM"},
+ {"Server Tunnels", "Túneles de Servidor"},
+ {"Client Forwards", "Redirecciones de Cliente"},
+ {"Server Forwards", "Redirecciones de Servidor"},
+ {"Unknown page", "Página desconocida"},
+ {"Invalid token", "Token inválido"},
+ {"SUCCESS", "ÉXITO"},
+ {"Stream closed", "Transmisión cerrada"},
+ {"Stream not found or already was closed", "No se encontró la transmisión o ya se cerró"},
+ {"Destination not found", "Destino no encontrado"},
+ {"StreamID can't be null", "StreamID no puede ser nulo"},
+ {"Return to destination page", "Volver a la página de destino"},
+ {"Back to commands list", "Volver a lista de comandos"},
+ {"Register at reg.i2p", "Registrar en reg.i2p"},
+ {"Description", "Descripción"},
+ {"A bit information about service on domain", "Un poco de información sobre el servicio en el dominio"},
+ {"Submit", "Enviar"},
+ {"Domain can't end with .b32.i2p", "El dominio no puede terminar con .b32.i2p"},
+ {"Domain must end with .i2p", "El dominio debe terminar con .i2p"},
+ {"Such destination is not found", "No se encontró el destino"},
+ {"Unknown command", "Comando desconocido"},
+ {"Command accepted", "Comando aceptado"},
+ {"Proxy error", "Error de proxy"},
+ {"Proxy info", "Información del proxy"},
+ {"Proxy error: Host not found", "Error de proxy: Host no encontrado"},
+ {"Remote host not found in router's addressbook", "Servidor remoto no encontrado en la libreta de direcciones del enrutador"},
+ {"You may try to find this host on jump services below", "Puede intentar encontrar este dominio en los siguientes servicios de salto"},
+ {"Invalid request", "Solicitud inválida"},
+ {"Proxy unable to parse your request", "Proxy no puede procesar su solicitud"},
+ {"Invalid request URI", "URI de solicitud inválida"},
+ {"Can't detect destination host from request", "No se puede detectar el host de destino de la solicitud"},
+ {"Outproxy failure", "Fallo en el proxy saliente"},
+ {"Bad outproxy settings", "Configuración de outproxy incorrecta"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "Dominio %s no está dentro de la red I2P, pero el proxy de salida no está activado"},
+ {"Unknown outproxy URL", "URL de proxy outproxy desconocido"},
+ {"Cannot resolve upstream proxy", "No se puede resolver el proxy de upstream"},
+ {"Hostname is too long", "Nombre de dominio muy largo"},
+ {"Cannot connect to upstream SOCKS proxy", "No se puede conectar al proxy SOCKS principal"},
+ {"Cannot negotiate with SOCKS proxy", "No se puede negociar con el proxy SOCKS"},
+ {"CONNECT error", "Error de CONNECT"},
+ {"Failed to connect", "Error al conectar"},
+ {"SOCKS proxy error", "Error de proxy SOCKS"},
+ {"Failed to send request to upstream", "No se pudo enviar petición al principal"},
+ {"No reply from SOCKS proxy", "Sin respuesta del proxy SOCKS"},
+ {"Cannot connect", "No se puede conectar"},
+ {"HTTP out proxy not implemented", "Proxy externo HTTP no implementado"},
+ {"Cannot connect to upstream HTTP proxy", "No se puede conectar al proxy HTTP principal"},
+ {"Host is down", "Servidor caído"},
+ {"Can't create connection to requested host, it may be down. Please try again later.", "No se puede crear la conexión al servidor solicitado, puede estar caído. Intente de nuevo más tarde."},
+ {"", ""},
+ };
+
+ static std::map<std::string, std::vector<std::string>> plurals
+ {
+ {"%d days", {"%d día", "%d días"}},
+ {"%d hours", {"%d hora", "%d horas"}},
+ {"%d minutes", {"%d minuto", "%d minutos"}},
+ {"%d seconds", {"%d segundo", "%d segundos"}},
+ {"", {"", ""}},
+ };
+
+ std::shared_ptr<const i2p::i18n::Locale> GetLocale()
+ {
+ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
+ }
+
+} // language
+} // i18n
+} // i2p
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Swedish.cpp
^
|
@@ -0,0 +1,220 @@
+/*
+* Copyright (c) 2023, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*/
+
+#include <map>
+#include <vector>
+#include <string>
+#include <memory>
+#include "I18N.h"
+
+// Swedish localization file
+
+namespace i2p
+{
+namespace i18n
+{
+namespace swedish // language namespace
+{
+ // language name in lowercase
+ static std::string language = "swedish";
+
+ // See for language plural forms here:
+ // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
+ static int plural (int n) {
+ return n != 1 ? 1 : 0;
+ }
+
+ static std::map<std::string, std::string> strings
+ {
+ {"%.2f KiB", "%.2f KiB"},
+ {"%.2f MiB", "%.2f MiB"},
+ {"%.2f GiB", "%.2f GiB"},
+ {"building", "bygger"},
+ {"failed", "misslyckad"},
+ {"expiring", "utgår"},
+ {"established", "upprättad"},
+ {"unknown", "okänt"},
+ {"exploratory", "utforskande"},
+ {"Purple I2P Webconsole", "Purple I2P Webbkonsoll"},
+ {"<b>i2pd</b> webconsole", "<b>i2pd</b>-Webbkonsoll"},
+ {"Main page", "Huvudsida"},
+ {"Router commands", "Routerkommandon"},
+ {"Local Destinations", "Lokala Platser"},
+ {"LeaseSets", "Hyresuppsättningar"},
+ {"Tunnels", "Tunnlar"},
+ {"Transit Tunnels", "Förmedlande Tunnlar"},
+ {"Transports", "Transporter"},
+ {"I2P tunnels", "I2P-tunnlar"},
+ {"SAM sessions", "SAM-perioder"},
+ {"ERROR", "FEL"},
+ {"OK", "OK"},
+ {"Testing", "Prövar"},
+ {"Firewalled", "Bakom Brandvägg"},
+ {"Unknown", "Okänt"},
+ {"Proxy", "Proxy"},
+ {"Mesh", "Mesh"},
+ {"Clock skew", "Tidsförskjutning"},
+ {"Offline", "Nedkopplad"},
+ {"Symmetric NAT", "Symmetrisk NAT"},
+ {"Full cone NAT", "Full kon NAT"},
+ {"No Descriptors", "Inga Beskrivningar"},
+ {"Uptime", "Upptid"},
+ {"Network status", "Nätverkstillstånd"},
+ {"Network status v6", "Nätverkstillstånd v6"},
+ {"Stopping in", "Avstängd om"},
+ {"Family", "Familj"},
+ {"Tunnel creation success rate", "Andel framgångsrika tunnlar"},
+ {"Received", "Mottaget"},
+ {"%.2f KiB/s", "%.2f KiB/s"},
+ {"Sent", "Skickat"},
+ {"Transit", "Förmedlat"},
+ {"Data path", "Sökväg"},
+ {"Hidden content. Press on text to see.", "Dolt innehåll. Tryck för att visa."},
+ {"Router Ident", "Routeridentitet"},
+ {"Router Family", "Routerfamilj"},
+ {"Router Caps", "Routerbegränsningar"},
+ {"Version", "Version"},
+ {"Our external address", "Vår externa adress"},
+ {"supported", "stöds"},
+ {"Routers", "Routrar"},
+ {"Floodfills", "Översvämningsfyllare"},
+ {"Client Tunnels", "Klienttunnlar"},
+ {"Services", "Tjänster"},
+ {"Enabled", "Påslaget"},
+ {"Disabled", "Avslaget"},
+ {"Encrypted B33 address", "Krypterad B33-Adress"},
+ {"Address registration line", "Adressregistreringsrad"},
+ {"Domain", "Domän"},
+ {"Generate", "Skapa"},
+ {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Uppmärksamma:</b> den resulterande strängen kan enbart användas för att registrera 2LD-domäner (exempel.i2p). För att registrera underdomäner, vänligen använd i2pd-tools."},
+ {"Address", "Adress"},
+ {"Type", "Typ"},
+ {"EncType", "EncTyp"},
+ {"Inbound tunnels", "Ingående Tunnlar"},
+ {"%dms", "%dms"},
+ {"Outbound tunnels", "Utgående Tunnlar"},
+ {"Tags", "Taggar"},
+ {"Incoming", "Ingående"},
+ {"Outgoing", "Utgående"},
+ {"Destination", "Plats"},
+ {"Amount", "Mängd"},
+ {"Incoming Tags", "Ingående Taggar"},
+ {"Tags sessions", "Tagg-perioder"},
+ {"Status", "Tillstånd"},
+ {"Local Destination", "Lokal Plats"},
+ {"Streams", "Strömmar"},
+ {"Close stream", "Stäng strömmen"},
+ {"Such destination is not found", "En sådan plats hittas ej"},
+ {"I2CP session not found", "I2CP-period hittades inte"},
+ {"I2CP is not enabled", "I2CP är inte påslaget"},
+ {"Invalid", "Ogiltig"},
+ {"Store type", "Lagringstyp"},
+ {"Expires", "Utgångsdatum"},
+ {"Non Expired Leases", "Ickeutgångna Hyresuppsättningar"},
+ {"Gateway", "Gateway"},
+ {"TunnelID", "TunnelID"},
+ {"EndDate", "EndDate"},
+ {"floodfill mode is disabled", "Floodfill läget är inaktiverat"},
+ {"Queue size", "Köstorlek"},
+ {"Run peer test", "Utför utsiktstest"},
+ {"Reload tunnels configuration", "Ladda om tunnelkonfiguration"},
+ {"Decline transit tunnels", "Avvisa förmedlande tunnlar"},
+ {"Accept transit tunnels", "Tillåt förmedlande tunnlar"},
+ {"Cancel graceful shutdown", "Avbryt välvillig avstängning"},
+ {"Start graceful shutdown", "Påbörja välvillig avstängning"},
+ {"Force shutdown", "Tvingad avstängning"},
+ {"Reload external CSS styles", "Ladda om externa CSS-stilar"},
+ {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Uppmärksamma:</b> inga ändringar här är beständiga eller påverkar dina inställningsfiler."},
+ {"Logging level", "Protokollförningsnivå"},
+ {"Transit tunnels limit", "Begränsa förmedlande tunnlar"},
+ {"Change", "Ändra"},
+ {"Change language", "Ändra språk"},
+ {"no transit tunnels currently built", "inga förmedlande tunnlar har byggts"},
+ {"SAM disabled", "SAM avslaget"},
+ {"no sessions currently running", "inga perioder igång"},
+ {"SAM session not found", "SAM-perioder hittades ej"},
+ {"SAM Session", "SAM-period"},
+ {"Server Tunnels", "Värdtunnlar"},
+ {"Client Forwards", "Klientförpassningar"},
+ {"Server Forwards", "Värdförpassningar"},
+ {"Unknown page", "Okänd sida"},
+ {"Invalid token", "Ogiltig polett"},
+ {"SUCCESS", "FRAMGÅNG"},
+ {"Stream closed", "Ström stängd"},
+ {"Stream not found or already was closed", "Strömmen hittades inte eller var redan avslutad"},
+ {"Destination not found", "Plats hittades ej"},
+ {"StreamID can't be null", "Ström-ID kan inte vara null"},
+ {"Return to destination page", "Återvänd till platssidan"},
+ {"You will be redirected in %d seconds", "Du omdirigeras inom %d sekunder"},
+ {"Transit tunnels count must not exceed %d", "Förmedlande tunnlar får inte överstiga %d"},
+ {"Back to commands list", "Tillbaka till kommandolistan"},
+ {"Register at reg.i2p", "Registrera vid reg.i2p"},
+ {"Description", "Beskrivning"},
+ {"A bit information about service on domain", "Ett stycke information om domänens tjänst"},
+ {"Submit", "Skicka"},
+ {"Domain can't end with .b32.i2p", "Domänen får inte sluta med .b32.i2p"},
+ {"Domain must end with .i2p", "Domänen måste sluta med .i2p"},
+ {"Unknown command", "Okänt kommando"},
+ {"Command accepted", "Kommando accepterades"},
+ {"Proxy error", "Proxyfel"},
+ {"Proxy info", "Proxyinfo"},
+ {"Proxy error: Host not found", "Proxyfel: Värden hittades ej"},
+ {"Remote host not found in router's addressbook", "Främmande värd hittades inte i routerns adressbok"},
+ {"You may try to find this host on jump services below", "Du kan försöka att hitta värden genom hopptjänsterna nedan"},
+ {"Invalid request", "Ogiltig förfrågan"},
+ {"Proxy unable to parse your request", "Proxyt kan inte behandla din förfrågan"},
+ {"Addresshelper is not supported", "Adresshjälparen stöds ej"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Värd %s är <font color=red>redan i routerns adressbok</font>. <b>Var försiktig: källan till denna URL kan vara skadlig!</b> Klicka här för att uppdatera registreringen: <a href=\"%s%s%s&update=true\">Fortsätt</a>."},
+ {"Addresshelper forced update rejected", "Tvingad uppdatering av adresshjälparen nekad"},
+ {"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "För att lägga till värd <b>%s</b> i routerns adressbok, klicka här: <a href=\"%s%s%s\">Fortsätt</a>."},
+ {"Addresshelper request", "Adresshjälpare förfrågan"},
+ {"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Värd %s tillagd i routerns adressbok från hjälparen. Klicka här för att fortsätta: <a href=\"%s\">Fortsätt</a>."},
+ {"Addresshelper adding", "Adresshjälpare tilläggning"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Värd %s är <font color=red>redan i routerns adressbok</font>. Klicka här för att uppdatera registreringen: <a href=\"%s%s%s&update=true\">Fortsätt</a>."},
+ {"Addresshelper update", "Adresshjälpare uppdatering"},
+ {"Invalid request URI", "Ogiltig förfrågnings-URI"},
+ {"Can't detect destination host from request", "Kan inte upptäcka platsvärden från förfrågan"},
+ {"Outproxy failure", "Utproxyfel"},
+ {"Bad outproxy settings", "Ogiltig utproxyinställning"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "Värd %s är inte inom I2P-näverket, men utproxy är inte påslaget"},
+ {"Unknown outproxy URL", "okänt Utproxy-URL"},
+ {"Cannot resolve upstream proxy", "Hittar inte uppströmsproxyt"},
+ {"Hostname is too long", "Värdnamnet är för långt"},
+ {"Cannot connect to upstream SOCKS proxy", "Kan inte ansluta till uppström SOCKS-proxy"},
+ {"Cannot negotiate with SOCKS proxy", "Kan inte förhandla med SOCKSproxyt"},
+ {"CONNECT error", "CONNECT-fel"},
+ {"Failed to connect", "Anslutningen misslyckades"},
+ {"SOCKS proxy error", "SOCKSproxyfel"},
+ {"Failed to send request to upstream", "Förfrågan uppströms kunde ej skickas"},
+ {"No reply from SOCKS proxy", "Fick inget svar från SOCKSproxyt"},
+ {"Cannot connect", "Kan inte ansluta"},
+ {"HTTP out proxy not implemented", "HTTP-Utproxy ej implementerat"},
+ {"Cannot connect to upstream HTTP proxy", "Kan inte ansluta till uppströms HTTP-proxy"},
+ {"Host is down", "Värden är nere"},
+ {"Can't create connection to requested host, it may be down. Please try again later.", "Kan inte ansluta till värden, den kan vara nere. Vänligen försök senare."},
+ {"", ""},
+ };
+
+ static std::map<std::string, std::vector<std::string>> plurals
+ {
+ {"%d days", {"%d dag", "%d dagar"}},
+ {"%d hours", {"%d timme", "%d timmar"}},
+ {"%d minutes", {"%d minut", "%d minuter"}},
+ {"%d seconds", {"%d sekund", "%d sekunder"}},
+ {"", {"", ""}},
+ };
+
+ std::shared_ptr<const i2p::i18n::Locale> GetLocale()
+ {
+ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
+ }
+
+} // language
+} // i18n
+} // i2p
+
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Turkish.cpp
^
|
@@ -0,0 +1,114 @@
+/*
+* Copyright (c) 2023, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*/
+
+#include <map>
+#include <vector>
+#include <string>
+#include <memory>
+#include "I18N.h"
+
+// Turkish localization file
+
+namespace i2p
+{
+namespace i18n
+{
+namespace turkish // language namespace
+{
+ // language name in lowercase
+ static std::string language = "turkish";
+
+ // See for language plural forms here:
+ // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
+ static int plural (int n) {
+ return n != 1 ? 1 : 0;
+ }
+
+ static std::map<std::string, std::string> strings
+ {
+ {"%.2f KiB", "%.2f KiB"},
+ {"%.2f MiB", "%.2f MiB"},
+ {"%.2f GiB", "%.2f GiB"},
+ {"building", "kuruluyor"},
+ {"failed", "başarısız"},
+ {"expiring", "süresi geçiyor"},
+ {"established", "kurulmuş"},
+ {"unknown", "bilinmeyen"},
+ {"Purple I2P Webconsole", "Mor I2P Webkonsolu"},
+ {"<b>i2pd</b> webconsole", "<b>i2pd</b> webkonsolu"},
+ {"Main page", "Ana sayfa"},
+ {"Router commands", "Router komutları"},
+ {"Local Destinations", "Yerel Hedefler"},
+ {"Tunnels", "Tüneller"},
+ {"Transit Tunnels", "Transit Tünelleri"},
+ {"Transports", "Taşıma"},
+ {"I2P tunnels", "I2P tünelleri"},
+ {"SAM sessions", "SAM oturumları"},
+ {"ERROR", "HATA"},
+ {"OK", "TAMAM"},
+ {"Testing", "Test ediliyor"},
+ {"Firewalled", "Güvenlik Duvarı Kısıtlaması"},
+ {"Unknown", "Bilinmeyen"},
+ {"Proxy", "Proxy"},
+ {"Clock skew", "Saat sorunu"},
+ {"Offline", "Çevrimdışı"},
+ {"Symmetric NAT", "Simetrik NAT"},
+ {"Full cone NAT", "Full cone NAT"},
+ {"No Descriptors", "Tanımlayıcı Yok"},
+ {"Uptime", "Bağlantı süresi"},
+ {"Network status", "Ağ durumu"},
+ {"Network status v6", "Ağ durumu v6"},
+ {"Family", "Aile"},
+ {"Tunnel creation success rate", "Tünel oluşturma başarı oranı"},
+ {"Received", "Alındı"},
+ {"%.2f KiB/s", "%.2f KiB/s"},
+ {"Sent", "Gönderildi"},
+ {"Transit", "Transit"},
+ {"Data path", "Veri yolu"},
+ {"Hidden content. Press on text to see.", "Gizlenmiş içerik. Görmek için yazıya tıklayınız."},
+ {"Router Family", "Router Familyası"},
+ {"Decline transit tunnels", "Transit tünellerini reddet"},
+ {"Accept transit tunnels", "Transit tünellerini kabul et"},
+ {"Cancel graceful shutdown", "Düzgün durdurmayı iptal Et"},
+ {"Start graceful shutdown", "Düzgün durdurmayı başlat"},
+ {"Force shutdown", "Durdurmaya zorla"},
+ {"Reload external CSS styles", "Harici CSS stilini yeniden yükle"},
+ {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Not:</b> burada yapılan ayarların hiçbiri kalıcı değildir ve ayar dosyalarınızı değiştirmez."},
+ {"Logging level", "Kayıt tutma seviyesi"},
+ {"Transit tunnels limit", "Transit tünel limiti"},
+ {"Change", "Değiştir"},
+ {"Change language", "Dil değiştir"},
+ {"no transit tunnels currently built", "kurulmuş bir transit tüneli bulunmamakta"},
+ {"SAM disabled", "SAM devre dışı"},
+ {"no sessions currently running", "hiçbir oturum şu anda çalışmıyor"},
+ {"SAM session not found", "SAM oturumu bulunamadı"},
+ {"SAM Session", "SAM oturumu"},
+ {"Server Tunnels", "Sunucu Tünelleri"},
+ {"Unknown page", "Bilinmeyen sayfa"},
+ {"Invalid token", "Geçersiz token"},
+ {"SUCCESS", "BAŞARILI"},
+ {"", ""},
+ };
+
+ static std::map<std::string, std::vector<std::string>> plurals
+ {
+ {"%d days", {"%d gün", "%d gün"}},
+ {"%d hours", {"%d saat", "%d saat"}},
+ {"%d minutes", {"%d dakika", "%d dakika"}},
+ {"%d seconds", {"%d saniye", "%d saniye"}},
+ {"", {"", ""}},
+ };
+
+ std::shared_ptr<const i2p::i18n::Locale> GetLocale()
+ {
+ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
+ }
+
+} // language
+} // i18n
+} // i2p
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Turkmen.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2021-2022, The PurpleI2P Project
+* Copyright (c) 2021-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -31,15 +31,16 @@
static std::map<std::string, std::string> strings
{
- {"KiB", "KiB"},
- {"MiB", "MiB"},
- {"GiB", "GiB"},
+ {"%.2f KiB", "%.2f KiB"},
+ {"%.2f MiB", "%.2f MiB"},
+ {"%.2f GiB", "%.2f GiB"},
{"building", "bina"},
{"failed", "şowsuz"},
{"expiring", "möhleti gutarýar"},
{"established", "işleýär"},
{"unknown", "näbelli"},
{"exploratory", "gözleg"},
+ {"Purple I2P Webconsole", "Web konsoly Purple I2P"},
{"<b>i2pd</b> webconsole", "Web konsoly <b>i2pd</b>"},
{"Main page", "Esasy sahypa"},
{"Router commands", "Marşrutizator buýruklary"},
@@ -57,7 +58,6 @@
{"Unknown", "Näbelli"},
{"Proxy", "Proksi"},
{"Mesh", "MESH-tor"},
- {"Error", "Ýalňyşlyk"},
{"Clock skew", "Takyk wagt däl"},
{"Offline", "Awtonom"},
{"Symmetric NAT", "Simmetriklik NAT"},
@@ -68,7 +68,7 @@
{"Family", "Maşgala"},
{"Tunnel creation success rate", "Gurlan teneller üstünlikli gurlan teneller"},
{"Received", "Alnan"},
- {"KiB/s", "KiB/s"},
+ {"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "Ýerleşdirildi"},
{"Transit", "Tranzit"},
{"Data path", "Maglumat ýoly"},
@@ -94,7 +94,7 @@
{"Type", "Görnüş"},
{"EncType", "Şifrlemek görnüşi"},
{"Inbound tunnels", "Gelýän tuneller"},
- {"ms", "ms"},
+ {"%dms", "%dms"},
{"Outbound tunnels", "Çykýan tuneller"},
{"Tags", "Bellikler"},
{"Incoming", "Gelýän"},
@@ -116,7 +116,6 @@
{"Gateway", "Derweze"},
{"TunnelID", "Tuneliň ID"},
{"EndDate", "Gutarýar"},
- {"not floodfill", "fludfil däl"},
{"Queue size", "Nobatyň ululygy"},
{"Run peer test", "Synag başlaň"},
{"Decline transit tunnels", "Tranzit tunellerini ret ediň"},
@@ -146,8 +145,6 @@
{"Destination not found", "Niýetlenen ýeri tapylmady"},
{"StreamID can't be null", "StreamID boş bolup bilmez"},
{"Return to destination page", "Barmaly nokadynyň nokadyna gaýdyp geliň"},
- {"You will be redirected in 5 seconds", "5 sekuntdan soň täzeden ugrukdyrylarsyňyz"},
- {"Transit tunnels count must not exceed 65535", "Tranzit tagtalaryň sany 65535-den geçmeli däldir"},
{"Back to commands list", "Topar sanawyna dolan"},
{"Register at reg.i2p", "Reg.i2P-de hasaba duruň"},
{"Description", "Beýany"},
@@ -165,32 +162,24 @@
{"You may try to find this host on jump services below", "Aşakdaky böküş hyzmatlarynda bu öý eýesini tapmaga synanyşyp bilersiňiz"},
{"Invalid request", "Nädogry haýyş"},
{"Proxy unable to parse your request", "Proksi haýyşyňyzy derňäp bilmeýär"},
- {"addresshelper is not supported", "Salgylandyryjy goldanok"},
- {"Host", "Adres"},
- {"added to router's addressbook from helper", "marşruteriň adresini kömekçiden goşdy"},
- {"Click here to proceed:", "Dowam etmek bu ýerde basyň:"},
- {"Continue", "Dowam et"},
- {"Addresshelper found", "Forgelper tapyldy"},
- {"already in router's addressbook", "marşruteriň adres kitaby"},
- {"Click here to update record:", "Recordazgyny täzelemek üçin bu ýerde basyň:"},
- {"invalid request uri", "nädogry haýyş URI"},
+ {"Invalid request URI", "Nädogry haýyş URI"},
{"Can't detect destination host from request", "Haýyşdan barmaly ýerini tapyp bilemok"},
{"Outproxy failure", "Daşarky proksi ýalňyşlyk"},
- {"bad outproxy settings", "daşarky daşarky proksi sazlamalary nädogry"},
- {"not inside I2P network, but outproxy is not enabled", "I2P torunda däl, ýöne daşarky proksi goşulmaýar"},
- {"unknown outproxy url", "näbelli daşarky proksi URL"},
- {"cannot resolve upstream proxy", "has ýokary proksi kesgitläp bilmeýär"},
- {"hostname too long", "hoster eýesi ady gaty uzyn"},
- {"cannot connect to upstream socks proxy", "ýokary jorap SOCKS proksi bilen birigip bolmaýar"},
- {"Cannot negotiate with socks proxy", "Iň ýokary jorap SOCKS proksi bilen ylalaşyp bilmeýärler"},
+ {"Bad outproxy settings", "Daşarky Daşarky proksi sazlamalary nädogry"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "Adres %s I2P torunda däl, ýöne daşarky proksi goşulmaýar"},
+ {"Unknown outproxy URL", "Näbelli daşarky proksi URL"},
+ {"Cannot resolve upstream proxy", "Has ýokary proksi kesgitläp bilmeýär"},
+ {"Hostname is too long", "Hoster eýesi ady gaty uzyn"},
+ {"Cannot connect to upstream SOCKS proxy", "Ýokary jorap SOCKS proksi bilen birigip bolmaýar"},
+ {"Cannot negotiate with SOCKS proxy", "Iň ýokary jorap SOCKS proksi bilen ylalaşyp bilmeýärler"},
{"CONNECT error", "Bagyr haýyşy säwligi"},
- {"Failed to Connect", "Birikdirip bilmedi"},
- {"socks proxy error", "socks proksi ýalňyşlygy"},
- {"failed to send request to upstream", "öý eýesi proksi üçin haýyş iberip bilmedi"},
- {"No Reply From socks proxy", "Jorap proksi serwerinden hiç hili jogap ýok"},
- {"cannot connect", "birikdirip bilmedi"},
- {"http out proxy not implemented", "daşarky HTTP proksi serwerini goldamak amala aşyrylmaýar"},
- {"cannot connect to upstream http proxy", "ýokary akym HTTP proksi serwerine birigip bilmedi"},
+ {"Failed to connect", "Birikdirip bilmedi"},
+ {"SOCKS proxy error", "SOCKS proksi ýalňyşlygy"},
+ {"Failed to send request to upstream", "Öý eýesi proksi üçin haýyş iberip bilmedi"},
+ {"No reply from SOCKS proxy", "Jorap SOCKS proksi serwerinden hiç hili jogap ýok"},
+ {"Cannot connect", "Birikdirip bilmedi"},
+ {"HTTP out proxy not implemented", "Daşarky HTTP proksi serwerini goldamak amala aşyrylmaýar"},
+ {"Cannot connect to upstream HTTP proxy", "Ýokary jorap HTTP proksi bilen birigip bolmaýar"},
{"Host is down", "Salgy elýeterli däl"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Talap edilýän salgyda birikmäni gurup bilmedim, onlaýn bolup bilmez. Soňra haýyşy soň gaýtalamaga synanyşyň."},
{"", ""},
@@ -198,10 +187,10 @@
static std::map<std::string, std::vector<std::string>> plurals
{
- {"days", {"gün", "gün"}},
- {"hours", {"sagat", "sagat"}},
- {"minutes", {"minut", "minut"}},
- {"seconds", {"sekunt", "sekunt"}},
+ {"%d days", {"%d gün", "%d gün"}},
+ {"%d hours", {"%d sagat", "%d sagat"}},
+ {"%d minutes", {"%d minut", "%d minut"}},
+ {"%d seconds", {"%d sekunt", "%d sekunt"}},
{"", {"", ""}},
};
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Ukrainian.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2021, The PurpleI2P Project
+* Copyright (c) 2021-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -31,15 +31,16 @@
static std::map<std::string, std::string> strings
{
- {"KiB", "КіБ"},
- {"MiB", "МіБ"},
- {"GiB", "ГіБ"},
+ {"%.2f KiB", "%.2f КіБ"},
+ {"%.2f MiB", "%.2f МіБ"},
+ {"%.2f GiB", "%.2f ГіБ"},
{"building", "будується"},
{"failed", "невдалий"},
{"expiring", "завершується"},
{"established", "працює"},
{"unknown", "невідомо"},
{"exploratory", "дослідницький"},
+ {"Purple I2P Webconsole", "Веб-консоль Purple I2P"},
{"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"},
{"Main page", "Головна"},
{"Router commands", "Команди маршрутизатора"},
@@ -57,18 +58,20 @@
{"Unknown", "Невідомо"},
{"Proxy", "Проксі"},
{"Mesh", "MESH-мережа"},
- {"Error", "Помилка"},
{"Clock skew", "Неточний час"},
{"Offline", "Офлайн"},
{"Symmetric NAT", "Симетричний NAT"},
+ {"Full cone NAT", "Повний NAT"},
+ {"No Descriptors", "Немає Описів"},
{"Uptime", "У мережі"},
{"Network status", "Мережевий статус"},
{"Network status v6", "Мережевий статус v6"},
{"Stopping in", "Зупинка через"},
{"Family", "Сімейство"},
{"Tunnel creation success rate", "Успішно побудованих тунелів"},
+ {"Total tunnel creation success rate", "Загальна кількість створених тунелів"},
{"Received", "Отримано"},
- {"KiB/s", "КіБ/с"},
+ {"%.2f KiB/s", "%.2f КіБ/с"},
{"Sent", "Відправлено"},
{"Transit", "Транзит"},
{"Data path", "Шлях до даних"},
@@ -93,8 +96,9 @@
{"Address", "Адреса"},
{"Type", "Тип"},
{"EncType", "ТипШифр"},
+ {"Expire LeaseSet", "Завершити LeaseSet"},
{"Inbound tunnels", "Вхідні тунелі"},
- {"ms", "мс"},
+ {"%dms", "%dмс"},
{"Outbound tunnels", "Вихідні тунелі"},
{"Tags", "Теги"},
{"Incoming", "Вхідні"},
@@ -107,6 +111,7 @@
{"Local Destination", "Локальні Призначення"},
{"Streams", "Потоки"},
{"Close stream", "Закрити потік"},
+ {"Such destination is not found", "Така точка призначення не знайдена"},
{"I2CP session not found", "I2CP сесія не знайдена"},
{"I2CP is not enabled", "I2CP не увікнуто"},
{"Invalid", "Некоректний"},
@@ -116,9 +121,10 @@
{"Gateway", "Шлюз"},
{"TunnelID", "ID тунеля"},
{"EndDate", "Закінчується"},
- {"not floodfill", "не флудфіл"},
+ {"floodfill mode is disabled", "режим floodfill вимкнено"},
{"Queue size", "Розмір черги"},
{"Run peer test", "Запустити тестування"},
+ {"Reload tunnels configuration", "Перезавантажити налаштування тунелів"},
{"Decline transit tunnels", "Відхиляти транзитні тунелі"},
{"Accept transit tunnels", "Ухвалювати транзитні тунелі"},
{"Cancel graceful shutdown", "Скасувати плавну зупинку"},
@@ -146,8 +152,10 @@
{"Destination not found", "Точка призначення не знайдена"},
{"StreamID can't be null", "Ідентифікатор потоку не може бути порожнім"},
{"Return to destination page", "Повернутися на сторінку точки призначення"},
- {"You will be redirected in 5 seconds", "Ви будете переадресовані через 5 секунд"},
- {"Transit tunnels count must not exceed 65535", "Кількість транзитних тунелів не повинна перевищувати 65535"},
+ {"You will be redirected in %d seconds", "Ви будете переадресовані через %d секунд"},
+ {"LeaseSet expiration time updated", "Час закінчення LeaseSet оновлено"},
+ {"LeaseSet is not found or already expired", "LeaseSet не знайдено або вже закінчився"},
+ {"Transit tunnels count must not exceed %d", "Кількість транзитних тунелів не повинна перевищувати %d"},
{"Back to commands list", "Повернутися до списку команд"},
{"Register at reg.i2p", "Зареєструвати на reg.i2p"},
{"Description", "Опис"},
@@ -155,7 +163,6 @@
{"Submit", "Надіслати"},
{"Domain can't end with .b32.i2p", "Домен не може закінчуватися на .b32.i2p"},
{"Domain must end with .i2p", "Домен повинен закінчуватися на .i2p"},
- {"Such destination is not found", "Така точка призначення не знайдена"},
{"Unknown command", "Невідома команда"},
{"Command accepted", "Команда прийнята"},
{"Proxy error", "Помилка проксі"},
@@ -165,32 +172,33 @@
{"You may try to find this host on jump services below", "Ви можете спробувати знайти дану адресу на джамп сервісах нижче"},
{"Invalid request", "Некоректний запит"},
{"Proxy unable to parse your request", "Проксі не може розібрати ваш запит"},
- {"addresshelper is not supported", "addresshelper не підтримується"},
- {"Host", "Адреса"},
- {"added to router's addressbook from helper", "доданий в адресну книгу маршрутизатора через хелпер"},
- {"Click here to proceed:", "Натисніть тут щоб продовжити:"},
- {"Continue", "Продовжити"},
- {"Addresshelper found", "Знайдено addresshelper"},
- {"already in router's addressbook", "вже в адресній книзі маршрутизатора"},
- {"Click here to update record:", "Натисніть тут щоб оновити запис:"},
- {"invalid request uri", "некоректний URI запиту"},
+ {"Addresshelper is not supported", "Адресна книга не підтримується"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Хост %s <font color=red>вже в адресній книзі маршрутизатора</font>. <b>Будьте обережні: джерело цієї адреси може зашкодити!</b> Натисніть тут, щоб оновити запис: <a href=\"%s%s%s&update=true\">Продовжити</a>."},
+ {"Addresshelper forced update rejected", "Адресна книга відхилила примусове оновлення"},
+ {"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Щоб додати хост <b>%s</b> в адресі маршрутизатора, натисніть тут: <a href=\"%s%s%s\">Продовжити</a>."},
+ {"Addresshelper request", "Запит на адресну сторінку"},
+ {"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Хост %s доданий в адресну книгу маршрутизатора від помічника. Натисніть тут, щоб продовжити: <a href=\"%s\">Продовжити</a>."},
+ {"Addresshelper adding", "Адреса додана"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Хост %s <font color=red>вже в адресній книзі маршрутизатора</font>. Натисніть тут, щоб оновити запис: <a href=\"%s%s%s&update=true\">Продовжити</a>."},
+ {"Addresshelper update", "Оновлення адресної книги"},
+ {"Invalid request URI", "Некоректний URI запиту"},
{"Can't detect destination host from request", "Не вдалось визначити адресу призначення з запиту"},
{"Outproxy failure", "Помилка зовнішнього проксі"},
- {"bad outproxy settings", "некоректні налаштування зовнішнього проксі"},
- {"not inside I2P network, but outproxy is not enabled", "не в I2P мережі, але зовнішній проксі не включений"},
- {"unknown outproxy url", "невідомий URL зовнішнього проксі"},
- {"cannot resolve upstream proxy", "не вдається визначити висхідний проксі"},
- {"hostname too long", "ім'я вузла надто довге"},
- {"cannot connect to upstream socks proxy", "не вдається підключитися до висхідного SOCKS проксі"},
- {"Cannot negotiate with socks proxy", "Не вдається домовитися з висхідним SOCKS проксі"},
+ {"Bad outproxy settings", "Некоректні налаштування зовнішнього проксі"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "Адрес %s не в I2P мережі, але зовнішній проксі не включений"},
+ {"Unknown outproxy URL", "Невідомий URL зовнішнього проксі"},
+ {"Cannot resolve upstream proxy", "Не вдається визначити висхідний проксі"},
+ {"Hostname is too long", "Ім'я вузла надто довге"},
+ {"Cannot connect to upstream SOCKS proxy", "Не вдалося підключитися до висхідного SOCKS проксі сервера"},
+ {"Cannot negotiate with SOCKS proxy", "Не вдається домовитися з висхідним SOCKS проксі"},
{"CONNECT error", "Помилка CONNECT запиту"},
- {"Failed to Connect", "Не вдалося підключитися"},
- {"socks proxy error", "помилка SOCKS проксі"},
- {"failed to send request to upstream", "не вдалося відправити запит висхідному проксі"},
- {"No Reply From socks proxy", "Немає відповіді від SOCKS проксі сервера"},
- {"cannot connect", "не вдалося підключитися"},
- {"http out proxy not implemented", "підтримка зовнішнього HTTP проксі сервера не реалізована"},
- {"cannot connect to upstream http proxy", "не вдалося підключитися до висхідного HTTP проксі сервера"},
+ {"Failed to connect", "Не вдалося підключитися"},
+ {"SOCKS proxy error", "Помилка SOCKS проксі"},
+ {"Failed to send request to upstream", "Не вдалося відправити запит висхідному проксі"},
+ {"No reply from SOCKS proxy", "Немає відповіді від SOCKS проксі сервера"},
+ {"Cannot connect", "Не вдалося підключитися"},
+ {"HTTP out proxy not implemented", "Підтримка зовнішнього HTTP проксі сервера не реалізована"},
+ {"Cannot connect to upstream HTTP proxy", "Не вдалося підключитися до висхідного HTTP проксі сервера"},
{"Host is down", "Вузол недоступний"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Не вдалося встановити з'єднання до запитаного вузла, можливо він не в мережі. Спробуйте повторити запит пізніше."},
{"", ""},
@@ -198,10 +206,10 @@
static std::map<std::string, std::vector<std::string>> plurals
{
- {"days", {"день", "дня", "днів"}},
- {"hours", {"годину", "години", "годин"}},
- {"minutes", {"хвилину", "хвилини", "хвилин"}},
- {"seconds", {"секунду", "секунди", "секунд"}},
+ {"%d days", {"%d день", "%d дня", "%d днів"}},
+ {"%d hours", {"%d годину", "%d години", "%d годин"}},
+ {"%d minutes", {"%d хвилину", "%d хвилини", "%d хвилин"}},
+ {"%d seconds", {"%d секунду", "%d секунди", "%d секунд"}},
{"", {"", "", ""}},
};
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/i18n/Uzbek.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2021-2022, The PurpleI2P Project
+* Copyright (c) 2021-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -31,15 +31,16 @@
static std::map<std::string, std::string> strings
{
- {"KiB", "KiB"},
- {"MiB", "MiB"},
- {"GiB", "GiB"},
+ {"%.2f KiB", "%.2f KiB"},
+ {"%.2f MiB", "%.2f MiB"},
+ {"%.2f GiB", "%.2f GiB"},
{"building", "yaratilmoqda"},
{"failed", "muvaffaqiyatsiz"},
{"expiring", "muddati tugaydi"},
{"established", "aloqa o'rnatildi"},
{"unknown", "noma'lum"},
{"exploratory", "tadqiqiy"},
+ {"Purple I2P Webconsole", "Veb-konsoli Purple I2P"},
{"<b>i2pd</b> webconsole", "<b>i2pd</b> veb-konsoli"},
{"Main page", "Asosiy sahifa"},
{"Router commands", "Router buyruqlari"},
@@ -57,18 +58,20 @@
{"Unknown", "Notanish"},
{"Proxy", "Proksi"},
{"Mesh", "Mesh To'r"},
- {"Error", "Xato"},
{"Clock skew", "Aniq vaqt emas"},
{"Offline", "Oflayn"},
{"Symmetric NAT", "Simmetrik NAT"},
+ {"Full cone NAT", "Full cone NAT"},
+ {"No Descriptors", "Deskriptorlar yo'q"},
{"Uptime", "Ish vaqti"},
{"Network status", "Tarmoq holati"},
{"Network status v6", "Tarmoq holati v6"},
{"Stopping in", "Ichida to'xtatish"},
{"Family", "Oila"},
{"Tunnel creation success rate", "Tunnel yaratish muvaffaqiyat darajasi"},
+ {"Total tunnel creation success rate", "Tunnel yaratishning umumiy muvaffaqiyat darajasi"},
{"Received", "Qabul qilindi"},
- {"KiB/s", "KiB/s"},
+ {"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "Yuborilgan"},
{"Transit", "Tranzit"},
{"Data path", "Ma'lumotlar joylanishi"},
@@ -93,8 +96,9 @@
{"Address", "Manzil"},
{"Type", "Turi"},
{"EncType", "ShifrlashTuri"},
+ {"Expire LeaseSet", "LeaseSet muddati tugaydi"},
{"Inbound tunnels", "Kirish tunnellari"},
- {"ms", "ms"},
+ {"%dms", "%dms"},
{"Outbound tunnels", "Chiquvchi tunnellar"},
{"Tags", "Teglar"},
{"Incoming", "Kiruvchi"},
@@ -107,6 +111,7 @@
{"Local Destination", "Mahalliy joylanish"},
{"Streams", "Strim"},
{"Close stream", "Strimni o'chirish"},
+ {"Such destination is not found", "Bunday yo'nalish topilmadi"},
{"I2CP session not found", "I2CP sessiyasi topilmadi"},
{"I2CP is not enabled", "I2CP yoqilmagan"},
{"Invalid", "Noto'g'ri"},
@@ -116,9 +121,10 @@
{"Gateway", "Kirish yo'li"},
{"TunnelID", "TunnelID"},
{"EndDate", "Tugash Sanasi"},
- {"not floodfill", "floodfill emas"},
+ {"floodfill mode is disabled", "floodfill rejimi o'chirilgan"},
{"Queue size", "Navbat hajmi"},
{"Run peer test", "Sinovni boshlang"},
+ {"Reload tunnels configuration", "Tunnel konfiguratsiyasini qayta yuklash"},
{"Decline transit tunnels", "Tranzit tunnellarini rad etish"},
{"Accept transit tunnels", "Tranzit tunnellarni qabul qilish"},
{"Cancel graceful shutdown", "Yumshoq to'xtashni bekor qilish"},
@@ -146,8 +152,10 @@
{"Destination not found", "Yo'nalish topilmadi"},
{"StreamID can't be null", "StreamID bo'sh bo'lishi mumkin emas"},
{"Return to destination page", "Manzilgoh sahifasiga qaytish"},
- {"You will be redirected in 5 seconds", "Siz 5 soniya ichida qayta yo'naltirilasiz"},
- {"Transit tunnels count must not exceed 65535", "Tranzit tunnellar soni 65535 dan oshmasligi kerak"},
+ {"You will be redirected in %d seconds", "Siz %d soniyadan so‘ng boshqa yo‘nalishga yo‘naltirilasiz"},
+ {"LeaseSet expiration time updated", "LeaseSet amal qilish muddati yangilandi"},
+ {"LeaseSet is not found or already expired", "LeaseSet topilmadi yoki muddati tugagan"},
+ {"Transit tunnels count must not exceed %d", "Tranzit tunnellar soni %d dan oshmasligi kerak"},
{"Back to commands list", "Buyruqlar ro'yxatiga qaytish"},
{"Register at reg.i2p", "Reg.i2p-da ro'yxatdan o'ting"},
{"Description", "Tavsif"},
@@ -155,7 +163,6 @@
{"Submit", "Yuborish"},
{"Domain can't end with .b32.i2p", "Domen .b32.i2p bilan tugashi mumkin emas"},
{"Domain must end with .i2p", "Domen .i2p bilan tugashi kerak"},
- {"Such destination is not found", "Bunday yo'nalish topilmadi"},
{"Unknown command", "Noma'lum buyruq"},
{"Command accepted", "Buyruq qabul qilindi"},
{"Proxy error", "Proksi xatosi"},
@@ -165,32 +172,33 @@
{"You may try to find this host on jump services below", "Siz xost quyida o'tish xizmatlari orqali topishga harakat qilishingiz mumkin"},
{"Invalid request", "Noto‘g‘ri so‘rov"},
{"Proxy unable to parse your request", "Proksi sizning so'rovingizni aniqlab ololmayapti"},
- {"addresshelper is not supported", "addresshelper qo'llab -quvvatlanmaydi"},
- {"Host", "Xost"},
- {"added to router's addressbook from helper", "'helper'dan routerning 'addressbook'ga qo'shildi"},
- {"Click here to proceed:", "Davom etish uchun shu yerni bosing:"},
- {"Continue", "Davom etish"},
- {"Addresshelper found", "Addresshelper topildi"},
- {"already in router's addressbook", "allaqachon 'addressbook'da yozilgan"},
- {"Click here to update record:", "Yozuvni yangilash uchun shu yerni bosing:"},
- {"invalid request uri", "noto'g'ri URI so'rovi"},
+ {"Addresshelper is not supported", "Addresshelper qo'llab-quvvatlanmaydi"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "%s xosti <font color=red>allaqachon routerning manzillar kitobida</font>. <b>Ehtiyot bo'ling: bu URL manbasi zararli bo'lishi mumkin!</b> Yozuvni yangilash uchun bu yerni bosing: <a href=\"%s%s%s&update=true\">Davom etish</a>."},
+ {"Addresshelper forced update rejected", "Addresshelperni majburiy yangilash rad etildi"},
+ {"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Routerning manzillar kitobiga <b>%s</b> xostini qo'shish uchun bu yerni bosing: <a href=\"%s%s%s\">Davom etish</a>."},
+ {"Addresshelper request", "Addresshelper so'rovi"},
+ {"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Yordamchidan router manzillar kitobiga %s xost qo‘shildi. Davom etish uchun bu yerga bosing: <a href=\"%s\">Davom etish</a>."},
+ {"Addresshelper adding", "Addresshelperni qo'shish"},
+ {"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "%s xosti <font color=red>allaqachon routerning manzillar kitobida</font>. Yozuvni yangilash uchun shu yerni bosing: <a href=\"%s%s%s&update=true\">Davom etish</a>."},
+ {"Addresshelper update", "Addresshelperni yangilash"},
+ {"Invalid request URI", "Noto'g'ri URI so'rovi"},
{"Can't detect destination host from request", "So‘rov orqali manzil xostini aniqlab bo'lmayapti"},
{"Outproxy failure", "Tashqi proksi muvaffaqiyatsizligi"},
- {"bad outproxy settings", "noto'g'ri tashqi proksi-server sozlamalari"},
- {"not inside I2P network, but outproxy is not enabled", "I2P tarmog'ida emas, lekin tashqi proksi yoqilmagan"},
- {"unknown outproxy url", "noma'lum outproxy url"},
- {"cannot resolve upstream proxy", "yuqoridagi 'proxy-server'ni aniqlab olib bolmayapti"},
- {"hostname too long", "xost nomi juda uzun"},
- {"cannot connect to upstream socks proxy", "yuqori 'socks proxy'ga ulanib bo'lmayapti"},
- {"Cannot negotiate with socks proxy", "'Socks proxy' bilan muzokara olib bo'lmaydi"},
+ {"Bad outproxy settings", "Noto'g'ri tashqi proksi-server sozlamalari"},
+ {"Host %s is not inside I2P network, but outproxy is not enabled", "Xost %s I2P tarmog'ida emas, lekin tashqi proksi yoqilmagan"},
+ {"Unknown outproxy URL", "Noma'lum outproxy URL"},
+ {"Cannot resolve upstream proxy", "Yuqoridagi 'proxy-server'ni aniqlab olib bolmayapti"},
+ {"Hostname is too long", "Xost nomi juda uzun"},
+ {"Cannot connect to upstream SOCKS proxy", "Yuqori 'SOCKS proxy'ga ulanib bo'lmayapti"},
+ {"Cannot negotiate with SOCKS proxy", "'SOCKS proxy' bilan muzokara olib bo'lmaydi"},
{"CONNECT error", "CONNECT xatosi"},
- {"Failed to Connect", "Ulanib bo'lmayapti"},
- {"socks proxy error", "'socks proxy' xatosi"},
- {"failed to send request to upstream", "yuqori http proksi-serveriga so'rovni uborib bo'lmadi"},
- {"No Reply From socks proxy", "'Socks proxy'dan javob yo'q"},
- {"cannot connect", "ulanib bo'lmaydi"},
- {"http out proxy not implemented", "tashqi HTTP proksi-serverni qo'llab-quvvatlash amalga oshirilmagan"},
- {"cannot connect to upstream http proxy", "yuqori http 'proxy-server'iga ulanib bo'lmayapti"},
+ {"Failed to connect", "Ulanib bo'lmayapti"},
+ {"SOCKS proxy error", "'SOCKS proxy' xatosi"},
+ {"Failed to send request to upstream", "Yuqori proksi-serveriga so'rovni uborib bo'lmadi"},
+ {"No reply from SOCKS proxy", "'SOCKS proxy'dan javob yo'q"},
+ {"Cannot connect", "Ulanib bo'lmaydi"},
+ {"HTTP out proxy not implemented", "Tashqi HTTP proksi-serverni qo'llab-quvvatlash amalga oshirilmagan"},
+ {"Cannot connect to upstream HTTP proxy", "Yuqori 'HTTP proxy'ga ulanib bo'lmayapti"},
{"Host is down", "Xost ishlamayapti"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Talab qilingan xost bilan aloqa o'rnatilmadi, u ishlamay qolishi mumkin. Iltimos keyinroq qayta urinib ko'ring."},
{"", ""},
@@ -198,10 +206,10 @@
static std::map<std::string, std::vector<std::string>> plurals
{
- {"days", {"kun", "kun"}},
- {"hours", {"soat", "soat"}},
- {"minutes", {"daqiqa", "daqiqa"}},
- {"seconds", {"soniya", "soniya"}},
+ {"%d days", {"%d kun", "%d kun"}},
+ {"%d hours", {"%d soat", "%d soat"}},
+ {"%d minutes", {"%d daqiqa", "%d daqiqa"}},
+ {"%d seconds", {"%d soniya", "%d soniya"}},
{"", {"", ""}},
};
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Base.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -28,6 +28,11 @@
return T32;
}
+ bool IsBase32 (char ch)
+ {
+ return (ch >= 'a' && ch <= 'z') || (ch >= '2' && ch <= '7');
+ }
+
static void iT64Build(void);
/*
@@ -55,6 +60,11 @@
return T64;
}
+ bool IsBase64 (char ch)
+ {
+ return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '-' || ch == '~';
+ }
+
/*
* Reverse Substitution Table (built in run time)
*/
@@ -187,6 +197,9 @@
else
return 0;
+ if(*InBuffer == P64)
+ return 0;
+
ps = (unsigned char *)(InBuffer + InCount - 1);
while ( *ps-- == P64 )
outCount--;
@@ -269,7 +282,7 @@
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen)
{
- int tmp = 0, bits = 0;
+ unsigned int tmp = 0, bits = 0;
size_t ret = 0;
for (size_t i = 0; i < len; i++)
{
@@ -298,7 +311,7 @@
size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen)
{
size_t ret = 0, pos = 1;
- int bits = 8, tmp = inBuf[0];
+ unsigned int bits = 8, tmp = inBuf[0];
while (ret < outLen && (bits > 0 || pos < len))
{
if (bits < 5)
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Base.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -19,9 +19,11 @@
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
const char * GetBase32SubstitutionTable ();
const char * GetBase64SubstitutionTable ();
+ bool IsBase64 (char ch);
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
+ bool IsBase32 (char ch);
/**
* Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Blinding.cpp
^
|
@@ -135,7 +135,7 @@
//----------------------------------------------------------
const uint8_t B33_TWO_BYTES_SIGTYPE_FLAG = 0x01;
- const uint8_t B33_PER_SECRET_FLAG = 0x02; // not used for now
+ // const uint8_t B33_PER_SECRET_FLAG = 0x02; // not used for now
const uint8_t B33_PER_CLIENT_AUTH_FLAG = 0x04;
BlindedPublicKey::BlindedPublicKey (std::shared_ptr<const IdentityEx> identity, bool clientAuth):
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/CPU.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -7,52 +7,62 @@
*/
#include "CPU.h"
-#if defined(__x86_64__) || defined(__i386__)
-#include <cpuid.h>
-#endif
#include "Log.h"
#ifndef bit_AES
-#define bit_AES (1 << 25)
+ #define bit_AES (1 << 25)
#endif
-#ifndef bit_AVX
-#define bit_AVX (1 << 28)
+
+#if defined(__GNUC__) && __GNUC__ < 6 && IS_X86
+ #include <cpuid.h>
#endif
+#ifdef _MSC_VER
+ #include <intrin.h>
+#endif
namespace i2p
{
namespace cpu
{
bool aesni = false;
- bool avx = false;
- void Detect(bool AesSwitch, bool AvxSwitch, bool force)
+ inline bool cpu_support_aes()
{
-#if defined(__x86_64__) || defined(__i386__)
- int info[4];
- __cpuid(0, info[0], info[1], info[2], info[3]);
- if (info[0] >= 0x00000001) {
- __cpuid(0x00000001, info[0], info[1], info[2], info[3]);
-#if defined (_WIN32) && (WINVER == 0x0501) // WinXP
- if (AesSwitch && force) { // only if forced
-#else
- if ((info[2] & bit_AES && AesSwitch) || (AesSwitch && force)) {
+#if IS_X86
+#if defined(__clang__)
+# if (__clang_major__ >= 6)
+ __builtin_cpu_init();
+# endif
+ return __builtin_cpu_supports("aes");
+#elif (defined(__GNUC__) && __GNUC__ >= 6)
+ __builtin_cpu_init();
+ return __builtin_cpu_supports("aes");
+#elif (defined(__GNUC__) && __GNUC__ < 6)
+ int cpu_info[4];
+ bool flag = false;
+ __cpuid(0, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
+ if (cpu_info[0] >= 0x00000001) {
+ __cpuid(0x00000001, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
+ flag = ((cpu_info[2] & bit_AES) != 0);
+ }
+ return flag;
+#elif defined(_MSC_VER)
+ int cpu_info[4];
+ __cpuid(cpu_info, 1);
+ return ((cpu_info[2] & bit_AES) != 0);
#endif
- aesni = true;
- }
-#if defined (_WIN32) && (WINVER == 0x0501) // WinXP
- if (AvxSwitch && force) { // only if forced
-#else
- if ((info[2] & bit_AVX && AvxSwitch) || (AvxSwitch && force)) {
#endif
- avx = true;
- }
+ return false;
+ }
+
+ void Detect(bool AesSwitch, bool force)
+ {
+ if ((cpu_support_aes() && AesSwitch) || (AesSwitch && force)) {
+ aesni = true;
}
-#endif // defined(__x86_64__) || defined(__i386__)
LogPrint(eLogInfo, "AESNI ", (aesni ? "enabled" : "disabled"));
- LogPrint(eLogInfo, "AVX ", (avx ? "enabled" : "disabled"));
}
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/CPU.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -9,14 +9,31 @@
#ifndef LIBI2PD_CPU_H
#define LIBI2PD_CPU_H
+#if defined(_M_AMD64) || defined(__x86_64__) || defined(_M_IX86) || defined(__i386__)
+# define IS_X86 1
+# if defined(_M_AMD64) || defined(__x86_64__)
+# define IS_X86_64 1
+# else
+# define IS_X86_64 0
+# endif
+#else
+# define IS_X86 0
+# define IS_X86_64 0
+#endif
+
+#if defined(__AES__) && !defined(_MSC_VER) && IS_X86
+# define SUPPORTS_AES 1
+#else
+# define SUPPORTS_AES 0
+#endif
+
namespace i2p
{
namespace cpu
{
extern bool aesni;
- extern bool avx;
- void Detect(bool AesSwitch, bool AvxSwitch, bool force);
+ void Detect(bool AesSwitch, bool force);
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Config.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -45,7 +45,7 @@
("logclftime", bool_switch()->default_value(false), "Write full CLF-formatted date and time to log (default: disabled, write only time)")
("family", value<std::string>()->default_value(""), "Specify a family, router belongs to")
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)")
- ("host", value<std::string>()->default_value("0.0.0.0"), "External IP")
+ ("host", value<std::string>()->default_value(""), "External IP")
("ifname", value<std::string>()->default_value(""), "Network interface to bind to")
("ifname4", value<std::string>()->default_value(""), "Network interface to bind to for ipv4")
("ifname6", value<std::string>()->default_value(""), "Network interface to bind to for ipv6")
@@ -64,7 +64,7 @@
("bandwidth", value<std::string>()->default_value(""), "Transit traffic 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")
- ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)")
+ ("ssu", bool_switch()->default_value(false), "Ignored. Always false")
("ntcpproxy", value<std::string>()->default_value(""), "Ignored")
#ifdef _WIN32
("svcctl", value<std::string>()->default_value(""), "Ignored")
@@ -77,7 +77,8 @@
limits.add_options()
("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.transittunnels", value<uint16_t>()->default_value(5000), "Maximum active transit tunnels (default:5000)")
+ ("limits.zombies", value<double>()->default_value(0), "Minimum percentage of successfully created tunnels under which tunnel cleanup is paused (default [%]: 0.00)")
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Ignored")
("limits.ntcphard", value<uint16_t>()->default_value(0), "Ignored")
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Ignored")
@@ -95,6 +96,7 @@
("http.hostname", value<std::string>()->default_value("localhost"), "Expected hostname for WebUI")
("http.webroot", value<std::string>()->default_value("/"), "WebUI root path (default: / )")
("http.lang", value<std::string>()->default_value("english"), "WebUI language (default: english )")
+ ("http.showTotalTCSR", value<bool>()->default_value(false), "Show additional value with total TCSR since router's start (default: false)")
;
options_description httpproxy("HTTP Proxy options");
@@ -148,7 +150,8 @@
sam.add_options()
("sam.enabled", value<bool>()->default_value(true), "Enable or disable SAM Application bridge")
("sam.address", value<std::string>()->default_value("127.0.0.1"), "SAM listen address")
- ("sam.port", value<uint16_t>()->default_value(7656), "SAM listen port")
+ ("sam.port", value<uint16_t>()->default_value(7656), "SAM listen TCP port")
+ ("sam.portudp", value<uint16_t>()->default_value(0), "SAM listen UDP port")
("sam.singlethread", value<bool>()->default_value(true), "Sessions run in the SAM bridge's thread")
;
@@ -190,7 +193,7 @@
options_description precomputation("Precomputation options");
precomputation.add_options()
("precomputation.elgamal",
-#if defined(__x86_64__)
+#if (defined(_M_AMD64) || defined(__x86_64__))
value<bool>()->default_value(false),
#else
value<bool>()->default_value(true),
@@ -214,17 +217,21 @@
"https://reseed.onion.im/,"
"https://i2pseed.creativecowpat.net:8443/,"
"https://reseed.i2pgit.org/,"
- "https://i2p.novg.net/,"
"https://banana.incognet.io/,"
"https://reseed-pl.i2pd.xyz/,"
- "https://www2.mk16.de/"
+ "https://www2.mk16.de/,"
+ "https://i2p.ghativega.in/,"
+ "https://i2p.novg.net/,"
+ "https://reseed.is.prestium.org/,"
+ "https://reseed.us.prestium.org/"
), "Reseed URLs, separated by comma")
("reseed.yggurls", value<std::string>()->default_value(
"http://[324:71e:281a:9ed3::ace]:7070/,"
"http://[301:65b9:c7cd:9a36::1]:18801/,"
"http://[320:8936:ec1a:31f1::216]/,"
"http://[306:3834:97b9:a00a::1]/,"
- "http://[316:f9e0:f22e:a74f::216]/"
+ "http://[316:f9e0:f22e:a74f::216]/,"
+ "http://[300:eaff:7fab:181b::e621]:7170"
), "Reseed URLs through the Yggdrasil, separated by comma")
;
@@ -274,14 +281,17 @@
options_description ssu2("SSU2 Options");
ssu2.add_options()
- ("ssu2.enabled", value<bool>()->default_value(false), "Enable SSU2 (default: disabled)")
- ("ssu2.published", value<bool>()->default_value(false), "Publish SSU2 (default: disabled)")
+ ("ssu2.enabled", value<bool>()->default_value(true), "Enable SSU2 (default: enabled)")
+ ("ssu2.published", value<bool>()->default_value(true), "Publish SSU2 (default: enabled)")
("ssu2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming SSU2 packets (default: auto)")
+ ("ssu2.mtu4", value<uint16_t>()->default_value(0), "MTU for ipv4 address (default: detect)")
+ ("ssu2.mtu6", value<uint16_t>()->default_value(0), "MTU for ipv6 address (default: detect)")
+ ("ssu2.proxy", value<std::string>()->default_value(""), "Socks5 proxy URL for SSU2 transport")
;
options_description nettime("Time sync options");
nettime.add_options()
- ("nettime.enabled", value<bool>()->default_value(false), "Disable time sync (default: disabled)")
+ ("nettime.enabled", value<bool>()->default_value(false), "Enable NTP time sync (default: disabled)")
("nettime.ntpservers", value<std::string>()->default_value(
"0.pool.ntp.org,"
"1.pool.ntp.org,"
@@ -301,7 +311,7 @@
options_description cpuext("CPU encryption extensions options");
cpuext.add_options()
("cpuext.aesni", bool_switch()->default_value(true), "Use auto detection for AESNI CPU extensions. If false, AESNI will be not used")
- ("cpuext.avx", bool_switch()->default_value(true), "Use auto detection for AVX CPU extensions. If false, AVX will be not used")
+ ("cpuext.avx", bool_switch()->default_value(false), "Deprecated option")
("cpuext.force", bool_switch()->default_value(false), "Force usage of CPU extensions. Useful when cpuinfo is not available on virtual machines")
;
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Crypto.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -28,6 +28,7 @@
#include "I2PEndian.h"
#include "Log.h"
+
namespace i2p
{
namespace crypto
@@ -159,8 +160,10 @@
// DH/ElGamal
+#if !IS_X86_64
const int ELGAMAL_SHORT_EXPONENT_NUM_BITS = 226;
const int ELGAMAL_SHORT_EXPONENT_NUM_BYTES = ELGAMAL_SHORT_EXPONENT_NUM_BITS/8+1;
+#endif
const int ELGAMAL_FULL_EXPONENT_NUM_BITS = 2048;
const int ELGAMAL_FULL_EXPONENT_NUM_BYTES = ELGAMAL_FULL_EXPONENT_NUM_BITS/8;
@@ -239,55 +242,6 @@
static BIGNUM * (* g_ElggTable)[255] = nullptr;
-// DH
-
- DHKeys::DHKeys ()
- {
- m_DH = DH_new ();
- DH_set0_pqg (m_DH, BN_dup (elgp), NULL, BN_dup (elgg));
- DH_set0_key (m_DH, NULL, NULL);
- }
-
- DHKeys::~DHKeys ()
- {
- DH_free (m_DH);
- }
-
- void DHKeys::GenerateKeys ()
- {
- BIGNUM * priv_key = NULL, * pub_key = NULL;
-#if !defined(__x86_64__) // use short exponent for non x64
- priv_key = BN_new ();
- BN_rand (priv_key, ELGAMAL_SHORT_EXPONENT_NUM_BITS, 0, 1);
-#endif
- if (g_ElggTable)
- {
-#if defined(__x86_64__)
- priv_key = BN_new ();
- BN_rand (priv_key, ELGAMAL_FULL_EXPONENT_NUM_BITS, 0, 1);
-#endif
- auto ctx = BN_CTX_new ();
- pub_key = ElggPow (priv_key, g_ElggTable, ctx);
- DH_set0_key (m_DH, pub_key, priv_key);
- BN_CTX_free (ctx);
- }
- else
- {
- DH_set0_key (m_DH, NULL, priv_key);
- DH_generate_key (m_DH);
- DH_get0_key (m_DH, (const BIGNUM **)&pub_key, (const BIGNUM **)&priv_key);
- }
-
- bn2buf (pub_key, m_PublicKey, 256);
- }
-
- void DHKeys::Agree (const uint8_t * pub, uint8_t * shared)
- {
- BIGNUM * pk = BN_bin2bn (pub, 256, NULL);
- DH_compute_key (shared, pk, m_DH);
- BN_free (pk);
- }
-
// x25519
X25519Keys::X25519Keys ()
{
@@ -408,7 +362,7 @@
BIGNUM * b1 = BN_CTX_get (ctx);
BIGNUM * b = BN_CTX_get (ctx);
// select random k
-#if defined(__x86_64__)
+#if IS_X86_64
BN_rand (k, ELGAMAL_FULL_EXPONENT_NUM_BITS, -1, 1); // full exponent for x64
#else
BN_rand (k, ELGAMAL_SHORT_EXPONENT_NUM_BITS, -1, 1); // short exponent of 226 bits
@@ -475,7 +429,7 @@
void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub)
{
-#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER)
+#if IS_X86 || defined(_MSC_VER)
RAND_bytes (priv, 256);
#else
// lower 226 bits (28 bytes and 2 bits) only. short exponent
@@ -601,79 +555,8 @@
BN_CTX_free (ctx);
}
-// HMAC
- const uint64_t IPAD = 0x3636363636363636;
- const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C;
-
-
- static const uint64_t ipads[] = { IPAD, IPAD, IPAD, IPAD };
- static const uint64_t opads[] = { OPAD, OPAD, OPAD, OPAD };
-
- void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest)
- // key is 32 bytes
- // digest is 16 bytes
- // block size is 64 bytes
- {
- uint64_t buf[256];
- uint64_t hash[12]; // 96 bytes
-#if (defined(__x86_64__) || defined(__i386__)) && defined(__AVX__) // not all X86 targets supports AVX (like old Pentium, see #1600)
- if(i2p::cpu::avx)
- {
- __asm__
- (
- "vmovups %[key], %%ymm0 \n"
- "vmovups %[ipad], %%ymm1 \n"
- "vmovups %%ymm1, 32(%[buf]) \n"
- "vxorps %%ymm0, %%ymm1, %%ymm1 \n"
- "vmovups %%ymm1, (%[buf]) \n"
- "vmovups %[opad], %%ymm1 \n"
- "vmovups %%ymm1, 32(%[hash]) \n"
- "vxorps %%ymm0, %%ymm1, %%ymm1 \n"
- "vmovups %%ymm1, (%[hash]) \n"
- "vzeroall \n" // end of AVX
- "movups %%xmm0, 80(%[hash]) \n" // zero last 16 bytes
- :
- : [key]"m"(*(const uint8_t *)key), [ipad]"m"(*ipads), [opad]"m"(*opads),
- [buf]"r"(buf), [hash]"r"(hash)
- : "memory", "%xmm0" // TODO: change to %ymm0 later
- );
- }
- else
-#endif
- {
- // ikeypad
- buf[0] = key.GetLL ()[0] ^ IPAD;
- buf[1] = key.GetLL ()[1] ^ IPAD;
- buf[2] = key.GetLL ()[2] ^ IPAD;
- buf[3] = key.GetLL ()[3] ^ IPAD;
- buf[4] = IPAD;
- buf[5] = IPAD;
- buf[6] = IPAD;
- buf[7] = IPAD;
- // okeypad
- hash[0] = key.GetLL ()[0] ^ OPAD;
- hash[1] = key.GetLL ()[1] ^ OPAD;
- hash[2] = key.GetLL ()[2] ^ OPAD;
- hash[3] = key.GetLL ()[3] ^ OPAD;
- hash[4] = OPAD;
- hash[5] = OPAD;
- hash[6] = OPAD;
- hash[7] = OPAD;
- // fill last 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
- memset (hash + 10, 0, 16);
- }
-
- // concatenate with msg
- memcpy (buf + 8, msg, len);
- // calculate first hash
- MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes
-
- // calculate digest
- MD5((uint8_t *)hash, 96, digest);
- }
-
// AES
-#ifdef __AES__
+#if SUPPORTS_AES
#define KeyExpansion256(round0,round1) \
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
"movaps %%xmm1, %%xmm4 \n" \
@@ -698,7 +581,7 @@
"movaps %%xmm3, "#round1"(%[sched]) \n"
#endif
-#ifdef __AES__
+#if SUPPORTS_AES
void ECBCryptoAESNI::ExpandKey (const AESKey& key)
{
__asm__
@@ -739,7 +622,7 @@
#endif
-#ifdef __AES__
+#if SUPPORTS_AES
#define EncryptAES256(sched) \
"pxor (%["#sched"]), %%xmm0 \n" \
"aesenc 16(%["#sched"]), %%xmm0 \n" \
@@ -760,16 +643,18 @@
void ECBEncryption::Encrypt (const ChipherBlock * in, ChipherBlock * out)
{
-#ifdef __AES__
+#if SUPPORTS_AES
if(i2p::cpu::aesni)
{
__asm__
- (
- "movups (%[in]), %%xmm0 \n"
- EncryptAES256(sched)
- "movups %%xmm0, (%[out]) \n"
- : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
- );
+ (
+ "movups (%[in]), %%xmm0 \n"
+ EncryptAES256(sched)
+ "movups %%xmm0, (%[out]) \n"
+ :
+ : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out)
+ : "%xmm0", "memory"
+ );
}
else
#endif
@@ -778,7 +663,7 @@
}
}
-#ifdef __AES__
+#if SUPPORTS_AES
#define DecryptAES256(sched) \
"pxor 224(%["#sched"]), %%xmm0 \n" \
"aesdec 208(%["#sched"]), %%xmm0 \n" \
@@ -799,16 +684,18 @@
void ECBDecryption::Decrypt (const ChipherBlock * in, ChipherBlock * out)
{
-#ifdef __AES__
+#if SUPPORTS_AES
if(i2p::cpu::aesni)
{
__asm__
- (
- "movups (%[in]), %%xmm0 \n"
- DecryptAES256(sched)
- "movups %%xmm0, (%[out]) \n"
- : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
- );
+ (
+ "movups (%[in]), %%xmm0 \n"
+ DecryptAES256(sched)
+ "movups %%xmm0, (%[out]) \n"
+ :
+ : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out)
+ : "%xmm0", "memory"
+ );
}
else
#endif
@@ -817,7 +704,7 @@
}
}
-#ifdef __AES__
+#if SUPPORTS_AES
#define CallAESIMC(offset) \
"movaps "#offset"(%[shed]), %%xmm0 \n" \
"aesimc %%xmm0, %%xmm0 \n" \
@@ -826,7 +713,7 @@
void ECBEncryption::SetKey (const AESKey& key)
{
-#ifdef __AES__
+#if SUPPORTS_AES
if(i2p::cpu::aesni)
{
ExpandKey (key);
@@ -840,28 +727,30 @@
void ECBDecryption::SetKey (const AESKey& key)
{
-#ifdef __AES__
+#if SUPPORTS_AES
if(i2p::cpu::aesni)
{
ExpandKey (key); // expand encryption key first
// then invert it using aesimc
__asm__
- (
- CallAESIMC(16)
- CallAESIMC(32)
- CallAESIMC(48)
- CallAESIMC(64)
- CallAESIMC(80)
- CallAESIMC(96)
- CallAESIMC(112)
- CallAESIMC(128)
- CallAESIMC(144)
- CallAESIMC(160)
- CallAESIMC(176)
- CallAESIMC(192)
- CallAESIMC(208)
- : : [shed]"r"(GetKeySchedule ()) : "%xmm0", "memory"
- );
+ (
+ CallAESIMC(16)
+ CallAESIMC(32)
+ CallAESIMC(48)
+ CallAESIMC(64)
+ CallAESIMC(80)
+ CallAESIMC(96)
+ CallAESIMC(112)
+ CallAESIMC(128)
+ CallAESIMC(144)
+ CallAESIMC(160)
+ CallAESIMC(176)
+ CallAESIMC(192)
+ CallAESIMC(208)
+ :
+ : [shed]"r"(GetKeySchedule ())
+ : "%xmm0", "memory"
+ );
}
else
#endif
@@ -872,28 +761,28 @@
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
{
-#ifdef __AES__
+#if SUPPORTS_AES
if(i2p::cpu::aesni)
{
__asm__
- (
- "movups (%[iv]), %%xmm1 \n"
- "1: \n"
- "movups (%[in]), %%xmm0 \n"
- "pxor %%xmm1, %%xmm0 \n"
- EncryptAES256(sched)
- "movaps %%xmm0, %%xmm1 \n"
- "movups %%xmm0, (%[out]) \n"
- "add $16, %[in] \n"
- "add $16, %[out] \n"
- "dec %[num] \n"
- "jnz 1b \n"
- "movups %%xmm1, (%[iv]) \n"
- :
- : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
- [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
- : "%xmm0", "%xmm1", "cc", "memory"
- );
+ (
+ "movups (%[iv]), %%xmm1 \n"
+ "1: \n"
+ "movups (%[in]), %%xmm0 \n"
+ "pxor %%xmm1, %%xmm0 \n"
+ EncryptAES256(sched)
+ "movaps %%xmm0, %%xmm1 \n"
+ "movups %%xmm0, (%[out]) \n"
+ "add $16, %[in] \n"
+ "add $16, %[out] \n"
+ "dec %[num] \n"
+ "jnz 1b \n"
+ "movups %%xmm1, (%[iv]) \n"
+ :
+ : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
+ [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
+ : "%xmm0", "%xmm1", "cc", "memory"
+ );
}
else
#endif
@@ -917,22 +806,22 @@
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out)
{
-#ifdef __AES__
+#if SUPPORTS_AES
if(i2p::cpu::aesni)
{
__asm__
- (
- "movups (%[iv]), %%xmm1 \n"
- "movups (%[in]), %%xmm0 \n"
- "pxor %%xmm1, %%xmm0 \n"
- EncryptAES256(sched)
- "movups %%xmm0, (%[out]) \n"
- "movups %%xmm0, (%[iv]) \n"
- :
- : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
- [in]"r"(in), [out]"r"(out)
- : "%xmm0", "%xmm1", "memory"
- );
+ (
+ "movups (%[iv]), %%xmm1 \n"
+ "movups (%[in]), %%xmm0 \n"
+ "pxor %%xmm1, %%xmm0 \n"
+ EncryptAES256(sched)
+ "movups %%xmm0, (%[out]) \n"
+ "movups %%xmm0, (%[iv]) \n"
+ :
+ : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
+ [in]"r"(in), [out]"r"(out)
+ : "%xmm0", "%xmm1", "memory"
+ );
}
else
#endif
@@ -941,29 +830,29 @@
void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
{
-#ifdef __AES__
+#if SUPPORTS_AES
if(i2p::cpu::aesni)
{
__asm__
- (
- "movups (%[iv]), %%xmm1 \n"
- "1: \n"
- "movups (%[in]), %%xmm0 \n"
- "movaps %%xmm0, %%xmm2 \n"
- DecryptAES256(sched)
- "pxor %%xmm1, %%xmm0 \n"
- "movups %%xmm0, (%[out]) \n"
- "movaps %%xmm2, %%xmm1 \n"
- "add $16, %[in] \n"
- "add $16, %[out] \n"
- "dec %[num] \n"
- "jnz 1b \n"
- "movups %%xmm1, (%[iv]) \n"
- :
- : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
- [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
- : "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
- );
+ (
+ "movups (%[iv]), %%xmm1 \n"
+ "1: \n"
+ "movups (%[in]), %%xmm0 \n"
+ "movaps %%xmm0, %%xmm2 \n"
+ DecryptAES256(sched)
+ "pxor %%xmm1, %%xmm0 \n"
+ "movups %%xmm0, (%[out]) \n"
+ "movaps %%xmm2, %%xmm1 \n"
+ "add $16, %[in] \n"
+ "add $16, %[out] \n"
+ "dec %[num] \n"
+ "jnz 1b \n"
+ "movups %%xmm1, (%[iv]) \n"
+ :
+ : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
+ [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
+ : "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
+ );
}
else
#endif
@@ -987,22 +876,22 @@
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out)
{
-#ifdef __AES__
+#if SUPPORTS_AES
if(i2p::cpu::aesni)
{
__asm__
- (
- "movups (%[iv]), %%xmm1 \n"
- "movups (%[in]), %%xmm0 \n"
- "movups %%xmm0, (%[iv]) \n"
- DecryptAES256(sched)
- "pxor %%xmm1, %%xmm0 \n"
- "movups %%xmm0, (%[out]) \n"
- :
- : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
- [in]"r"(in), [out]"r"(out)
- : "%xmm0", "%xmm1", "memory"
- );
+ (
+ "movups (%[iv]), %%xmm1 \n"
+ "movups (%[in]), %%xmm0 \n"
+ "movups %%xmm0, (%[iv]) \n"
+ DecryptAES256(sched)
+ "pxor %%xmm1, %%xmm0 \n"
+ "movups %%xmm0, (%[out]) \n"
+ :
+ : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
+ [in]"r"(in), [out]"r"(out)
+ : "%xmm0", "%xmm1", "memory"
+ );
}
else
#endif
@@ -1011,34 +900,34 @@
void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out)
{
-#ifdef __AES__
+#if SUPPORTS_AES
if(i2p::cpu::aesni)
{
__asm__
- (
- // encrypt IV
- "movups (%[in]), %%xmm0 \n"
- EncryptAES256(sched_iv)
- "movaps %%xmm0, %%xmm1 \n"
- // double IV encryption
- EncryptAES256(sched_iv)
- "movups %%xmm0, (%[out]) \n"
- // encrypt data, IV is xmm1
- "1: \n"
- "add $16, %[in] \n"
- "add $16, %[out] \n"
- "movups (%[in]), %%xmm0 \n"
- "pxor %%xmm1, %%xmm0 \n"
- EncryptAES256(sched_l)
- "movaps %%xmm0, %%xmm1 \n"
- "movups %%xmm0, (%[out]) \n"
- "dec %[num] \n"
- "jnz 1b \n"
- :
- : [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.ECB().GetKeySchedule ()),
- [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
- : "%xmm0", "%xmm1", "cc", "memory"
- );
+ (
+ // encrypt IV
+ "movups (%[in]), %%xmm0 \n"
+ EncryptAES256(sched_iv)
+ "movaps %%xmm0, %%xmm1 \n"
+ // double IV encryption
+ EncryptAES256(sched_iv)
+ "movups %%xmm0, (%[out]) \n"
+ // encrypt data, IV is xmm1
+ "1: \n"
+ "add $16, %[in] \n"
+ "add $16, %[out] \n"
+ "movups (%[in]), %%xmm0 \n"
+ "pxor %%xmm1, %%xmm0 \n"
+ EncryptAES256(sched_l)
+ "movaps %%xmm0, %%xmm1 \n"
+ "movups %%xmm0, (%[out]) \n"
+ "dec %[num] \n"
+ "jnz 1b \n"
+ :
+ : [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.ECB().GetKeySchedule ()),
+ [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
+ : "%xmm0", "%xmm1", "cc", "memory"
+ );
}
else
#endif
@@ -1052,35 +941,35 @@
void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out)
{
-#ifdef __AES__
+#if SUPPORTS_AES
if(i2p::cpu::aesni)
{
__asm__
- (
- // decrypt IV
- "movups (%[in]), %%xmm0 \n"
- DecryptAES256(sched_iv)
- "movaps %%xmm0, %%xmm1 \n"
- // double IV encryption
- DecryptAES256(sched_iv)
- "movups %%xmm0, (%[out]) \n"
- // decrypt data, IV is xmm1
- "1: \n"
- "add $16, %[in] \n"
- "add $16, %[out] \n"
- "movups (%[in]), %%xmm0 \n"
- "movaps %%xmm0, %%xmm2 \n"
- DecryptAES256(sched_l)
- "pxor %%xmm1, %%xmm0 \n"
- "movups %%xmm0, (%[out]) \n"
- "movaps %%xmm2, %%xmm1 \n"
- "dec %[num] \n"
- "jnz 1b \n"
- :
- : [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.ECB().GetKeySchedule ()),
- [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
- : "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
- );
+ (
+ // decrypt IV
+ "movups (%[in]), %%xmm0 \n"
+ DecryptAES256(sched_iv)
+ "movaps %%xmm0, %%xmm1 \n"
+ // double IV encryption
+ DecryptAES256(sched_iv)
+ "movups %%xmm0, (%[out]) \n"
+ // decrypt data, IV is xmm1
+ "1: \n"
+ "add $16, %[in] \n"
+ "add $16, %[out] \n"
+ "movups (%[in]), %%xmm0 \n"
+ "movaps %%xmm0, %%xmm2 \n"
+ DecryptAES256(sched_l)
+ "pxor %%xmm1, %%xmm0 \n"
+ "movups %%xmm0, (%[out]) \n"
+ "movaps %%xmm2, %%xmm1 \n"
+ "dec %[num] \n"
+ "jnz 1b \n"
+ :
+ : [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.ECB().GetKeySchedule ()),
+ [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
+ : "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
+ );
}
else
#endif
@@ -1109,7 +998,7 @@
EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce);
EVP_EncryptUpdate(ctx, NULL, &outlen, ad, adLen);
EVP_EncryptUpdate(ctx, buf, &outlen, msg, msgLen);
- EVP_EncryptFinal_ex(ctx, buf, &outlen);
+ EVP_EncryptFinal_ex(ctx, buf + outlen, &outlen);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, buf + msgLen);
}
else
@@ -1403,9 +1292,9 @@
}
}*/
- void InitCrypto (bool precomputation, bool aesni, bool avx, bool force)
+ void InitCrypto (bool precomputation, bool aesni, bool force)
{
- i2p::cpu::Detect (aesni, avx, force);
+ i2p::cpu::Detect (aesni, force);
#if LEGACY_OPENSSL
SSL_library_init ();
#endif
@@ -1415,7 +1304,7 @@
CRYPTO_set_locking_callback (OpensslLockingCallback);*/
if (precomputation)
{
-#if defined(__x86_64__)
+#if IS_X86_64
g_ElggTable = new BIGNUM * [ELGAMAL_FULL_EXPONENT_NUM_BYTES][255];
PrecalculateElggTable (g_ElggTable, ELGAMAL_FULL_EXPONENT_NUM_BYTES);
#else
@@ -1430,7 +1319,7 @@
if (g_ElggTable)
{
DestroyElggTable (g_ElggTable,
-#if defined(__x86_64__)
+#if IS_X86_64
ELGAMAL_FULL_EXPONENT_NUM_BYTES
#else
ELGAMAL_SHORT_EXPONENT_NUM_BYTES
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Crypto.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -62,24 +62,6 @@
// RSA
const BIGNUM * GetRSAE ();
- // DH
- class DHKeys
- {
- public:
-
- DHKeys ();
- ~DHKeys ();
-
- void GenerateKeys ();
- const uint8_t * GetPublicKey () const { return m_PublicKey; };
- void Agree (const uint8_t * pub, uint8_t * shared);
-
- private:
-
- DH * m_DH;
- uint8_t m_PublicKey[256];
- };
-
// x25519
class X25519Keys
{
@@ -121,10 +103,6 @@
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data
void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub);
- // HMAC
- typedef i2p::data::Tag<32> MACKey;
- void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest);
-
// AES
struct ChipherBlock
{
@@ -172,7 +150,7 @@
};
-#ifdef __AES__
+#if SUPPORTS_AES
class ECBCryptoAESNI
{
public:
@@ -189,7 +167,7 @@
};
#endif
-#ifdef __AES__
+#if SUPPORTS_AES
class ECBEncryption: public ECBCryptoAESNI
#else
class ECBEncryption
@@ -205,7 +183,7 @@
AES_KEY m_Key;
};
-#ifdef __AES__
+#if SUPPORTS_AES
class ECBDecryption: public ECBCryptoAESNI
#else
class ECBDecryption
@@ -329,7 +307,7 @@
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets)
// init and terminate
- void InitCrypto (bool precomputation, bool aesni, bool avx, bool force);
+ void InitCrypto (bool precomputation, bool aesni, bool force);
void TerminateCrypto ();
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Datagram.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -425,7 +425,7 @@
if (m)
send.push_back(i2p::tunnel::TunnelMessageBlock{i2p::tunnel::eDeliveryTypeTunnel,routingPath->remoteLease->tunnelGateway, routingPath->remoteLease->tunnelID, m});
}
- routingPath->outboundTunnel->SendTunnelDataMsg(send);
+ routingPath->outboundTunnel->SendTunnelDataMsgs(send);
}
m_SendQueue.clear();
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Datagram.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -15,6 +15,7 @@
#include <map>
#include <vector>
#include "Base.h"
+#include "Gzip.h"
#include "Identity.h"
#include "LeaseSet.h"
#include "I2NPProtocol.h"
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Destination.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -108,7 +108,7 @@
if (authType >= i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_NONE && authType <= i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK)
m_AuthType = authType;
else
- LogPrint (eLogError, "Destination: Unknown auth type ", authType);
+ LogPrint (eLogError, "Destination: Unknown auth type: ", authType);
}
}
it = params->find (I2CP_PARAM_LEASESET_PRIV_KEY);
@@ -117,7 +117,7 @@
m_LeaseSetPrivKey.reset (new i2p::data::Tag<32>());
if (m_LeaseSetPrivKey->FromBase64 (it->second) != 32)
{
- LogPrint(eLogError, "Destination: Invalid value i2cp.leaseSetPrivKey ", it->second);
+ LogPrint(eLogCritical, "Destination: Invalid value i2cp.leaseSetPrivKey: ", it->second);
m_LeaseSetPrivKey.reset (nullptr);
}
}
@@ -262,17 +262,6 @@
return nullptr;
}
}
- else
- {
- auto ls = i2p::data::netdb.FindLeaseSet (ident);
- if (ls && !ls->IsExpired ())
- {
- ls->PopulateLeases (); // since we don't store them in netdb
- std::lock_guard<std::mutex> _lock(m_RemoteLeaseSetsMutex);
- m_RemoteLeaseSets[ident] = ls;
- return ls;
- }
- }
return nullptr;
}
@@ -399,6 +388,11 @@
void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len)
{
+ if (len < DATABASE_STORE_HEADER_SIZE)
+ {
+ LogPrint (eLogError, "Destination: Database store msg is too short ", len);
+ return;
+ }
uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET);
size_t offset = DATABASE_STORE_HEADER_SIZE;
if (replyToken)
@@ -406,6 +400,11 @@
LogPrint (eLogInfo, "Destination: Reply token is ignored for DatabaseStore");
offset += 36;
}
+ if (offset > len || len > i2p::data::MAX_LS_BUFFER_SIZE + offset)
+ {
+ LogPrint (eLogError, "Destination: Database store message is too long ", len);
+ return;
+ }
i2p::data::IdentHash key (buf + DATABASE_STORE_KEY_OFFSET);
std::shared_ptr<i2p::data::LeaseSet> leaseSet;
switch (buf[DATABASE_STORE_TYPE_OFFSET])
@@ -467,12 +466,15 @@
{
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset,
it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr , GetPreferredCryptoType ());
- if (ls2->IsValid ())
+ if (ls2->IsValid () && !ls2->IsExpired ())
{
+ leaseSet = ls2;
+ std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key
m_RemoteLeaseSets[key] = ls2; // also store as key for next lookup
- leaseSet = ls2;
}
+ else
+ LogPrint (eLogError, "Destination: New remote encrypted LeaseSet2 failed");
}
else
LogPrint (eLogInfo, "Destination: Couldn't find request for encrypted LeaseSet2");
@@ -622,7 +624,7 @@
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer,
shared_from_this (), std::placeholders::_1));
- outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg);
+ outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0, msg);
m_LastSubmissionTime = ts;
}
@@ -763,9 +765,17 @@
request->requestTime = ts;
if (!SendLeaseSetRequest (dest, floodfill, request))
{
- // request failed
- m_LeaseSetRequests.erase (ret.first);
- if (requestComplete) requestComplete (nullptr);
+ // try another
+ LogPrint (eLogWarning, "Destination: Couldn't send LeaseSet request to ", floodfill->GetIdentHash ().ToBase64 (), ". Trying another");
+ request->excluded.insert (floodfill->GetIdentHash ());
+ floodfill = i2p::data::netdb.GetClosestFloodfill (dest, request->excluded);
+ if (!SendLeaseSetRequest (dest, floodfill, request))
+ {
+ // request failed
+ LogPrint (eLogWarning, "Destination: LeaseSet request for ", dest.ToBase32 (), " was not sent");
+ m_LeaseSetRequests.erase (ret.first);
+ if (requestComplete) requestComplete (nullptr);
+ }
}
}
else // duplicate
@@ -792,11 +802,11 @@
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request)
{
if (!request->replyTunnel || !request->replyTunnel->IsEstablished ())
- request->replyTunnel = m_Pool->GetNextInboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (true));
- if (!request->replyTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no inbound tunnels found");
+ request->replyTunnel = m_Pool->GetNextInboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (false)); // outbound from floodfill
+ if (!request->replyTunnel) LogPrint (eLogWarning, "Destination: Can't send LeaseSet request, no compatible inbound tunnels found");
if (!request->outboundTunnel || !request->outboundTunnel->IsEstablished ())
- request->outboundTunnel = m_Pool->GetNextOutboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (false));
- if (!request->outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no outbound tunnels found");
+ request->outboundTunnel = m_Pool->GetNextOutboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (true)); // inbound from floodfill
+ if (!request->outboundTunnel) LogPrint (eLogWarning, "Destination: Can't send LeaseSet request, no compatible outbound tunnels found");
if (request->replyTunnel && request->outboundTunnel)
{
@@ -814,7 +824,7 @@
AddSessionKey (replyKey, replyTag);
auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest,
request->excluded, request->replyTunnel, replyKey, replyTag, isECIES));
- request->outboundTunnel->SendTunnelDataMsg (
+ request->outboundTunnel->SendTunnelDataMsgs (
{
i2p::tunnel::TunnelMessageBlock
{
@@ -909,7 +919,7 @@
bool isPublic, const std::map<std::string, std::string> * params):
LeaseSetDestination (service, isPublic, params),
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
- m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS),
+ m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0),
m_DatagramDestination (nullptr), m_RefCounter (0),
m_ReadyChecker(service)
{
@@ -979,7 +989,7 @@
m_StreamingAckDelay = std::stoi(it->second);
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
if (it != params->end ())
- m_IsStreamingAnswerPings = (it->second == "true");
+ m_IsStreamingAnswerPings = std::stoi (it->second); // 1 for true
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
{
@@ -993,12 +1003,12 @@
else if (authType == i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK)
ReadAuthKey (I2CP_PARAM_LEASESET_CLIENT_PSK, params);
else
- LogPrint (eLogError, "Destination: Unexpected auth type ", authType);
+ LogPrint (eLogError, "Destination: Unexpected auth type: ", authType);
if (m_AuthKeys->size ())
LogPrint (eLogInfo, "Destination: ", m_AuthKeys->size (), " auth keys read");
else
{
- LogPrint (eLogError, "Destination: No auth keys read for auth type ", authType);
+ LogPrint (eLogCritical, "Destination: No auth keys read for auth type: ", authType);
m_AuthKeys = nullptr;
}
}
@@ -1007,7 +1017,7 @@
}
catch (std::exception & ex)
{
- LogPrint(eLogError, "Destination: Unable to parse parameters for destination: ", ex.what());
+ LogPrint(eLogCritical, "Destination: Unable to parse parameters for destination: ", ex.what());
}
}
@@ -1026,22 +1036,30 @@
void ClientDestination::Stop ()
{
+ LogPrint(eLogDebug, "Destination: Stopping destination ", GetIdentHash().ToBase32(), ".b32.i2p");
LeaseSetDestination::Stop ();
m_ReadyChecker.cancel();
+ LogPrint(eLogDebug, "Destination: -> Stopping Streaming Destination");
m_StreamingDestination->Stop ();
//m_StreamingDestination->SetOwner (nullptr);
m_StreamingDestination = nullptr;
+
+ LogPrint(eLogDebug, "Destination: -> Stopping Streaming Destination by ports");
for (auto& it: m_StreamingDestinationsByPorts)
{
it.second->Stop ();
//it.second->SetOwner (nullptr);
}
m_StreamingDestinationsByPorts.clear ();
+ m_LastStreamingDestination = nullptr;
+
if (m_DatagramDestination)
{
+ LogPrint(eLogDebug, "Destination: -> Stopping Datagram Destination");
delete m_DatagramDestination;
m_DatagramDestination = nullptr;
}
+ LogPrint(eLogDebug, "Destination: -> Stopping done");
}
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
@@ -1061,9 +1079,15 @@
case PROTOCOL_TYPE_STREAMING:
{
// streaming protocol
- auto dest = GetStreamingDestination (toPort);
- if (dest)
- dest->HandleDataMessagePayload (buf, length);
+ if (toPort != m_LastPort || !m_LastStreamingDestination)
+ {
+ m_LastStreamingDestination = GetStreamingDestination (toPort);
+ if (!m_LastStreamingDestination)
+ m_LastStreamingDestination = m_StreamingDestination; // if no destination on port use default
+ m_LastPort = toPort;
+ }
+ if (m_LastStreamingDestination)
+ m_LastStreamingDestination->HandleDataMessagePayload (buf, length);
else
LogPrint (eLogError, "Destination: Missing streaming destination");
}
@@ -1087,7 +1111,7 @@
}
}
- void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port)
+ void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, uint16_t port)
{
if (!streamRequestComplete)
{
@@ -1096,7 +1120,13 @@
}
auto leaseSet = FindLeaseSet (dest);
if (leaseSet)
- streamRequestComplete(CreateStream (leaseSet, port));
+ {
+ auto stream = CreateStream (leaseSet, port);
+ GetService ().post ([streamRequestComplete, stream]()
+ {
+ streamRequestComplete(stream);
+ });
+ }
else
{
auto s = GetSharedFromThis ();
@@ -1111,7 +1141,7 @@
}
}
- void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port)
+ void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port)
{
if (!streamRequestComplete)
{
@@ -1129,7 +1159,42 @@
});
}
- std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port)
+ template<typename Dest>
+ std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStreamSync (const Dest& dest, uint16_t port)
+ {
+ volatile bool done = false;
+ std::shared_ptr<i2p::stream::Stream> stream;
+ std::condition_variable streamRequestComplete;
+ std::mutex streamRequestCompleteMutex;
+ CreateStream (
+ [&done, &streamRequestComplete, &streamRequestCompleteMutex, &stream](std::shared_ptr<i2p::stream::Stream> s)
+ {
+ stream = s;
+ std::unique_lock<std::mutex> l(streamRequestCompleteMutex);
+ streamRequestComplete.notify_all ();
+ done = true;
+ },
+ dest, port);
+ while (!done)
+ {
+ std::unique_lock<std::mutex> l(streamRequestCompleteMutex);
+ if (!done)
+ streamRequestComplete.wait (l);
+ }
+ return stream;
+ }
+
+ std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (const i2p::data::IdentHash& dest, uint16_t port)
+ {
+ return CreateStreamSync (dest, port);
+ }
+
+ std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port)
+ {
+ return CreateStreamSync (dest, port);
+ }
+
+ std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, uint16_t port)
{
if (m_StreamingDestination)
return m_StreamingDestination->CreateNewOutgoingStream (remote, port);
@@ -1166,7 +1231,7 @@
});
}
- std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const
+ std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (uint16_t port) const
{
if (port)
{
@@ -1174,8 +1239,9 @@
if (it != m_StreamingDestinationsByPorts.end ())
return it->second;
}
- // if port is zero or not found, use default destination
- return m_StreamingDestination;
+ else // if port is zero, use default destination
+ return m_StreamingDestination;
+ return nullptr;
}
void ClientDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor)
@@ -1203,7 +1269,7 @@
m_StreamingDestination->AcceptOnce (acceptor);
}
- std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (int port, bool gzip)
+ std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (uint16_t port, bool gzip)
{
auto dest = std::make_shared<i2p::stream::StreamingDestination> (GetSharedFromThis (), port, gzip);
if (port)
@@ -1213,7 +1279,7 @@
return dest;
}
- std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::RemoveStreamingDestination (int port)
+ std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::RemoveStreamingDestination (uint16_t port)
{
if (port)
{
@@ -1274,7 +1340,7 @@
f1.write ((char *)keys->priv, 256);
return;
}
- LogPrint(eLogError, "Destinations: Can't save keys to ", path);
+ LogPrint(eLogCritical, "Destinations: Can't save keys to ", path);
}
void ClientDestination::CreateNewLeaseSet (const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels)
@@ -1351,7 +1417,7 @@
if (pubKey.FromBase64 (it.second.substr (pos+1)))
m_AuthKeys->push_back (pubKey);
else
- LogPrint (eLogError, "Destination: Unexpected auth key ", it.second.substr (pos+1));
+ LogPrint (eLogCritical, "Destination: Unexpected auth key: ", it.second.substr (pos+1));
}
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Destination.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -14,6 +14,7 @@
#include <mutex>
#include <memory>
#include <map>
+#include <unordered_map>
#include <set>
#include <string>
#include <functional>
@@ -184,8 +185,8 @@
boost::asio::io_service& m_Service;
mutable std::mutex m_RemoteLeaseSetsMutex;
- std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
- std::map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
+ std::unordered_map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
+ std::unordered_map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
std::mutex m_LeaseSetMutex;
@@ -241,13 +242,15 @@
int GetRefCounter () const { return m_RefCounter; };
// streaming
- std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
- std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
- std::shared_ptr<i2p::stream::StreamingDestination> RemoveStreamingDestination (int port);
+ std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (uint16_t port, bool gzip = true); // additional
+ std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (uint16_t port = 0) const;
+ std::shared_ptr<i2p::stream::StreamingDestination> RemoveStreamingDestination (uint16_t port);
// following methods operate with default streaming destination
- void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0);
- void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0);
- std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
+ void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, uint16_t port = 0);
+ void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port = 0);
+ std::shared_ptr<i2p::stream::Stream> CreateStream (const i2p::data::IdentHash& dest, uint16_t port = 0); // sync
+ std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port = 0); // sync
+ std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, uint16_t port = 0);
void SendPing (const i2p::data::IdentHash& to);
void SendPing (std::shared_ptr<const i2p::data::BlindedPublicKey> to);
void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor);
@@ -282,6 +285,9 @@
void PersistTemporaryKeys (EncryptionKey * keys, bool isSingleKey);
void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params);
+ template<typename Dest>
+ std::shared_ptr<i2p::stream::Stream> CreateStreamSync (const Dest& dest, uint16_t port);
+
private:
i2p::data::PrivateKeys m_Keys;
@@ -292,6 +298,7 @@
bool m_IsStreamingAnswerPings;
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
+ std::shared_ptr<i2p::stream::StreamingDestination> m_LastStreamingDestination; uint16_t m_LastPort; // for server tunnels
i2p::datagram::DatagramDestination * m_DatagramDestination;
int m_RefCounter; // how many clients(tunnels) use this destination
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/ECIESX25519AEADRatchetSession.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -335,7 +335,8 @@
case eECIESx25519BlkAckRequest:
{
LogPrint (eLogDebug, "Garlic: Ack request");
- m_AckRequests.push_back ({receiveTagset->GetTagSetID (), index});
+ if (receiveTagset)
+ m_AckRequests.push_back ({receiveTagset->GetTagSetID (), index});
break;
}
case eECIESx25519BlkTermination:
@@ -1149,7 +1150,7 @@
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag)
{
- auto m = NewI2NPMessage ();
+ auto m = NewI2NPMessage ((msg ? msg->GetPayloadLength () : 0) + 128);
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
size_t offset = 0;
@@ -1175,7 +1176,7 @@
// Noise_N, we are Alice, routerPublicKey is Bob's
i2p::crypto::NoiseSymmetricState noiseState;
i2p::crypto::InitNoiseNState (noiseState, routerPublicKey);
- auto m = NewI2NPMessage ();
+ auto m = NewI2NPMessage ((msg ? msg->GetPayloadLength () : 0) + 128);
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
size_t offset = 0;
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Ed25519.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -413,7 +413,7 @@
BIGNUM * y = BN_new ();
BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y);
BIGNUM * x = RecoverX (y, ctx);
- if (BN_is_bit_set (x, 0) != isHighestBitSet)
+ if ((bool)BN_is_bit_set (x, 0) != isHighestBitSet)
BN_sub (x, q, x); // x = q - x
BIGNUM * z = BN_new (), * t = BN_new ();
BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/FS.cpp
^
|
@@ -136,6 +136,14 @@
dataDir = (home != NULL && strlen(home) > 0) ? home : "";
dataDir += "/Library/Application Support/" + appName;
return;
+#elif defined(__HAIKU__)
+ char *home = getenv("HOME");
+ if (home != NULL && strlen(home) > 0) {
+ dataDir = std::string(home) + "/config/settings/" + appName;
+ } else {
+ dataDir = "/tmp/" + appName;
+ }
+ return;
#else /* other unix */
#if defined(ANDROID)
const char * ext = getenv("EXTERNAL_STORAGE");
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Family.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -88,7 +88,7 @@
}
EVP_PKEY_free (pkey);
if (verifier && cn)
- m_SigningKeys.emplace (cn, std::make_pair(verifier, m_SigningKeys.size () + 1));
+ m_SigningKeys.emplace (cn, std::make_pair(verifier, (int)m_SigningKeys.size () + 1));
}
SSL_free (ssl);
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Garlic.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -588,7 +588,7 @@
auto it = m_ECIESx25519Tags.find (tag);
if (it != m_ECIESx25519Tags.end ())
{
- if (it->second.tagset->HandleNextMessage (buf, len, it->second.index))
+ if (it->second.tagset && it->second.tagset->HandleNextMessage (buf, len, it->second.index))
m_LastTagset = it->second.tagset;
else
LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
@@ -709,7 +709,7 @@
else
LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel");
if (tunnel) // we have sent it through an outbound tunnel
- tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg);
+ tunnel->SendTunnelDataMsgTo (gwHash, gwTunnel, msg);
else
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
}
@@ -1075,7 +1075,7 @@
{
auto tunnel = GetTunnelPool ()->GetNextOutboundTunnel ();
if (tunnel)
- tunnel->SendTunnelDataMsg (gwHash, gwTunnel, CreateI2NPMessage (typeID, buf, len - offset, msgID));
+ tunnel->SendTunnelDataMsgTo (gwHash, gwTunnel, CreateI2NPMessage (typeID, buf, len - offset, msgID));
else
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Gzip.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -57,7 +57,8 @@
if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END)
return outLen - m_Inflator.avail_out;
// else
- LogPrint (eLogError, "Gzip: Inflate error ", err);
+ if (err)
+ LogPrint (eLogError, "Gzip: Inflate error ", err);
return 0;
}
}
@@ -128,7 +129,8 @@
return outLen - m_Deflator.avail_out;
}
// else
- LogPrint (eLogError, "Gzip: Deflate error ", err);
+ if (err)
+ LogPrint (eLogError, "Gzip: Deflate error ", err);
return 0;
}
@@ -137,7 +139,7 @@
if (m_IsDirty) deflateReset (&m_Deflator);
m_IsDirty = true;
size_t offset = 0;
- int err;
+ int err = 0;
for (const auto& it: bufs)
{
m_Deflator.next_in = const_cast<uint8_t *>(it.first);
@@ -158,7 +160,8 @@
offset = outLen - m_Deflator.avail_out;
}
// else
- LogPrint (eLogError, "Gzip: Deflate error ", err);
+ if (err)
+ LogPrint (eLogError, "Gzip: Deflate error ", err);
return 0;
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/HTTP.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -93,15 +93,18 @@
std::size_t pos_c = 0; /* < work position */
if(url.at(0) != '/' || pos_p > 0) {
std::size_t pos_s = 0;
+
/* schema */
pos_c = url.find("://");
if (pos_c != std::string::npos) {
schema = url.substr(0, pos_c);
pos_p = pos_c + 3;
}
+
/* user[:pass] */
pos_s = url.find('/', pos_p); /* find first slash */
pos_c = url.find('@', pos_p); /* find end of 'user' or 'user:pass' part */
+
if (pos_c != std::string::npos && (pos_s == std::string::npos || pos_s > pos_c)) {
std::size_t delim = url.find(':', pos_p);
if (delim && delim != std::string::npos && delim < pos_c) {
@@ -113,21 +116,28 @@
}
pos_p = pos_c + 1;
}
+
/* hostname[:port][/path] */
- if (url[pos_p] == '[') // ipv6
+ if (url.at(pos_p) == '[') // ipv6
{
auto pos_b = url.find(']', pos_p);
if (pos_b == std::string::npos) return false;
+ ipv6 = true;
pos_c = url.find_first_of(":/", pos_b);
}
else
pos_c = url.find_first_of(":/", pos_p);
+
if (pos_c == std::string::npos) {
/* only hostname, without post and path */
- host = url.substr(pos_p, std::string::npos);
+ host = ipv6 ?
+ url.substr(pos_p + 1, url.length() - 1) :
+ url.substr(pos_p, std::string::npos);
return true;
} else if (url.at(pos_c) == ':') {
- host = url.substr(pos_p, pos_c - pos_p);
+ host = ipv6 ?
+ url.substr(pos_p + 1, pos_c - pos_p - 2) :
+ url.substr(pos_p, pos_c - pos_p);
/* port[/path] */
pos_p = pos_c + 1;
pos_c = url.find('/', pos_p);
@@ -135,6 +145,7 @@
? url.substr(pos_p, std::string::npos)
: url.substr(pos_p, pos_c - pos_p);
/* stoi throws exception on failure, we don't need it */
+ port = 0;
for (char c : port_str) {
if (c < '0' || c > '9')
return false;
@@ -146,7 +157,9 @@
pos_p = pos_c;
} else {
/* start of path part found */
- host = url.substr(pos_p, pos_c - pos_p);
+ host = ipv6 ?
+ url.substr(pos_p + 1, pos_c - pos_p - 2) :
+ url.substr(pos_p, pos_c - pos_p);
pos_p = pos_c;
}
}
@@ -159,6 +172,7 @@
return true;
} else if (url.at(pos_c) == '?') {
/* found query part */
+ hasquery = true;
path = url.substr(pos_p, pos_c - pos_p);
pos_p = pos_c + 1;
pos_c = url.find('#', pos_p);
@@ -210,15 +224,25 @@
} else if (user != "") {
out += user + "@";
}
- if (port) {
- out += host + ":" + std::to_string(port);
+ if (ipv6) {
+ if (port) {
+ out += "[" + host + "]:" + std::to_string(port);
+ } else {
+ out += "[" + host + "]";
+ }
} else {
- out += host;
+ if (port) {
+ out += host + ":" + std::to_string(port);
+ } else {
+ out += host;
+ }
}
}
out += path;
+ if (hasquery) // add query even if it was empty
+ out += "?";
if (query != "")
- out += "?" + query;
+ out += query;
if (frag != "")
out += "#" + frag;
return out;
@@ -346,6 +370,14 @@
return "";
}
+ size_t HTTPReq::GetNumHeaders (const std::string& name) const
+ {
+ size_t num = 0;
+ for (auto& it : headers)
+ if (it.first == name) num++;
+ return num;
+ }
+
bool HTTPRes::is_chunked() const
{
auto it = headers.find("Transfer-Encoding");
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/HTTP.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -33,10 +33,12 @@
std::string host;
unsigned short int port;
std::string path;
+ bool hasquery;
std::string query;
std::string frag;
+ bool ipv6;
- URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), query(""), frag("") {};
+ URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), hasquery(false), query(""), frag(""), ipv6(false) {};
/**
* @brief Tries to parse url from string
@@ -101,6 +103,8 @@
void RemoveHeader (const std::string& name, const std::string& exempt); // remove all headers starting with name, but exempt
void RemoveHeader (const std::string& name) { RemoveHeader (name, ""); };
std::string GetHeader (const std::string& name) const;
+ size_t GetNumHeaders (const std::string& name) const;
+ size_t GetNumHeaders () const { return headers.size (); };
};
struct HTTPRes : HTTPMsg {
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/I2NPProtocol.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -36,6 +36,11 @@
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >();
}
+ std::shared_ptr<I2NPMessage> NewI2NPMediumMessage ()
+ {
+ return std::make_shared<I2NPMessageBuffer<I2NP_MAX_MEDIUM_MESSAGE_SIZE> >();
+ }
+
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint)
{
return i2p::tunnel::tunnels.NewI2NPTunnelMessage (endpoint);
@@ -43,7 +48,10 @@
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len)
{
- return (len < I2NP_MAX_SHORT_MESSAGE_SIZE - I2NP_HEADER_SIZE - 2) ? NewI2NPShortMessage () : NewI2NPMessage ();
+ len += I2NP_HEADER_SIZE + 2;
+ if (len <= I2NP_MAX_SHORT_MESSAGE_SIZE) return NewI2NPShortMessage ();
+ if (len <= I2NP_MAX_MEDIUM_MESSAGE_SIZE) return NewI2NPMediumMessage ();
+ return NewI2NPMessage ();
}
void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID, bool checksum)
@@ -126,7 +134,8 @@
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers)
{
- auto m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage ();
+ int cnt = excludedPeers ? excludedPeers->size () : 0;
+ auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage ();
uint8_t * buf = m->GetPayload ();
memcpy (buf, key, 32); // key
buf += 32;
@@ -147,7 +156,6 @@
if (excludedPeers)
{
- int cnt = excludedPeers->size ();
htobe16buf (buf, cnt);
buf += 2;
for (auto& it: *excludedPeers)
@@ -353,21 +361,6 @@
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
}
- static uint16_t g_MaxNumTransitTunnels = DEFAULT_MAX_NUM_TRANSIT_TUNNELS; // TODO:
- void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels)
- {
- if (maxNumTransitTunnels > 0 && g_MaxNumTransitTunnels != maxNumTransitTunnels)
- {
- LogPrint (eLogDebug, "I2NP: Max number of transit tunnels set to ", maxNumTransitTunnels);
- g_MaxNumTransitTunnels = maxNumTransitTunnels;
- }
- }
-
- uint16_t GetMaxNumTransitTunnels ()
- {
- return g_MaxNumTransitTunnels;
- }
-
static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
{
for (int i = 0; i < num; i++)
@@ -379,10 +372,7 @@
if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false;
uint8_t retCode = 0;
// replace record to reply
- if (i2p::context.AcceptsTunnels () &&
- i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels &&
- !i2p::transport::transports.IsBandwidthExceeded () &&
- !i2p::transport::transports.IsTransitBandwidthExceeded ())
+ if (i2p::context.AcceptsTunnels () && !i2p::context.IsHighCongestion ())
{
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
@@ -392,7 +382,8 @@
clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG,
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
- i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel);
+ if (!i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel))
+ retCode = 30;
}
else
retCode = 30; // always reject with bandwidth reason (30)
@@ -433,6 +424,11 @@
{
int num = buf[0];
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
+ if (num > i2p::tunnel::MAX_NUM_RECORDS)
+ {
+ LogPrint (eLogError, "I2NP: Too many records in VaribleTunnelBuild message ", num);
+ return;
+ }
if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1)
{
LogPrint (eLogError, "I2NP: VaribleTunnelBuild message of ", num, " records is too short ", len);
@@ -486,6 +482,11 @@
{
int num = buf[0];
LogPrint (eLogDebug, "I2NP: TunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID);
+ if (num > i2p::tunnel::MAX_NUM_RECORDS)
+ {
+ LogPrint (eLogError, "I2NP: Too many records in TunnelBuildReply message ", num);
+ return;
+ }
size_t recordSize = isShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE;
if (len < num*recordSize + 1)
{
@@ -517,6 +518,11 @@
{
int num = buf[0];
LogPrint (eLogDebug, "I2NP: ShortTunnelBuild ", num, " records");
+ if (num > i2p::tunnel::MAX_NUM_RECORDS)
+ {
+ LogPrint (eLogError, "I2NP: Too many records in ShortTunnelBuild message ", num);
+ return;
+ }
if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1)
{
LogPrint (eLogError, "I2NP: ShortTunnelBuild message of ", num, " records is too short ", len);
@@ -558,7 +564,8 @@
return;
}
auto& noiseState = i2p::context.GetCurrentNoiseState ();
- uint8_t replyKey[32], layerKey[32], ivKey[32];
+ uint8_t replyKey[32]; // AEAD/Chacha20/Poly1305
+ i2p::crypto::AESKey layerKey, ivKey; // AES
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelReplyKey", noiseState.m_CK);
memcpy (replyKey, noiseState.m_CK + 32, 32);
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK);
@@ -574,11 +581,8 @@
// check if we accept this tunnel
uint8_t retCode = 0;
- if (!i2p::context.AcceptsTunnels () ||
- i2p::tunnel::tunnels.GetTransitTunnels ().size () > g_MaxNumTransitTunnels ||
- i2p::transport::transports.IsBandwidthExceeded () ||
- i2p::transport::transports.IsTransitBandwidthExceeded ())
- retCode = 30;
+ if (!i2p::context.AcceptsTunnels () || i2p::context.IsHighCongestion ())
+ retCode = 30;
if (!retCode)
{
// create new transit tunnel
@@ -589,7 +593,8 @@
layerKey, ivKey,
clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG,
clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
- i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel);
+ if (!i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel))
+ retCode = 30;
}
// encrypt reply
@@ -743,46 +748,38 @@
return l;
}
- void HandleI2NPMessage (uint8_t * msg, size_t len)
+ void HandleTunnelBuildI2NPMessage (std::shared_ptr<I2NPMessage> msg)
{
- if (len < I2NP_HEADER_SIZE)
+ if (msg)
{
- LogPrint (eLogError, "I2NP: Message length ", len, " is smaller than header");
- return;
- }
- uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET];
- uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET);
- LogPrint (eLogDebug, "I2NP: Msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
- uint8_t * buf = msg + I2NP_HEADER_SIZE;
- auto size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET);
- len -= I2NP_HEADER_SIZE;
- if (size > len)
- {
- LogPrint (eLogError, "I2NP: Payload size ", size, " exceeds buffer length ", len);
- size = len;
- }
- switch (typeID)
- {
- case eI2NPVariableTunnelBuild:
- HandleVariableTunnelBuildMsg (msgID, buf, size);
- break;
- case eI2NPShortTunnelBuild:
- HandleShortTunnelBuildMsg (msgID, buf, size);
- break;
- case eI2NPVariableTunnelBuildReply:
- HandleTunnelBuildReplyMsg (msgID, buf, size, false);
- break;
- case eI2NPShortTunnelBuildReply:
- HandleTunnelBuildReplyMsg (msgID, buf, size, true);
- break;
- case eI2NPTunnelBuild:
- HandleTunnelBuildMsg (buf, size);
- break;
- case eI2NPTunnelBuildReply:
- // TODO:
- break;
- default:
- LogPrint (eLogWarning, "I2NP: Unexpected message ", (int)typeID);
+ uint8_t typeID = msg->GetTypeID();
+ uint32_t msgID = msg->GetMsgID();
+ LogPrint (eLogDebug, "I2NP: Handling tunnel build message with len=", msg->GetLength(),", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
+ uint8_t * payload = msg->GetPayload();
+ auto size = msg->GetPayloadLength();
+ switch (typeID)
+ {
+ case eI2NPVariableTunnelBuild:
+ HandleVariableTunnelBuildMsg (msgID, payload, size);
+ break;
+ case eI2NPShortTunnelBuild:
+ HandleShortTunnelBuildMsg (msgID, payload, size);
+ break;
+ case eI2NPVariableTunnelBuildReply:
+ HandleTunnelBuildReplyMsg (msgID, payload, size, false);
+ break;
+ case eI2NPShortTunnelBuildReply:
+ HandleTunnelBuildReplyMsg (msgID, payload, size, true);
+ break;
+ case eI2NPTunnelBuild:
+ HandleTunnelBuildMsg (payload, size);
+ break;
+ case eI2NPTunnelBuildReply:
+ // TODO:
+ break;
+ default:
+ LogPrint (eLogError, "I2NP: Unexpected message with type", (int)typeID, " during handling TBM; skipping");
+ }
}
}
@@ -795,10 +792,12 @@
switch (typeID)
{
case eI2NPTunnelData:
- i2p::tunnel::tunnels.PostTunnelData (msg);
+ if (!msg->from)
+ i2p::tunnel::tunnels.PostTunnelData (msg);
break;
case eI2NPTunnelGateway:
- i2p::tunnel::tunnels.PostTunnelData (msg);
+ if (!msg->from)
+ i2p::tunnel::tunnels.PostTunnelData (msg);
break;
case eI2NPGarlic:
{
@@ -809,10 +808,16 @@
break;
}
case eI2NPDatabaseStore:
- case eI2NPDatabaseSearchReply:
+ case eI2NPDatabaseSearchReply:
+ // forward to netDb if came directly or through exploratory tunnel as response to our request
+ if (!msg->from || !msg->from->GetTunnelPool () || msg->from->GetTunnelPool ()->IsExploratory ())
+ i2p::data::netdb.PostI2NPMsg (msg);
+ break;
+
case eI2NPDatabaseLookup:
- // forward to netDb
- i2p::data::netdb.PostI2NPMsg (msg);
+ // forward to netDb if floodfill and came directly
+ if (!msg->from && i2p::context.IsFloodfill ())
+ i2p::data::netdb.PostI2NPMsg (msg);
break;
case eI2NPDeliveryStatus:
{
@@ -823,16 +828,20 @@
break;
}
case eI2NPVariableTunnelBuild:
- case eI2NPVariableTunnelBuildReply:
case eI2NPTunnelBuild:
- case eI2NPTunnelBuildReply:
case eI2NPShortTunnelBuild:
+ // forward to tunnel thread
+ if (!msg->from)
+ i2p::tunnel::tunnels.PostTunnelData (msg);
+ break;
+ case eI2NPVariableTunnelBuildReply:
+ case eI2NPTunnelBuildReply:
case eI2NPShortTunnelBuildReply:
// forward to tunnel thread
i2p::tunnel::tunnels.PostTunnelData (msg);
break;
default:
- HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
+ LogPrint(eLogError, "I2NP: Unexpected I2NP message with type ", int(typeID), " during handling; skipping");
}
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/I2NPProtocol.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -140,6 +140,7 @@
const size_t I2NP_MAX_MESSAGE_SIZE = 62708;
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096;
+ const size_t I2NP_MAX_MEDIUM_MESSAGE_SIZE = 16384;
const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT)
const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds
@@ -262,6 +263,7 @@
std::shared_ptr<I2NPMessage> NewI2NPMessage ();
std::shared_ptr<I2NPMessage> NewI2NPShortMessage ();
+ std::shared_ptr<I2NPMessage> NewI2NPMediumMessage ();
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint);
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len);
@@ -293,7 +295,7 @@
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
size_t GetI2NPMessageLength (const uint8_t * msg, size_t len);
- void HandleI2NPMessage (uint8_t * msg, size_t len);
+ void HandleTunnelBuildI2NPMessage (std::shared_ptr<I2NPMessage> msg);
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg);
class I2NPMessagesHandler
@@ -308,10 +310,6 @@
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs;
};
-
- const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 2500;
- void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
- uint16_t GetMaxNumTransitTunnels ();
}
#endif
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/I2PEndian.h
^
|
@@ -14,7 +14,7 @@
#if defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/endian.h>
-#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__GLIBC__)
+#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__GLIBC__) || defined(__HAIKU__)
#include <endian.h>
#elif defined(__APPLE__) && defined(__MACH__)
@@ -36,6 +36,23 @@
#define le64toh(x) OSSwapLittleToHostInt64(x)
#elif defined(_WIN32)
+#if defined(_MSC_VER)
+#include <stdlib.h>
+#define htobe16(x) _byteswap_ushort(x)
+#define htole16(x) (x)
+#define be16toh(x) _byteswap_ushort(x)
+#define le16toh(x) (x)
+
+#define htobe32(x) _byteswap_ulong(x)
+#define htole32(x) (x)
+#define be32toh(x) _byteswap_ulong(x)
+#define le32toh(x) (x)
+
+#define htobe64(x) _byteswap_uint64(x)
+#define htole64(x) (x)
+#define be64toh(x) _byteswap_uint64(x)
+#define le64toh(x) (x)
+#else
#define htobe16(x) __builtin_bswap16(x)
#define htole16(x) (x)
#define be16toh(x) __builtin_bswap16(x)
@@ -50,6 +67,7 @@
#define htole64(x) (x)
#define be64toh(x) __builtin_bswap64(x)
#define le64toh(x) (x)
+#endif
#else
#define NEEDS_LOCAL_ENDIAN
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Identity.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -49,13 +49,22 @@
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType)
{
+ uint8_t randomPaddingBlock[32];
+ RAND_bytes (randomPaddingBlock, 32);
if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
{
- memcpy (m_StandardIdentity.publicKey, publicKey, 32);
- RAND_bytes (m_StandardIdentity.publicKey + 32, 224);
+ memcpy (m_StandardIdentity.publicKey, publicKey ? publicKey : randomPaddingBlock, 32);
+ for (int i = 0; i < 7; i++) // 224 bytes
+ memcpy (m_StandardIdentity.publicKey + 32*(i + 1), randomPaddingBlock, 32);
}
else
- memcpy (m_StandardIdentity.publicKey, publicKey, 256);
+ {
+ if (publicKey)
+ memcpy (m_StandardIdentity.publicKey, publicKey, 256);
+ else
+ for (int i = 0; i < 8; i++) // 256 bytes
+ memcpy (m_StandardIdentity.publicKey + 32*i, randomPaddingBlock, 32);
+ }
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{
size_t excessLen = 0;
@@ -93,7 +102,8 @@
case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
{
size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32
- RAND_bytes (m_StandardIdentity.signingKey, padding);
+ for (int i = 0; i < 3; i++) // 96 bytes
+ memcpy (m_StandardIdentity.signingKey + 32*i, randomPaddingBlock, 32);
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH);
break;
}
@@ -177,7 +187,6 @@
IdentityEx::~IdentityEx ()
{
- delete m_Verifier;
}
IdentityEx& IdentityEx::operator=(const IdentityEx& other)
@@ -191,9 +200,8 @@
if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE;
memcpy (m_ExtendedBuffer, other.m_ExtendedBuffer, m_ExtendedLen);
}
-
- delete m_Verifier;
m_Verifier = nullptr;
+ CreateVerifier ();
return *this;
}
@@ -202,11 +210,10 @@
{
m_StandardIdentity = standard;
m_IdentHash = m_StandardIdentity.Hash ();
-
m_ExtendedLen = 0;
- delete m_Verifier;
m_Verifier = nullptr;
+ CreateVerifier ();
return *this;
}
@@ -239,8 +246,8 @@
m_ExtendedLen = 0;
SHA256(buf, GetFullLen (), m_IdentHash);
- delete m_Verifier;
m_Verifier = nullptr;
+ CreateVerifier ();
return GetFullLen ();
}
@@ -276,7 +283,6 @@
size_t IdentityEx::GetSigningPublicKeyLen () const
{
- if (!m_Verifier) CreateVerifier ();
if (m_Verifier)
return m_Verifier->GetPublicKeyLen ();
return 128;
@@ -291,7 +297,6 @@
size_t IdentityEx::GetSigningPrivateKeyLen () const
{
- if (!m_Verifier) CreateVerifier ();
if (m_Verifier)
return m_Verifier->GetPrivateKeyLen ();
return GetSignatureLen ()/2;
@@ -299,14 +304,12 @@
size_t IdentityEx::GetSignatureLen () const
{
- if (!m_Verifier) CreateVerifier ();
if (m_Verifier)
return m_Verifier->GetSignatureLen ();
return i2p::crypto::DSA_SIGNATURE_LENGTH;
}
bool IdentityEx::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
- if (!m_Verifier) CreateVerifier ();
if (m_Verifier)
return m_Verifier->Verify (buf, len, signature);
return false;
@@ -363,52 +366,29 @@
return nullptr;
}
- void IdentityEx::CreateVerifier () const
+ void IdentityEx::CreateVerifier ()
{
- if (m_Verifier) return; // don't create again
- auto verifier = CreateVerifier (GetSigningKeyType ());
- if (verifier)
+ if (!m_Verifier)
{
- auto keyLen = verifier->GetPublicKeyLen ();
- if (keyLen <= 128)
- verifier->SetPublicKey (m_StandardIdentity.signingKey + 128 - keyLen);
- else
+ auto verifier = CreateVerifier (GetSigningKeyType ());
+ if (verifier)
{
- // for P521
- uint8_t * signingKey = new uint8_t[keyLen];
- memcpy (signingKey, m_StandardIdentity.signingKey, 128);
- size_t excessLen = keyLen - 128;
- memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
- verifier->SetPublicKey (signingKey);
- delete[] signingKey;
+ auto keyLen = verifier->GetPublicKeyLen ();
+ if (keyLen <= 128)
+ verifier->SetPublicKey (m_StandardIdentity.signingKey + 128 - keyLen);
+ else
+ {
+ // for P521
+ uint8_t * signingKey = new uint8_t[keyLen];
+ memcpy (signingKey, m_StandardIdentity.signingKey, 128);
+ size_t excessLen = keyLen - 128;
+ memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
+ verifier->SetPublicKey (signingKey);
+ delete[] signingKey;
+ }
}
+ m_Verifier.reset (verifier);
}
- UpdateVerifier (verifier);
- }
-
- void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const
- {
- bool del = false;
- {
- std::lock_guard<std::mutex> l(m_VerifierMutex);
- if (!m_Verifier)
- m_Verifier = verifier;
- else
- del = true;
- }
- if (del)
- delete verifier;
- }
-
- void IdentityEx::DropVerifier () const
- {
- i2p::crypto::Verifier * verifier;
- {
- std::lock_guard<std::mutex> l(m_VerifierMutex);
- verifier = m_Verifier;
- m_Verifier = nullptr;
- }
- delete verifier;
}
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (CryptoKeyType keyType, const uint8_t * key)
@@ -601,7 +581,7 @@
if (keyType == SIGNING_KEY_TYPE_DSA_SHA1)
m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey));
else if (keyType == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 && !IsOfflineSignature ())
- m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); // TODO: remove public key check
+ m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey + (sizeof(Identity::signingKey) - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH))); // TODO: remove public key check
else
{
// public key is not required
@@ -695,7 +675,7 @@
return nullptr;
}
- PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type, CryptoKeyType cryptoType)
+ PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type, CryptoKeyType cryptoType, bool isDestination)
{
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{
@@ -705,9 +685,12 @@
GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, signingPublicKey);
// encryption
uint8_t publicKey[256];
- GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey);
+ if (isDestination)
+ RAND_bytes (keys.m_PrivateKey, 256);
+ else
+ GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey);
// identity
- keys.m_Public = std::make_shared<IdentityEx> (publicKey, signingPublicKey, type, cryptoType);
+ keys.m_Public = std::make_shared<IdentityEx> (isDestination ? nullptr : publicKey, signingPublicKey, type, cryptoType);
keys.CreateSigner ();
return keys;
@@ -820,29 +803,12 @@
XORMetric operator^(const IdentHash& key1, const IdentHash& key2)
{
XORMetric m;
-#if (defined(__x86_64__) || defined(__i386__)) && defined(__AVX__) // not all X86 targets supports AVX (like old Pentium, see #1600)
- if(i2p::cpu::avx)
- {
- __asm__
- (
- "vmovups %1, %%ymm0 \n"
- "vmovups %2, %%ymm1 \n"
- "vxorps %%ymm0, %%ymm1, %%ymm1 \n"
- "vmovups %%ymm1, %0 \n"
- : "=m"(*m.metric)
- : "m"(*key1), "m"(*key2)
- : "memory", "%xmm0", "%xmm1" // should be replaced by %ymm0/1 once supported by compiler
- );
- }
- else
-#endif
- {
- const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL ();
- m.metric_ll[0] = hash1[0] ^ hash2[0];
- m.metric_ll[1] = hash1[1] ^ hash2[1];
- m.metric_ll[2] = hash1[2] ^ hash2[2];
- m.metric_ll[3] = hash1[3] ^ hash2[3];
- }
+
+ const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL ();
+ m.metric_ll[0] = hash1[0] ^ hash2[0];
+ m.metric_ll[1] = hash1[1] ^ hash2[1];
+ m.metric_ll[2] = hash1[2] ^ hash2[2];
+ m.metric_ll[3] = hash1[3] ^ hash2[3];
return m;
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Identity.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -13,9 +13,7 @@
#include <string.h>
#include <string>
#include <memory>
-#include <atomic>
#include <vector>
-#include <mutex>
#include "Base.h"
#include "Signature.h"
#include "CryptoKey.h"
@@ -118,7 +116,6 @@
SigningKeyType GetSigningKeyType () const;
bool IsRSA () const; // signing key type
CryptoKeyType GetCryptoKeyType () const;
- void DropVerifier () const; // to save memory
bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); }
void RecalculateIdentHash(uint8_t * buff=nullptr);
@@ -128,15 +125,13 @@
private:
- void CreateVerifier () const;
- void UpdateVerifier (i2p::crypto::Verifier * verifier) const;
-
+ void CreateVerifier ();
+
private:
Identity m_StandardIdentity;
IdentHash m_IdentHash;
- mutable i2p::crypto::Verifier * m_Verifier = nullptr;
- mutable std::mutex m_VerifierMutex;
+ std::unique_ptr<i2p::crypto::Verifier> m_Verifier;
size_t m_ExtendedLen;
uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE];
};
@@ -171,7 +166,7 @@
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (const uint8_t * key) const;
static std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key);
- static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL);
+ static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL, bool isDestination = false);
static void GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub);
static void GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub); // priv and pub are 256 bytes long
static i2p::crypto::Signer * CreateSigner (SigningKeyType keyType, const uint8_t * priv);
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/KadDHT.cpp
^
|
@@ -0,0 +1,372 @@
+/*
+* Copyright (c) 2023, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*
+*/
+
+#include "KadDHT.h"
+
+namespace i2p
+{
+namespace data
+{
+ DHTNode::DHTNode ():
+ zero (nullptr), one (nullptr)
+ {
+ }
+
+ DHTNode::~DHTNode ()
+ {
+ if (zero) delete zero;
+ if (one) delete one;
+ }
+
+ void DHTNode::MoveRouterUp (bool fromOne)
+ {
+ DHTNode *& side = fromOne ? one : zero;
+ if (side)
+ {
+ if (router) router = nullptr; // shouldn't happen
+ router = side->router;
+ side->router = nullptr;
+ delete side;
+ side = nullptr;
+ }
+ }
+
+ DHTTable::DHTTable ():
+ m_Size (0)
+ {
+ m_Root = new DHTNode;
+ }
+
+ DHTTable::~DHTTable ()
+ {
+ delete m_Root;
+ }
+
+ void DHTTable::Clear ()
+ {
+ m_Size = 0;
+ delete m_Root;
+ m_Root = new DHTNode;
+ }
+
+ void DHTTable::Insert (const std::shared_ptr<RouterInfo>& r)
+ {
+ if (!r) return;
+ return Insert (r, m_Root, 0);
+ }
+
+ void DHTTable::Insert (const std::shared_ptr<RouterInfo>& r, DHTNode * root, int level)
+ {
+ if (root->router)
+ {
+ if (root->router->GetIdentHash () == r->GetIdentHash ())
+ {
+ root->router = r; // replace
+ return;
+ }
+ auto r2 = root->router;
+ root->router = nullptr; m_Size--;
+ int bit1, bit2;
+ do
+ {
+ bit1 = r->GetIdentHash ().GetBit (level);
+ bit2 = r2->GetIdentHash ().GetBit (level);
+ if (bit1 == bit2)
+ {
+ if (bit1)
+ {
+ if (root->one) return; // something wrong
+ root->one = new DHTNode;
+ root = root->one;
+ }
+ else
+ {
+ if (root->zero) return; // something wrong
+ root->zero = new DHTNode;
+ root = root->zero;
+ }
+ level++;
+ }
+ }
+ while (bit1 == bit2);
+
+ if (!root->zero)
+ root->zero = new DHTNode;
+ if (!root->one)
+ root->one = new DHTNode;
+ if (bit1)
+ {
+ Insert (r2, root->zero, level + 1);
+ Insert (r, root->one, level + 1);
+ }
+ else
+ {
+ Insert (r2, root->one, level + 1);
+ Insert (r, root->zero, level + 1);
+ }
+ }
+ else
+ {
+ if (!root->zero && !root->one)
+ {
+ root->router = r; m_Size++;
+ return;
+ }
+ int bit = r->GetIdentHash ().GetBit (level);
+ if (bit)
+ {
+ if (!root->one)
+ root->one = new DHTNode;
+ Insert (r, root->one, level + 1);
+ }
+ else
+ {
+ if (!root->zero)
+ root->zero = new DHTNode;
+ Insert (r, root->zero, level + 1);
+ }
+ }
+ }
+
+ bool DHTTable::Remove (const IdentHash& h)
+ {
+ return Remove (h, m_Root, 0);
+ }
+
+ bool DHTTable::Remove (const IdentHash& h, DHTNode * root, int level)
+ {
+ if (root)
+ {
+ if (root->router && root->router->GetIdentHash () == h)
+ {
+ root->router = nullptr;
+ m_Size--;
+ return true;
+ }
+ int bit = h.GetBit (level);
+ if (bit)
+ {
+ if (root->one && Remove (h, root->one, level + 1))
+ {
+ if (root->one->IsEmpty ())
+ {
+ delete root->one;
+ root->one = nullptr;
+ if (root->zero && root->zero->router)
+ root->MoveRouterUp (false);
+ }
+ else if (root->one->router && !root->zero)
+ root->MoveRouterUp (true);
+ return true;
+ }
+ }
+ else
+ {
+ if (root->zero && Remove (h, root->zero, level + 1))
+ {
+ if (root->zero->IsEmpty ())
+ {
+ delete root->zero;
+ root->zero = nullptr;
+ if (root->one && root->one->router)
+ root->MoveRouterUp (true);
+ }
+ else if (root->zero->router && !root->one)
+ root->MoveRouterUp (false);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, const Filter& filter) const
+ {
+ if (filter) m_Filter = filter;
+ auto r = FindClosest (h, m_Root, 0);
+ m_Filter = nullptr;
+ return r;
+ }
+
+ std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, DHTNode * root, int level) const
+ {
+ bool split = false;
+ do
+ {
+ if (root->router)
+ return (!m_Filter || m_Filter (root->router)) ? root->router : nullptr;
+ split = root->zero && root->one;
+ if (!split)
+ {
+ if (root->zero) root = root->zero;
+ else if (root->one) root = root->one;
+ else return nullptr;
+ level++;
+ }
+ }
+ while (!split);
+ int bit = h.GetBit (level);
+ if (bit)
+ {
+ if (root->one)
+ {
+ auto r = FindClosest (h, root->one, level + 1);
+ if (r) return r;
+ }
+ if (root->zero)
+ {
+ auto r = FindClosest (h, root->zero, level + 1);
+ if (r) return r;
+ }
+ }
+ else
+ {
+ if (root->zero)
+ {
+ auto r = FindClosest (h, root->zero, level + 1);
+ if (r) return r;
+ }
+ if (root->one)
+ {
+ auto r = FindClosest (h, root->one, level + 1);
+ if (r) return r;
+ }
+ }
+ return nullptr;
+ }
+
+ std::vector<std::shared_ptr<RouterInfo> > DHTTable::FindClosest (const IdentHash& h, size_t num, const Filter& filter) const
+ {
+ std::vector<std::shared_ptr<RouterInfo> > vec;
+ if (num > 0)
+ {
+ if (filter) m_Filter = filter;
+ FindClosest (h, num, m_Root, 0, vec);
+ m_Filter = nullptr;
+ }
+ return vec;
+ }
+
+ void DHTTable::FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes) const
+ {
+ if (hashes.size () >= num) return;
+ bool split = false;
+ do
+ {
+ if (root->router)
+ {
+ if (!m_Filter || m_Filter (root->router))
+ hashes.push_back (root->router);
+ return;
+ }
+ split = root->zero && root->one;
+ if (!split)
+ {
+ if (root->zero) root = root->zero;
+ else if (root->one) root = root->one;
+ else return;
+ level++;
+ }
+ }
+ while (!split);
+ int bit = h.GetBit (level);
+ if (bit)
+ {
+ if (root->one)
+ FindClosest (h, num, root->one, level + 1, hashes);
+ if (hashes.size () < num && root->zero)
+ FindClosest (h, num, root->zero, level + 1, hashes);
+ }
+ else
+ {
+ if (root->zero)
+ FindClosest (h, num, root->zero, level + 1, hashes);
+ if (hashes.size () < num && root->one)
+ FindClosest (h, num, root->one, level + 1, hashes);
+ }
+ }
+
+ void DHTTable::Cleanup (const Filter& filter)
+ {
+ if (filter)
+ {
+ m_Filter = filter;
+ Cleanup (m_Root);
+ m_Filter = nullptr;
+ }
+ else
+ Clear ();
+ }
+
+ void DHTTable::Cleanup (DHTNode * root)
+ {
+ if (!root) return;
+ if (root->router)
+ {
+ if (!m_Filter || !m_Filter (root->router))
+ {
+ m_Size--;
+ root->router = nullptr;
+ }
+ return;
+ }
+ if (root->zero)
+ {
+ Cleanup (root->zero);
+ if (root->zero->IsEmpty ())
+ {
+ delete root->zero;
+ root->zero = nullptr;
+ }
+ }
+ if (root->one)
+ {
+ Cleanup (root->one);
+ if (root->one->IsEmpty ())
+ {
+ delete root->one;
+ root->one = nullptr;
+ if (root->zero && root->zero->router)
+ root->MoveRouterUp (false);
+ }
+ else if (root->one->router && !root->zero)
+ root->MoveRouterUp (true);
+ }
+ }
+
+ void DHTTable::Print (std::stringstream& s)
+ {
+ Print (s, m_Root, 0);
+ }
+
+ void DHTTable::Print (std::stringstream& s, DHTNode * root, int level)
+ {
+ if (!root) return;
+ s << std::string (level, '-');
+ if (root->router)
+ {
+ if (!root->zero && !root->one)
+ s << '>' << GetIdentHashAbbreviation (root->router->GetIdentHash ());
+ else
+ s << "error";
+ }
+ s << std::endl;
+ if (root->zero)
+ {
+ s << std::string (level, '-') << "0" << std::endl;
+ Print (s, root->zero, level + 1);
+ }
+ if (root->one)
+ {
+ s << std::string (level, '-') << "1" << std::endl;
+ Print (s, root->one, level + 1);
+ }
+ }
+}
+}
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/KadDHT.h
^
|
@@ -0,0 +1,74 @@
+/*
+* Copyright (c) 2023, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*
+*/
+
+#ifndef KADDHT_H__
+#define KADDHT_H__
+
+#include <memory>
+#include <vector>
+#include <sstream>
+#include <functional>
+#include "RouterInfo.h"
+
+// Kademlia DHT (XOR distance)
+
+namespace i2p
+{
+namespace data
+{
+ struct DHTNode
+ {
+ DHTNode * zero, * one;
+ std::shared_ptr<RouterInfo> router;
+
+ DHTNode ();
+ ~DHTNode ();
+
+ bool IsEmpty () const { return !zero && !one && !router; };
+ void MoveRouterUp (bool fromOne);
+ };
+
+ class DHTTable
+ {
+ typedef std::function<bool (const std::shared_ptr<RouterInfo>&)> Filter;
+ public:
+
+ DHTTable ();
+ ~DHTTable ();
+
+ void Insert (const std::shared_ptr<RouterInfo>& r);
+ bool Remove (const IdentHash& h);
+ std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, const Filter& filter = nullptr) const;
+ std::vector<std::shared_ptr<RouterInfo> > FindClosest (const IdentHash& h, size_t num, const Filter& filter = nullptr) const;
+
+ void Print (std::stringstream& s);
+ size_t GetSize () const { return m_Size; };
+ void Clear ();
+ void Cleanup (const Filter& filter);
+
+ private:
+
+ void Insert (const std::shared_ptr<RouterInfo>& r, DHTNode * root, int level); // recursive
+ bool Remove (const IdentHash& h, DHTNode * root, int level);
+ std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, DHTNode * root, int level) const;
+ void FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes) const;
+ void Cleanup (DHTNode * root);
+ void Print (std::stringstream& s, DHTNode * root, int level);
+
+ private:
+
+ DHTNode * m_Root;
+ size_t m_Size;
+ // transient
+ mutable Filter m_Filter;
+ };
+}
+}
+
+#endif
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/LeaseSet.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -37,14 +37,7 @@
void LeaseSet::Update (const uint8_t * buf, size_t len, bool verifySignature)
{
- if (len > m_BufferLen)
- {
- auto oldBuffer = m_Buffer;
- m_Buffer = new uint8_t[len];
- delete[] oldBuffer;
- }
- memcpy (m_Buffer, buf, len);
- m_BufferLen = len;
+ SetBuffer (buf, len);
ReadFromBuffer (false, verifySignature);
}
@@ -57,7 +50,7 @@
void LeaseSet::ReadFromBuffer (bool readIdentity, bool verifySignature)
{
if (readIdentity || !m_Identity)
- m_Identity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
+ m_Identity = netdb.NewIdentity (m_Buffer, m_BufferLen);
size_t size = m_Identity->GetFullLen ();
if (size + 256 > m_BufferLen)
{
@@ -83,7 +76,7 @@
LogPrint (eLogDebug, "LeaseSet: Read num=", (int)num);
if (!num || num > MAX_NUM_LEASES)
{
- LogPrint (eLogError, "LeaseSet: Rncorrect number of leases", (int)num);
+ LogPrint (eLogError, "LeaseSet: Incorrect number of leases", (int)num);
m_IsValid = false;
return;
}
@@ -264,8 +257,18 @@
void LeaseSet::SetBuffer (const uint8_t * buf, size_t len)
{
- if (m_Buffer) delete[] m_Buffer;
- m_Buffer = new uint8_t[len];
+ if (len > MAX_LS_BUFFER_SIZE)
+ {
+ LogPrint (eLogError, "LeaseSet: Buffer is too long ", len);
+ len = MAX_LS_BUFFER_SIZE;
+ }
+ if (m_Buffer && len > m_BufferLen)
+ {
+ delete[] m_Buffer;
+ m_Buffer = nullptr;
+ }
+ if (!m_Buffer)
+ m_Buffer = new uint8_t[len];
m_BufferLen = len;
memcpy (m_Buffer, buf, len);
}
@@ -312,9 +315,9 @@
{
// standard LS2 header
std::shared_ptr<const IdentityEx> identity;
- if (readIdentity)
+ if (readIdentity || !GetIdentity ())
{
- identity = std::make_shared<IdentityEx>(buf, len);
+ identity = netdb.NewIdentity (buf, len);
SetIdentity (identity);
}
else
@@ -363,6 +366,8 @@
VerifySignature (identity, buf, len, offset);
SetIsValid (verified);
}
+ else
+ SetIsValid (true);
offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : identity->GetSignatureLen ();
if (offset > len) {
LogPrint (eLogWarning, "LeaseSet2: short buffer: wanted ", int(offset), "bytes, have ", int(len));
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/LeaseSet.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -96,6 +96,9 @@
void Encrypt (const uint8_t * data, uint8_t * encrypted) const;
bool IsDestination () const { return true; };
+ // used in webconsole
+ void ExpireLease () { m_ExpirationTime = i2p::util::GetSecondsSinceEpoch (); };
+
protected:
void UpdateLeasesBegin ();
@@ -145,6 +148,7 @@
{
public:
+ LeaseSet2 (uint8_t storeType): LeaseSet (true), m_StoreType (storeType) {}; // for update
LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL);
LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); // store type 5, called from local netdb only
uint8_t GetStoreType () const { return m_StoreType; };
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Log.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -18,13 +18,14 @@
/**
* @brief Maps our loglevel to their symbolic name
*/
- static const char * g_LogLevelStr[eNumLogLevels] =
+ static const char *g_LogLevelStr[eNumLogLevels] =
{
- "none", // eLogNone
- "error", // eLogError
- "warn", // eLogWarn
- "info", // eLogInfo
- "debug" // eLogDebug
+ "none", // eLogNone
+ "critical", // eLogCritical
+ "error", // eLogError
+ "warn", // eLogWarning
+ "info", // eLogInfo
+ "debug" // eLogDebug
};
/**
@@ -32,15 +33,16 @@
* @note Using ISO 6429 (ANSI) color sequences
*/
#ifdef _WIN32
- static const char *LogMsgColors[] = { "", "", "", "", "", "" };
+ static const char *LogMsgColors[] = { "", "", "", "", "", "", "" };
#else /* UNIX */
static const char *LogMsgColors[] = {
- [eLogNone] = "\033[0m", /* reset */
- [eLogError] = "\033[1;31m", /* red */
- [eLogWarning] = "\033[1;33m", /* yellow */
- [eLogInfo] = "\033[1;36m", /* cyan */
- [eLogDebug] = "\033[1;34m", /* blue */
- [eNumLogLevels] = "\033[0m", /* reset */
+ "\033[1;32m", /* none: green */
+ "\033[1;41m", /* critical: red background */
+ "\033[1;31m", /* error: red */
+ "\033[1;33m", /* warning: yellow */
+ "\033[1;36m", /* info: cyan */
+ "\033[1;34m", /* debug: blue */
+ "\033[0m" /* reset */
};
#endif
@@ -53,6 +55,7 @@
int priority = LOG_DEBUG;
switch (l) {
case eLogNone : priority = LOG_CRIT; break;
+ case eLogCritical: priority = LOG_CRIT; break;
case eLogError : priority = LOG_ERR; break;
case eLogWarning : priority = LOG_WARNING; break;
case eLogInfo : priority = LOG_INFO; break;
@@ -123,13 +126,14 @@
void Log::SetLogLevel (const std::string& level_) {
std::string level=str_tolower(level_);
- if (level == "none") { m_MinLevel = eLogNone; }
- else if (level == "error") { m_MinLevel = eLogError; }
- else if (level == "warn") { m_MinLevel = eLogWarning; }
- else if (level == "info") { m_MinLevel = eLogInfo; }
- else if (level == "debug") { m_MinLevel = eLogDebug; }
+ if (level == "none") { m_MinLevel = eLogNone; }
+ else if (level == "critical") { m_MinLevel = eLogCritical; }
+ else if (level == "error") { m_MinLevel = eLogError; }
+ else if (level == "warn") { m_MinLevel = eLogWarning; }
+ else if (level == "info") { m_MinLevel = eLogInfo; }
+ else if (level == "debug") { m_MinLevel = eLogDebug; }
else {
- LogPrint(eLogError, "Log: Unknown loglevel: ", level);
+ LogPrint(eLogCritical, "Log: Unknown loglevel: ", level);
return;
}
LogPrint(eLogInfo, "Log: Logging level set to ", level);
@@ -212,7 +216,7 @@
m_LogStream = os;
return;
}
- LogPrint(eLogError, "Log: Can't open file ", path);
+ LogPrint(eLogCritical, "Log: Can't open file ", path);
}
void Log::SendTo (std::shared_ptr<std::ostream> os) {
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Log.h
^
|
@@ -27,6 +27,7 @@
enum LogLevel
{
eLogNone = 0,
+ eLogCritical,
eLogError,
eLogWarning,
eLogInfo,
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/NTCP2.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -139,7 +139,7 @@
m3p2[3] = 0; // flag
memcpy (m3p2 + 4, i2p::context.GetRouterInfo ().GetBuffer (), bufLen); // TODO: own RI should be protected by mutex
// 2 bytes reserved
- htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA
+ htobe32buf (options + 8, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); // tsA, rounded to seconds
// 4 bytes reserved
// sign and encrypt options, use m_H as AD
uint8_t nonce[12];
@@ -162,7 +162,7 @@
uint8_t options[16];
memset (options, 0, 16);
htobe16buf (options + 2, paddingLen); // padLen
- htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsB
+ htobe32buf (options + 8, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); // tsB, rounded to seconds
// sign and encrypt options, use m_H as AD
uint8_t nonce[12];
memset (nonce, 0, 12); // set nonce to zero
@@ -309,7 +309,7 @@
KDF3Bob ();
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt
- // caclulate new h again for KDF data
+ // calculate new h again for KDF data
MixHash (m_SessionConfirmedBuffer + 48, m3p2Len); // h = SHA256(h || ciphertext)
else
{
@@ -374,10 +374,25 @@
transports.PeerDisconnected (shared_from_this ());
m_Server.RemoveNTCP2Session (shared_from_this ());
m_SendQueue.clear ();
- LogPrint (eLogDebug, "NTCP2: Session terminated");
+ SetSendQueueSize (0);
+ auto remoteIdentity = GetRemoteIdentity ();
+ if (remoteIdentity)
+ {
+ LogPrint (eLogDebug, "NTCP2: Session with ", GetRemoteEndpoint (),
+ " (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") terminated");
+ }
+ else
+ {
+ LogPrint (eLogDebug, "NTCP2: Session with ", GetRemoteEndpoint (), " terminated");
+ }
}
}
+ void NTCP2Session::Close ()
+ {
+ m_Socket.close ();
+ }
+
void NTCP2Session::TerminateByTimeout ()
{
SendTerminationAndTerminate (eNTCP2IdleTimeout);
@@ -418,7 +433,7 @@
void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts)
{
if (m_NextReceivedBuffer && !m_IsReceiving &&
- ts > m_LastActivityTimestamp + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT)
+ ts > GetLastActivityTimestamp () + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT)
{
delete[] m_NextReceivedBuffer;
m_NextReceivedBuffer = nullptr;
@@ -446,6 +461,7 @@
{
m_Establisher->CreateSessionRequestMessage ();
// send message
+ m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch ();
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
}
@@ -523,6 +539,7 @@
{
m_Establisher->CreateSessionCreatedMessage ();
// send message
+ m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch ();
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
}
@@ -536,6 +553,7 @@
}
else
{
+ m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred);
uint16_t paddingLen = 0;
if (m_Establisher->ProcessSessionCreatedMessage (paddingLen))
@@ -557,7 +575,11 @@
SendSessionConfirmed ();
}
else
+ {
+ if (GetRemoteIdentity ())
+ i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); // assume wrong s key
Terminate ();
+ }
}
}
@@ -640,6 +662,7 @@
}
else
{
+ m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
LogPrint (eLogDebug, "NTCP2: SessionConfirmed received");
// part 1
uint8_t nonce[12];
@@ -677,20 +700,39 @@
i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag
if (ri.IsUnreachable ())
{
- LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed");
+ LogPrint (eLogError, "NTCP2: RouterInfo verification failed in SessionConfirmed from ", GetRemoteEndpoint ());
SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail);
return;
}
- if (i2p::util::GetMillisecondsSinceEpoch () > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
+ LogPrint(eLogDebug, "NTCP2: SessionConfirmed from ", GetRemoteEndpoint (),
+ " (", i2p::data::GetIdentHashAbbreviation (ri.GetIdentHash ()), ")");
+ auto ts = i2p::util::GetMillisecondsSinceEpoch ();
+ if (ts > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
{
- LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed");
+ LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed for ", (ts - ri.GetTimestamp ())/1000LL, " seconds");
SendTerminationAndTerminate (eNTCP2Message3Error);
return;
}
- auto addr = ri.GetNTCP2AddressWithStaticKey (m_Establisher->m_RemoteStaticKey);
- if (!addr)
+ if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri.GetTimestamp ()) // 2 minutes
{
- LogPrint (eLogError, "NTCP2: No NTCP2 address with static key found in SessionConfirmed");
+ LogPrint (eLogError, "NTCP2: RouterInfo is from future for ", (ri.GetTimestamp () - ts)/1000LL, " seconds");
+ SendTerminationAndTerminate (eNTCP2Message3Error);
+ return;
+ }
+ auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri.GetNTCP2V4Address () :
+ (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri.GetYggdrasilAddress () : ri.GetNTCP2V6Address ());
+ if (!addr || memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32))
+ {
+ LogPrint (eLogError, "NTCP2: Wrong static key in SessionConfirmed");
+ Terminate ();
+ return;
+ }
+ if (addr->IsPublishedNTCP2 () && m_RemoteEndpoint.address () != addr->host &&
+ (!m_RemoteEndpoint.address ().is_v6 () || (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ?
+ memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data () + 1, addr->host.to_v6 ().to_bytes ().data () + 1, 7) : // from the same yggdrasil subnet
+ memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), addr->host.to_v6 ().to_bytes ().data (), 8)))) // temporary address
+ {
+ LogPrint (eLogError, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ());
Terminate ();
return;
}
@@ -746,6 +788,8 @@
void NTCP2Session::ServerLogin ()
{
+ SetTerminationTimeout (NTCP2_ESTABLISH_TIMEOUT);
+ SetLastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ());
m_Establisher->CreateEphemeralKey ();
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 (),
@@ -828,9 +872,8 @@
}
else
{
- m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
- m_NumReceivedBytes += bytes_transferred + 2; // + length
- i2p::transport::transports.UpdateReceivedBytes (bytes_transferred);
+ UpdateNumReceivedBytes (bytes_transferred + 2);
+ i2p::transport::transports.UpdateReceivedBytes (bytes_transferred + 2);
uint8_t nonce[12];
CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++;
if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false))
@@ -858,7 +901,7 @@
auto size = bufbe16toh (frame + offset);
offset += 2;
LogPrint (eLogDebug, "NTCP2: Block type ", (int)blk, " of size ", size);
- if (size > len)
+ if (offset + size > len)
{
LogPrint (eLogError, "NTCP2: Unexpected block length ", size);
break;
@@ -866,8 +909,20 @@
switch (blk)
{
case eNTCP2BlkDateTime:
+ {
LogPrint (eLogDebug, "NTCP2: Datetime");
- break;
+ if (m_IsEstablished)
+ {
+ uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
+ uint64_t tsA = bufbe32toh (frame + offset);
+ if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW)
+ {
+ LogPrint (eLogWarning, "NTCP2: Established session time difference ", (int)(ts - tsA), " exceeds clock skew");
+ SendTerminationAndTerminate (eNTCP2ClockSkew);
+ }
+ }
+ break;
+ }
case eNTCP2BlkOptions:
LogPrint (eLogDebug, "NTCP2: Options");
break;
@@ -1039,18 +1094,20 @@
}
else
{
- m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
- m_NumSentBytes += bytes_transferred;
+ UpdateNumSentBytes (bytes_transferred);
i2p::transport::transports.UpdateSentBytes (bytes_transferred);
LogPrint (eLogDebug, "NTCP2: Next frame sent ", bytes_transferred);
- if (m_LastActivityTimestamp > m_NextRouterInfoResendTime)
+ if (GetLastActivityTimestamp () > m_NextRouterInfoResendTime)
{
m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL +
rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
SendRouterInfo ();
}
else
+ {
SendQueue ();
+ SetSendQueueSize (m_SendQueue.size ());
+ }
}
}
@@ -1109,12 +1166,17 @@
{
if (!IsEstablished ()) return;
auto riLen = i2p::context.GetRouterInfo ().GetBufferLen ();
- size_t payloadLen = riLen + 4; // 3 bytes block header + 1 byte RI flag
+ size_t payloadLen = riLen + 3 + 1 + 7; // 3 bytes block header + 1 byte RI flag + 7 bytes DateTime
m_NextSendBuffer = new uint8_t[payloadLen + 16 + 2 + 64]; // up to 64 bytes padding
- m_NextSendBuffer[2] = eNTCP2BlkRouterInfo;
- htobe16buf (m_NextSendBuffer + 3, riLen + 1); // size
- m_NextSendBuffer[5] = 0; // flag
- memcpy (m_NextSendBuffer + 6, i2p::context.GetRouterInfo ().GetBuffer (), riLen);
+ // DateTime block
+ m_NextSendBuffer[2] = eNTCP2BlkDateTime;
+ htobe16buf (m_NextSendBuffer + 3, 4);
+ htobe32buf (m_NextSendBuffer + 5, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
+ // RouterInfo block
+ m_NextSendBuffer[9] = eNTCP2BlkRouterInfo;
+ htobe16buf (m_NextSendBuffer + 10, riLen + 1); // size
+ m_NextSendBuffer[12] = 0; // flag
+ memcpy (m_NextSendBuffer + 13, i2p::context.GetRouterInfo ().GetBuffer (), riLen);
// padding block
auto paddingSize = CreatePaddingBlock (payloadLen, m_NextSendBuffer + 2 + payloadLen, 64);
payloadLen += paddingSize;
@@ -1158,7 +1220,7 @@
{
if (m_IsTerminated) return;
for (auto it: msgs)
- m_SendQueue.push_back (it);
+ m_SendQueue.push_back (std::move (it));
if (!m_IsSending)
SendQueue ();
else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE)
@@ -1167,6 +1229,7 @@
GetIdentHashBase64(), " exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE);
Terminate ();
}
+ SetSendQueueSize (m_SendQueue.size ());
}
void NTCP2Session::SendLocalRouterInfo (bool update)
@@ -1199,7 +1262,7 @@
boost::system::error_code e;
auto itr = m_Resolver.resolve(q, e);
if(e)
- LogPrint(eLogError, "NTCP2: Failed to resolve proxy ", e.message());
+ LogPrint(eLogCritical, "NTCP2: Failed to resolve proxy ", e.message());
else
{
m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint(*itr));
@@ -1210,8 +1273,9 @@
else
LogPrint(eLogInfo, "NTCP2: Proxy is not used");
// start acceptors
- auto& addresses = context.GetRouterInfo ().GetAddresses ();
- for (const auto& address: addresses)
+ auto addresses = context.GetRouterInfo ().GetAddresses ();
+ if (!addresses) return;
+ for (const auto& address: *addresses)
{
if (!address) continue;
if (address->IsPublishedNTCP2 () && address->port)
@@ -1226,7 +1290,7 @@
}
catch ( std::exception & ex )
{
- LogPrint(eLogError, "NTCP2: Failed to bind to v4 port ", address->port, ex.what());
+ LogPrint(eLogCritical, "NTCP2: Failed to bind to v4 port ", address->port, ex.what());
ThrowFatal ("Unable to start IPv4 NTCP2 transport at port ", address->port, ": ", ex.what ());
continue;
}
@@ -1269,7 +1333,7 @@
}
catch ( std::exception & ex )
{
- LogPrint(eLogError, "NTCP2: Failed to bind to v6 port ", address->port, ": ", ex.what());
+ LogPrint(eLogCritical, "NTCP2: Failed to bind to v6 port ", address->port, ": ", ex.what());
ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ());
continue;
}
@@ -1288,7 +1352,7 @@
for (auto& it: ntcpSessions)
it.second->Terminate ();
for (auto& it: m_PendingIncomingSessions)
- it->Terminate ();
+ it.second->Terminate ();
}
m_NTCP2Sessions.clear ();
@@ -1304,20 +1368,32 @@
{
if (!session) return false;
if (incoming)
- m_PendingIncomingSessions.remove (session);
- if (!session->GetRemoteIdentity ()) return false;
+ m_PendingIncomingSessions.erase (session->GetRemoteEndpoint ().address ());
+ if (!session->GetRemoteIdentity ())
+ {
+ LogPrint (eLogWarning, "NTCP2: Unknown identity for ", session->GetRemoteEndpoint ());
+ session->Terminate ();
+ return false;
+ }
auto& ident = session->GetRemoteIdentity ()->GetIdentHash ();
auto it = m_NTCP2Sessions.find (ident);
if (it != m_NTCP2Sessions.end ())
{
- LogPrint (eLogWarning, "NTCP2: Session to ", ident.ToBase64 (), " already exists");
+ LogPrint (eLogWarning, "NTCP2: Session with ", ident.ToBase64 (), " already exists. ", incoming ? "Replaced" : "Dropped");
if (incoming)
+ {
// replace by new session
- it->second->Terminate ();
+ auto s = it->second;
+ m_NTCP2Sessions.erase (it);
+ s->Terminate ();
+ }
else
+ {
+ session->Terminate ();
return false;
+ }
}
- m_NTCP2Sessions.insert (std::make_pair (ident, session));
+ m_NTCP2Sessions.emplace (ident, session);
return true;
}
@@ -1342,7 +1418,8 @@
LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
return;
}
- LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint ());
+ LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint (),
+ " (", i2p::data::GetIdentHashAbbreviation (conn->GetRemoteIdentity ()->GetIdentHash ()), ")");
GetService ().post([this, conn]()
{
if (this->AddNTCP2Session (conn))
@@ -1398,33 +1475,47 @@
}
else
{
- LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetRemoteEndpoint ());
+ LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetRemoteEndpoint (),
+ " (", i2p::data::GetIdentHashAbbreviation (conn->GetRemoteIdentity ()->GetIdentHash ()), ")");
conn->ClientLogin ();
}
}
void NTCP2Server::HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error)
{
- if (!error)
+ if (!error && conn)
{
boost::system::error_code ec;
auto ep = conn->GetSocket ().remote_endpoint(ec);
if (!ec)
{
LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
- if (conn)
+ if (!i2p::util::net::IsInReservedRange(ep.address ()))
{
- conn->SetRemoteEndpoint (ep);
- conn->ServerLogin ();
- m_PendingIncomingSessions.push_back (conn);
- conn = nullptr;
+ if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
+ {
+ conn->SetRemoteEndpoint (ep);
+ conn->ServerLogin ();
+ conn = nullptr;
+ }
+ else
+ LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending");
}
+ else
+ LogPrint (eLogError, "NTCP2: Incoming connection from invalid IP ", ep.address ());
}
else
LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
}
else
+ {
LogPrint (eLogError, "NTCP2: Accept error ", error.message ());
+ if (error == boost::asio::error::no_descriptors)
+ {
+ i2p::context.SetError (eRouterErrorNoDescriptors);
+ return;
+ }
+ }
if (error != boost::asio::error::operation_aborted)
{
@@ -1439,27 +1530,47 @@
void NTCP2Server::HandleAcceptV6 (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error)
{
- if (!error)
+ if (!error && conn)
{
boost::system::error_code ec;
auto ep = conn->GetSocket ().remote_endpoint(ec);
if (!ec)
{
LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
- if (conn)
+ if (!i2p::util::net::IsInReservedRange(ep.address ()) ||
+ i2p::util::net::IsYggdrasilAddress (ep.address ()))
{
- conn->SetRemoteEndpoint (ep);
- conn->ServerLogin ();
- m_PendingIncomingSessions.push_back (conn);
+ if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
+ {
+ conn->SetRemoteEndpoint (ep);
+ conn->ServerLogin ();
+ conn = nullptr;
+ }
+ else
+ LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending");
}
+ else
+ LogPrint (eLogError, "NTCP2: Incoming connection from invalid IP ", ep.address ());
}
else
LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
}
+ else
+ {
+ LogPrint (eLogError, "NTCP2: Accept ipv6 error ", error.message ());
+ if (error == boost::asio::error::no_descriptors)
+ {
+ i2p::context.SetErrorV6 (eRouterErrorNoDescriptors);
+ return;
+ }
+ }
if (error != boost::asio::error::operation_aborted)
{
- conn = std::make_shared<NTCP2Session> (*this);
+ if (!conn) // connection is used, create new one
+ conn = std::make_shared<NTCP2Session> (*this);
+ else // reuse failed
+ conn->Close ();
m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this,
conn, std::placeholders::_1));
}
@@ -1490,18 +1601,34 @@
// pending
for (auto it = m_PendingIncomingSessions.begin (); it != m_PendingIncomingSessions.end ();)
{
- if ((*it)->IsEstablished () || (*it)->IsTerminationTimeoutExpired (ts))
+ if (it->second->IsEstablished () || it->second->IsTerminationTimeoutExpired (ts))
{
- (*it)->Terminate ();
+ it->second->Terminate ();
it = m_PendingIncomingSessions.erase (it); // established of expired
}
- else if ((*it)->IsTerminated ())
+ else if (it->second->IsTerminated ())
it = m_PendingIncomingSessions.erase (it); // already terminated
else
it++;
}
-
ScheduleTermination ();
+
+ // try to restart acceptors if no description
+ // we do it after timer to let timer take descriptor first
+ if (i2p::context.GetError () == eRouterErrorNoDescriptors)
+ {
+ i2p::context.SetError (eRouterErrorNone);
+ auto conn = std::make_shared<NTCP2Session> (*this);
+ m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this,
+ conn, std::placeholders::_1));
+ }
+ if (i2p::context.GetErrorV6 () == eRouterErrorNoDescriptors)
+ {
+ i2p::context.SetErrorV6 (eRouterErrorNone);
+ auto conn = std::make_shared<NTCP2Session> (*this);
+ m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this,
+ conn, std::placeholders::_1));
+ }
}
}
@@ -1558,7 +1685,7 @@
case eSocksProxy:
{
// TODO: support username/password auth etc
- static const uint8_t buff[3] = {0x05, 0x01, 0x00};
+ static const uint8_t buff[3] = {SOCKS5_VER, 0x01, 0x00};
boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(),
[] (const boost::system::error_code & ec, std::size_t transferred)
{
@@ -1672,21 +1799,21 @@
size_t sz = 6; // header + port
auto buff = std::make_shared<std::vector<int8_t> >(256);
auto readbuff = std::make_shared<std::vector<int8_t> >(256);
- (*buff)[0] = 0x05;
- (*buff)[1] = 0x01;
+ (*buff)[0] = SOCKS5_VER;
+ (*buff)[1] = SOCKS5_CMD_CONNECT;
(*buff)[2] = 0x00;
auto& ep = conn->GetRemoteEndpoint ();
if(ep.address ().is_v4 ())
{
- (*buff)[3] = 0x01;
+ (*buff)[3] = SOCKS5_ATYP_IPV4;
auto addrbytes = ep.address ().to_v4().to_bytes();
sz += 4;
memcpy(buff->data () + 4, addrbytes.data(), 4);
}
else if (ep.address ().is_v6 ())
{
- (*buff)[3] = 0x04;
+ (*buff)[3] = SOCKS5_ATYP_IPV6;
auto addrbytes = ep.address ().to_v6().to_bytes();
sz += 16;
memcpy(buff->data () + 4, addrbytes.data(), 16);
@@ -1708,22 +1835,24 @@
}
});
- boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 10),
- [timer, conn, sz, readbuff](const boost::system::error_code & e, std::size_t transferred)
+ boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE), // read min reply size
+ boost::asio::transfer_all(),
+ [timer, conn, readbuff](const boost::system::error_code & e, std::size_t transferred)
{
- if(e)
- {
+ if (e)
LogPrint(eLogError, "NTCP2: SOCKS proxy read error ", e.message());
- }
- else if(transferred == sz)
+ else if (!(*readbuff)[1]) // succeeded
{
- if((*readbuff)[1] == 0x00)
- {
- timer->cancel();
- conn->ClientLogin();
- return;
- }
+ boost::system::error_code ec;
+ size_t moreBytes = conn->GetSocket ().available(ec);
+ if (moreBytes) // read remaining portion of reply if ipv6 received
+ boost::asio::read (conn->GetSocket (), boost::asio::buffer(readbuff->data (), moreBytes), boost::asio::transfer_all (), ec);
+ timer->cancel();
+ conn->ClientLogin();
+ return;
}
+ else
+ LogPrint(eLogError, "NTCP2: Proxy reply error ", (int)(*readbuff)[1]);
timer->cancel();
conn->Terminate();
});
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/NTCP2.h
^
|
@@ -134,22 +134,22 @@
~NTCP2Session ();
void Terminate ();
void TerminateByTimeout ();
- void Done ();
- void Close () { m_Socket.close (); }; // for accept
+ void Done () override;
+ void Close (); // for accept
void DeleteNextReceiveBuffer (uint64_t ts);
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
const boost::asio::ip::tcp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
void SetRemoteEndpoint (const boost::asio::ip::tcp::endpoint& ep) { m_RemoteEndpoint = ep; };
- bool IsEstablished () const { return m_IsEstablished; };
+ bool IsEstablished () const override { return m_IsEstablished; };
bool IsTerminated () const { return m_IsTerminated; };
void ClientLogin (); // Alice
void ServerLogin (); // Bob
- void SendLocalRouterInfo (bool update); // after handshake or by update
- void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
+ void SendLocalRouterInfo (bool update) override; // after handshake or by update
+ void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
private:
@@ -277,7 +277,7 @@
boost::asio::deadline_timer m_TerminationTimer;
std::unique_ptr<boost::asio::ip::tcp::acceptor> m_NTCP2Acceptor, m_NTCP2V6Acceptor;
std::map<i2p::data::IdentHash, std::shared_ptr<NTCP2Session> > m_NTCP2Sessions;
- std::list<std::shared_ptr<NTCP2Session> > m_PendingIncomingSessions;
+ std::map<boost::asio::ip::address, std::shared_ptr<NTCP2Session> > m_PendingIncomingSessions;
ProxyType m_ProxyType;
std::string m_ProxyAddress, m_ProxyAuthorization;
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/NetDb.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2024, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -36,7 +36,7 @@
{
NetDb netdb;
- NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true), m_HiddenMode(false)
+ NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true)
{
}
@@ -55,24 +55,24 @@
Load ();
uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
- if (m_RouterInfos.size () < threshold || m_Floodfills.size () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils
+ if (m_RouterInfos.size () < threshold || m_Floodfills.GetSize () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils
{
Reseed ();
}
- else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false))
+ else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, false))
Reseed (); // we don't have a router we can connect to. Trying to reseed
auto it = m_RouterInfos.find (i2p::context.GetIdentHash ());
if (it != m_RouterInfos.end ())
{
// remove own router
- m_Floodfills.remove (it->second);
+ m_Floodfills.Remove (it->second->GetIdentHash ());
m_RouterInfos.erase (it);
}
// insert own router
m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ());
if (i2p::context.IsFloodfill ())
- m_Floodfills.push_back (i2p::context.GetSharedRouterInfo ());
+ m_Floodfills.Insert (i2p::context.GetSharedRouterInfo ());
i2p::config::GetOption("persist.profiles", m_PersistProfiles);
@@ -85,11 +85,10 @@
if (m_IsRunning)
{
if (m_PersistProfiles)
- for (auto& it: m_RouterInfos)
- it.second->SaveProfile ();
+ SaveProfiles ();
DeleteObsoleteProfiles ();
m_RouterInfos.clear ();
- m_Floodfills.clear ();
+ m_Floodfills.Clear ();
if (m_Thread)
{
m_IsRunning = false;
@@ -107,7 +106,7 @@
{
i2p::util::SetThreadName("NetDB");
- uint64_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
+ uint64_t lastManage = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch ();
int16_t profilesCleanupVariance = 0;
@@ -133,9 +132,6 @@
case eI2NPDatabaseLookup:
HandleDatabaseLookupMsg (msg);
break;
- case eI2NPDeliveryStatus:
- HandleDeliveryStatusMsg (msg);
- break;
case eI2NPDummyMsg:
// plain RouterInfo from NTCP2 with flags for now
HandleNTCP2RouterInfoMsg (msg);
@@ -153,62 +149,40 @@
if (!i2p::transport::transports.IsOnline ()) continue; // don't manage netdb when offline
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
- if (ts - lastManageRequest >= 15) // manage requests every 15 seconds
+ if (ts - lastManageRequest >= 15 || ts + 15 < lastManageRequest) // manage requests every 15 seconds
{
m_Requests.ManageRequests ();
lastManageRequest = ts;
}
- if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute
+ if (ts - lastManage >= 60 || ts + 60 < lastManage) // manage routers and leasesets every minute
{
- if (lastSave)
+ if (lastManage)
{
- SaveUpdated ();
+ ManageRouterInfos ();
ManageLeaseSets ();
}
- lastSave = ts;
+ lastManage = ts;
}
- if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT)
+ if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT ||
+ ts + i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT < lastDestinationCleanup)
{
i2p::context.CleanupDestination ();
lastDestinationCleanup = ts;
}
- if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance))
+ if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance) ||
+ ts + i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT < lastProfilesCleanup)
{
+ m_RouterProfilesPool.CleanUpMt ();
+ if (m_PersistProfiles) PersistProfiles ();
DeleteObsoleteProfiles ();
lastProfilesCleanup = ts;
profilesCleanupVariance = (rand () % (2 * i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE) - i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE);
}
- // publish
- if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
- {
- bool publish = false;
- if (m_PublishReplyToken)
- {
- // next publishing attempt
- if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true;
- }
- else if (i2p::context.GetLastUpdateTime () > lastPublish ||
- ts - lastPublish >= NETDB_PUBLISH_INTERVAL)
- {
- // new publish
- m_PublishExcluded.clear ();
- if (i2p::context.IsFloodfill ())
- m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // do publish to ourselves
- publish = true;
- }
- if (publish) // update timestamp and publish
- {
- i2p::context.UpdateTimestamp (ts);
- Publish ();
- lastPublish = ts;
- }
- }
-
- if (ts - lastExploratory >= 30) // exploratory every 30 seconds
+ if (ts - lastExploratory >= 30 || ts + 30 < lastExploratory) // exploratory every 30 seconds
{
auto numRouters = m_RouterInfos.size ();
if (!numRouters)
@@ -221,7 +195,7 @@
if (numRouters < 1) numRouters = 1;
if (numRouters > 9) numRouters = 9;
m_Requests.ManageRequests ();
- if(!m_HiddenMode)
+ if(!i2p::context.IsHidden ())
Explore (numRouters);
lastExploratory = ts;
}
@@ -234,12 +208,6 @@
}
}
- void NetDb::SetHidden(bool hide)
- {
- // TODO: remove reachable addresses from router info
- m_HiddenMode = hide;
- }
-
std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const uint8_t * buf, int len)
{
bool updated;
@@ -273,17 +241,40 @@
bool wasFloodfill = r->IsFloodfill ();
{
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
- r->Update (buf, len);
- }
+ if (!r->Update (buf, len))
+ {
+ updated = false;
+ m_Requests.RequestComplete (ident, r);
+ return r;
+ }
+ if (r->IsUnreachable () ||
+ i2p::util::GetMillisecondsSinceEpoch () + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < r->GetTimestamp ())
+ {
+ // delete router as invalid or from future after update
+ m_RouterInfos.erase (ident);
+ if (wasFloodfill)
+ {
+ std::unique_lock<std::mutex> l(m_FloodfillsMutex);
+ m_Floodfills.Remove (r->GetIdentHash ());
+ }
+ m_Requests.RequestComplete (ident, nullptr);
+ return nullptr;
+ }
+ }
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated
{
LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64());
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
if (wasFloodfill)
- m_Floodfills.remove (r);
+ m_Floodfills.Remove (r->GetIdentHash ());
else if (r->IsEligibleFloodfill ())
- m_Floodfills.push_back (r);
+ {
+ if (m_Floodfills.GetSize () < NETDB_NUM_FLOODFILLS_THRESHOLD || r->GetProfile ()->IsReal ())
+ m_Floodfills.Insert (r);
+ else
+ r->ResetFlooldFill ();
+ }
}
}
else
@@ -295,7 +286,8 @@
else
{
r = std::make_shared<RouterInfo> (buf, len);
- if (!r->IsUnreachable () && r->HasValidAddresses ())
+ if (!r->IsUnreachable () && r->HasValidAddresses () && (!r->IsFloodfill () || !r->GetProfile ()->IsUnreachable ()) &&
+ i2p::util::GetMillisecondsSinceEpoch () + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL > r->GetTimestamp ())
{
bool inserted = false;
{
@@ -307,8 +299,14 @@
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64());
if (r->IsFloodfill () && r->IsEligibleFloodfill ())
{
- std::unique_lock<std::mutex> l(m_FloodfillsMutex);
- m_Floodfills.push_back (r);
+ if (m_Floodfills.GetSize () < NETDB_NUM_FLOODFILLS_THRESHOLD ||
+ r->GetProfile ()->IsReal ()) // don't insert floodfill until it's known real if we have enough
+ {
+ std::unique_lock<std::mutex> l(m_FloodfillsMutex);
+ m_Floodfills.Insert (r);
+ }
+ else
+ r->ResetFlooldFill ();
}
}
else
@@ -365,15 +363,16 @@
bool NetDb::AddLeaseSet2 (const IdentHash& ident, const uint8_t * buf, int len, uint8_t storeType)
{
- std::unique_lock<std::mutex> lock(m_LeaseSetsMutex);
auto leaseSet = std::make_shared<LeaseSet2> (storeType, buf, len, false); // we don't need leases in netdb
if (leaseSet->IsValid ())
{
+ std::unique_lock<std::mutex> lock(m_LeaseSetsMutex);
auto it = m_LeaseSets.find(ident);
if (it == m_LeaseSets.end () || it->second->GetStoreType () != storeType ||
leaseSet->GetPublishedTimestamp () > it->second->GetPublishedTimestamp ())
{
- if (leaseSet->IsPublic () && !leaseSet->IsExpired ())
+ if (leaseSet->IsPublic () && !leaseSet->IsExpired () &&
+ i2p::util::GetSecondsSinceEpoch () + NETDB_EXPIRATION_TIMEOUT_THRESHOLD > leaseSet->GetPublishedTimestamp ())
{
// TODO: implement actual update
LogPrint (eLogInfo, "NetDb: LeaseSet2 updated: ", ident.ToBase32());
@@ -382,7 +381,7 @@
}
else
{
- LogPrint (eLogWarning, "NetDb: Unpublished or expired LeaseSet2 received: ", ident.ToBase32());
+ LogPrint (eLogWarning, "NetDb: Unpublished or expired or future LeaseSet2 received: ", ident.ToBase32());
m_LeaseSets.erase (ident);
}
}
@@ -423,9 +422,24 @@
void NetDb::SetUnreachable (const IdentHash& ident, bool unreachable)
{
- auto it = m_RouterInfos.find (ident);
- if (it != m_RouterInfos.end ())
- return it->second->SetUnreachable (unreachable);
+ auto r = FindRouter (ident);
+ if (r)
+ {
+ r->SetUnreachable (unreachable);
+ auto profile = r->GetProfile ();
+ if (profile)
+ profile->Unreachable (unreachable);
+ }
+ }
+
+ void NetDb::ExcludeReachableTransports (const IdentHash& ident, RouterInfo::CompatibleTransports transports)
+ {
+ auto r = FindRouter (ident);
+ if (r)
+ {
+ std::unique_lock<std::mutex> l(m_RouterInfosMutex);
+ r->ExcludeReachableTransports (transports);
+ }
}
void NetDb::Reseed ()
@@ -437,15 +451,15 @@
}
// try reseeding from floodfill first if specified
- std::string riPath;
- if(i2p::config::GetOption("reseed.floodfill", riPath))
+ std::string riPath; i2p::config::GetOption("reseed.floodfill", riPath);
+ if (!riPath.empty())
{
auto ri = std::make_shared<RouterInfo>(riPath);
- if (ri->IsFloodfill())
+ if (ri->IsFloodfill())
{
const uint8_t * riData = ri->GetBuffer();
int riLen = ri->GetBufferLen();
- if (!i2p::data::netdb.AddRouterInfo(riData, riLen))
+ if (!i2p::data::netdb.AddRouterInfo(riData, riLen))
{
// bad router info
LogPrint(eLogError, "NetDb: Bad router info");
@@ -494,13 +508,13 @@
{
auto r = std::make_shared<RouterInfo>(path);
if (r->GetRouterIdentity () && !r->IsUnreachable () && r->HasValidAddresses () &&
- ts < r->GetTimestamp () + 24*60*60*NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT*1000LL)
+ ts < r->GetTimestamp () + 24*60*60*NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT*1000LL) // too old
{
r->DeleteBuffer ();
if (m_RouterInfos.emplace (r->GetIdentHash (), r).second)
{
if (r->IsFloodfill () && r->IsEligibleFloodfill ())
- m_Floodfills.push_back (r);
+ m_Floodfills.Insert (r);
}
}
else
@@ -584,7 +598,7 @@
{
// make sure we cleanup netDb from previous attempts
m_RouterInfos.clear ();
- m_Floodfills.clear ();
+ m_Floodfills.Clear ();
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
std::vector<std::string> files;
@@ -592,17 +606,20 @@
for (const auto& path : files)
LoadRouterInfo (path, ts);
- LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)");
+ LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.GetSize (), " floodfils)");
}
void NetDb::SaveUpdated ()
{
int updatedCount = 0, deletedCount = 0, deletedFloodfillsCount = 0;
auto total = m_RouterInfos.size ();
- auto totalFloodfills = m_Floodfills.size ();
+ auto totalFloodfills = m_Floodfills.GetSize ();
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
auto uptime = i2p::context.GetUptime ();
+ double minTunnelCreationSuccessRate;
+ i2p::config::GetOption("limits.zombies", minTunnelCreationSuccessRate);
+ bool isLowRate = i2p::tunnel::tunnels.GetPreciseTunnelCreationSuccessRate () < minTunnelCreationSuccessRate;
// routers don't expire if less than 90 or uptime is less than 1 hour
bool checkForExpiration = total > NETDB_MIN_ROUTERS && uptime > 600; // 10 minutes
if (checkForExpiration && uptime > 3600) // 1 hour
@@ -612,30 +629,50 @@
auto own = i2p::context.GetSharedRouterInfo ();
for (auto& it: m_RouterInfos)
{
- if (it.second == own) continue; // skip own
+ if (!it.second || it.second == own) continue; // skip own
std::string ident = it.second->GetIdentHashBase64();
if (it.second->IsUpdated ())
{
- it.second->SaveToFile (m_Storage.Path(ident));
+ if (it.second->GetBuffer ())
+ {
+ // we have something to save
+ it.second->SaveToFile (m_Storage.Path(ident));
+ it.second->SetUnreachable (false);
+ it.second->DeleteBuffer ();
+ }
it.second->SetUpdated (false);
- it.second->SetUnreachable (false);
- it.second->DeleteBuffer ();
updatedCount++;
continue;
}
+ if (it.second->GetProfile ()->IsUnreachable ())
+ it.second->SetUnreachable (true);
// make router reachable back if too few routers or floodfills
- if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS ||
+ if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate ||
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
it.second->SetUnreachable (false);
- // find & mark expired routers
- if (!it.second->IsReachable () && it.second->IsSSU (false))
+ if (!it.second->IsUnreachable ())
{
- if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)
- // RouterInfo expires after 1 hour if uses introducer
+ // find & mark expired routers
+ if (!it.second->GetCompatibleTransports (true)) // non reachable by any transport
it.second->SetUnreachable (true);
- }
- else if (checkForExpiration && ts > it.second->GetTimestamp () + expirationTimeout)
+ else if (ts + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < it.second->GetTimestamp ())
+ {
+ LogPrint (eLogWarning, "NetDb: RouterInfo is from future for ", (it.second->GetTimestamp () - ts)/1000LL, " seconds");
it.second->SetUnreachable (true);
+ }
+ else if (checkForExpiration)
+ {
+ if (ts > it.second->GetTimestamp () + expirationTimeout)
+ it.second->SetUnreachable (true);
+ else if ((ts > it.second->GetTimestamp () + expirationTimeout/2) && // more than half of expiration
+ total > NETDB_NUM_ROUTERS_THRESHOLD && !it.second->IsHighBandwidth() && // low bandwidth
+ !it.second->IsFloodfill() && (!i2p::context.IsFloodfill () || // non floodfill
+ (CreateRoutingKey (it.second->GetIdentHash ()) ^ i2p::context.GetIdentHash ()).metric[0] >= 0x02)) // different first 7 bits
+ it.second->SetUnreachable (true);
+ }
+ if (it.second->IsUnreachable () && i2p::transport::transports.IsConnected (it.second->GetIdentHash ()))
+ it.second->SetUnreachable (false); // don't expire connected router
+ }
if (it.second->IsUnreachable ())
{
@@ -648,6 +685,9 @@
} // m_RouterInfos iteration
m_RouterInfoBuffersPool.CleanUpMt ();
+ m_RouterInfoAddressesPool.CleanUpMt ();
+ m_RouterInfoAddressVectorsPool.CleanUpMt ();
+ m_IdentitiesPool.CleanUpMt ();
if (updatedCount > 0)
LogPrint (eLogInfo, "NetDb: Saved ", updatedCount, " new/updated routers");
@@ -659,23 +699,22 @@
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
{
- if (it->second->IsUnreachable ())
- {
- if (m_PersistProfiles) it->second->SaveProfile ();
+ if (!it->second || it->second->IsUnreachable ())
it = m_RouterInfos.erase (it);
- continue;
+ else
+ {
+ it->second->DropProfile ();
+ it++;
}
- ++it;
}
}
// clean up expired floodfills or not floodfills anymore
{
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
- for (auto it = m_Floodfills.begin (); it != m_Floodfills.end ();)
- if ((*it)->IsUnreachable () || !(*it)->IsFloodfill ())
- it = m_Floodfills.erase (it);
- else
- ++it;
+ m_Floodfills.Cleanup ([](const std::shared_ptr<RouterInfo>& r)->bool
+ {
+ return r && r->IsFloodfill () && !r->IsUnreachable ();
+ });
}
}
}
@@ -703,7 +742,11 @@
auto outbound = pool ? pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
auto inbound = pool ? pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
if (outbound && inbound)
- outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, dest->CreateRequestMessage (floodfill, inbound));
+ {
+ auto msg = dest->CreateRequestMessage (floodfill, inbound);
+ outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0,
+ i2p::garlic::WrapECIESX25519MessageForRouter (msg, floodfill->GetIdentity ()->GetEncryptionPublicKey ()));
+ }
else
{
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no tunnels found");
@@ -748,6 +791,11 @@
{
const uint8_t * buf = m->GetPayload ();
size_t len = m->GetSize ();
+ if (len < DATABASE_STORE_HEADER_SIZE)
+ {
+ LogPrint (eLogError, "NetDb: Database store msg is too short ", len, ". Dropped");
+ return;
+ }
IdentHash ident (buf + DATABASE_STORE_KEY_OFFSET);
if (ident.IsZero ())
{
@@ -758,19 +806,27 @@
size_t offset = DATABASE_STORE_HEADER_SIZE;
if (replyToken)
{
- auto deliveryStatus = CreateDeliveryStatusMsg (replyToken);
+ if (len < offset + 36) // 32 + 4
+ {
+ LogPrint (eLogError, "NetDb: Database store msg with reply token is too short ", len, ". Dropped");
+ return;
+ }
uint32_t tunnelID = bufbe32toh (buf + offset);
offset += 4;
- if (!tunnelID) // send response directly
- transports.SendMessage (buf + offset, deliveryStatus);
- else
+ if (replyToken != 0xFFFFFFFFU) // if not caught on OBEP or IBGW
{
- auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
- auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr;
- if (outbound)
- outbound->SendTunnelDataMsg (buf + offset, tunnelID, deliveryStatus);
+ auto deliveryStatus = CreateDeliveryStatusMsg (replyToken);
+ if (!tunnelID) // send response directly
+ transports.SendMessage (buf + offset, deliveryStatus);
else
- LogPrint (eLogWarning, "NetDb: No outbound tunnels for DatabaseStore reply found");
+ {
+ auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
+ auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr;
+ if (outbound)
+ outbound->SendTunnelDataMsgTo (buf + offset, tunnelID, deliveryStatus);
+ else
+ LogPrint (eLogWarning, "NetDb: No outbound tunnels for DatabaseStore reply found");
+ }
}
offset += 32;
}
@@ -786,7 +842,17 @@
uint8_t storeType = buf[DATABASE_STORE_TYPE_OFFSET];
if (storeType) // LeaseSet or LeaseSet2
{
- if (!m->from) // unsolicited LS must be received directly
+ if (len > MAX_LS_BUFFER_SIZE + offset)
+ {
+ LogPrint (eLogError, "NetDb: Database store message is too long ", len);
+ return;
+ }
+ if (!context.IsFloodfill ())
+ {
+ LogPrint (eLogInfo, "NetDb: Not Floodfill, LeaseSet store request ignored for ", ident.ToBase32());
+ return;
+ }
+ else if (!m->from) // unsolicited LS must be received directly
{
if (storeType == NETDB_STORE_TYPE_LEASESET) // 1
{
@@ -795,7 +861,7 @@
}
else // all others are considered as LeaseSet2
{
- LogPrint (eLogDebug, "NetDb: Store request: LeaseSet2 of type ", storeType, " for ", ident.ToBase32());
+ LogPrint (eLogDebug, "NetDb: Store request: LeaseSet2 of type ", int(storeType), " for ", ident.ToBase32());
updated = AddLeaseSet2 (ident, buf + offset, len - offset, storeType);
}
}
@@ -872,7 +938,7 @@
{
// request destination
LogPrint (eLogDebug, "NetDb: Try ", key, " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ());
- outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
+ outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
dest->CreateRequestMessage (nextFloodfill, inbound));
deleteDest = false;
}
@@ -954,6 +1020,11 @@
std::shared_ptr<I2NPMessage> replyMsg;
if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP)
{
+ if (!context.IsFloodfill ())
+ {
+ LogPrint (eLogWarning, "NetDb: Exploratory lookup to non-floodfill dropped");
+ return;
+ }
LogPrint (eLogInfo, "NetDb: Exploratory close to ", key, " ", numExcluded, " excluded");
std::set<IdentHash> excludedRouters;
const uint8_t * excluded_ident = excluded;
@@ -979,12 +1050,12 @@
if (lookupType == DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP ||
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)
{
+ // try to find router
auto router = FindRouter (ident);
- if (router)
+ if (router && !router->IsUnreachable ())
{
LogPrint (eLogDebug, "NetDb: Requested RouterInfo ", key, " found");
- PopulateRouterInfoBuffer (router);
- if (router->GetBuffer ())
+ if (PopulateRouterInfoBuffer (router))
replyMsg = CreateDatabaseStoreMsg (router);
}
}
@@ -992,17 +1063,26 @@
if (!replyMsg && (lookupType == DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP ||
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP))
{
- auto leaseSet = FindLeaseSet (ident);
- if (!leaseSet)
- {
- // no lease set found
- LogPrint(eLogDebug, "NetDb: Requested LeaseSet not found for ", ident.ToBase32());
- }
- else if (!leaseSet->IsExpired ()) // we don't send back our LeaseSets
+ // try to find leaseset
+ if (context.IsFloodfill ())
+ {
+ auto leaseSet = FindLeaseSet (ident);
+ if (!leaseSet)
+ {
+ // no leaseset found
+ LogPrint(eLogDebug, "NetDb: Requested LeaseSet not found for ", ident.ToBase32());
+ }
+ else if (!leaseSet->IsExpired ()) // we don't send back expired leasesets
+ {
+ LogPrint (eLogDebug, "NetDb: Requested LeaseSet ", key, " found");
+ replyMsg = CreateDatabaseStoreMsg (ident, leaseSet);
+ }
+ }
+ else if (lookupType == DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP)
{
- LogPrint (eLogDebug, "NetDb: Requested LeaseSet ", key, " found");
- replyMsg = CreateDatabaseStoreMsg (ident, leaseSet);
- }
+ LogPrint (eLogWarning, "NetDb: Explicit LeaseSet lookup to non-floodfill dropped");
+ return;
+ }
}
if (!replyMsg)
@@ -1053,7 +1133,7 @@
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
if (outbound)
- outbound->SendTunnelDataMsg (replyIdent, replyTunnelID, replyMsg);
+ outbound->SendTunnelDataMsgTo (replyIdent, replyTunnelID, replyMsg);
else
transports.SendMessage (replyIdent, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg));
}
@@ -1062,16 +1142,6 @@
}
}
- void NetDb::HandleDeliveryStatusMsg (std::shared_ptr<const I2NPMessage> msg)
- {
- if (m_PublishReplyToken == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
- {
- LogPrint (eLogInfo, "NetDb: Publishing confirmed. reply token=", m_PublishReplyToken);
- m_PublishExcluded.clear ();
- m_PublishReplyToken = 0;
- }
- }
-
void NetDb::Explore (int numDestinations)
{
// new requests
@@ -1119,42 +1189,7 @@
m_Requests.RequestComplete (randomHash, nullptr);
}
if (throughTunnels && msgs.size () > 0)
- outbound->SendTunnelDataMsg (msgs);
- }
-
- void NetDb::Publish ()
- {
- i2p::context.UpdateStats (); // for floodfill
-
- if (m_PublishExcluded.size () > NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS)
- {
- LogPrint (eLogError, "NetDb: Couldn't publish our RouterInfo to ", NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again");
- m_PublishExcluded.clear ();
- }
-
- auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
- if (floodfill)
- {
- uint32_t replyToken;
- RAND_bytes ((uint8_t *)&replyToken, 4);
- LogPrint (eLogInfo, "NetDb: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
- m_PublishExcluded.insert (floodfill->GetIdentHash ());
- m_PublishReplyToken = replyToken;
- if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
- i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
- // send directly
- transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
- else
- {
- // otherwise through exploratory
- auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
- auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
- auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
- if (inbound && outbound)
- outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0,
- CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound));
- }
- }
+ outbound->SendTunnelDataMsgs (msgs);
}
void NetDb::Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg)
@@ -1186,25 +1221,17 @@
});
}
- std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const
+ std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith,
+ bool reverse, bool endpoint) const
{
return GetRandomRouter (
- [compatibleWith, reverse](std::shared_ptr<const RouterInfo> router)->bool
+ [compatibleWith, reverse, endpoint](std::shared_ptr<const RouterInfo> router)->bool
{
return !router->IsHidden () && router != compatibleWith &&
- (reverse ? compatibleWith->IsReachableFrom (*router) :
+ (reverse ? (compatibleWith->IsReachableFrom (*router) && router->GetCompatibleTransports (true)):
router->IsReachableFrom (*compatibleWith)) &&
- router->IsECIES ();
- });
- }
-
- std::shared_ptr<const RouterInfo> NetDb::GetRandomPeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const
- {
- return GetRandomRouter (
- [v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
- {
- return !router->IsHidden () && router->IsECIES () &&
- router->IsPeerTesting (v4) && !excluded.count (router->GetIdentHash ());
+ router->IsECIES () && !router->IsHighCongestion (false) &&
+ (!endpoint || (router->IsV4 () && (!reverse || router->IsPublished (true)))); // endpoint must be ipv4 and published if inbound(reverse)
});
}
@@ -1217,47 +1244,31 @@
router->IsSSU2PeerTesting (v4) && !excluded.count (router->GetIdentHash ());
});
}
-
- std::shared_ptr<const RouterInfo> NetDb::GetRandomSSUV6Router () const
- {
- return GetRandomRouter (
- [](std::shared_ptr<const RouterInfo> router)->bool
- {
- return !router->IsHidden () && router->IsECIES () && router->IsSSUV6 ();
- });
- }
-
- std::shared_ptr<const RouterInfo> NetDb::GetRandomIntroducer (bool v4, const std::set<IdentHash>& excluded) const
- {
- return GetRandomRouter (
- [v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
- {
- return !router->IsHidden () && router->IsECIES () && !router->IsFloodfill () && // floodfills don't send relay tag
- router->IsIntroducer (v4) && !excluded.count (router->GetIdentHash ());
- });
- }
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const
{
return GetRandomRouter (
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
{
- return !router->IsHidden () && router->IsSSU2Introducer (v4) &&
+ return !router->IsHidden () && router->IsSSU2Introducer (v4) &&
!excluded.count (router->GetIdentHash ());
});
}
-
- std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const
+
+ std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith,
+ bool reverse, bool endpoint) const
{
return GetRandomRouter (
- [compatibleWith, reverse](std::shared_ptr<const RouterInfo> router)->bool
+ [compatibleWith, reverse, endpoint](std::shared_ptr<const RouterInfo> router)->bool
{
return !router->IsHidden () && router != compatibleWith &&
- (reverse ? compatibleWith->IsReachableFrom (*router) :
+ (reverse ? (compatibleWith->IsReachableFrom (*router) && router->GetCompatibleTransports (true)) :
router->IsReachableFrom (*compatibleWith)) &&
(router->GetCaps () & RouterInfo::eHighBandwidth) &&
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
- router->IsECIES ();
+ router->IsECIES () && !router->IsHighCongestion (true) &&
+ (!endpoint || (router->IsV4 () && (!reverse || router->IsPublished (true)))); // endpoint must be ipv4 and published if inbound(reverse)
+
});
}
@@ -1269,7 +1280,9 @@
uint16_t inds[3];
RAND_bytes ((uint8_t *)inds, sizeof (inds));
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
- inds[0] %= m_RouterInfos.size ();
+ auto count = m_RouterInfos.size ();
+ if(count == 0) return nullptr;
+ inds[0] %= count;
auto it = m_RouterInfos.begin ();
std::advance (it, inds[0]);
// try random router
@@ -1325,79 +1338,39 @@
}
std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination,
- const std::set<IdentHash>& excluded, bool closeThanUsOnly) const
+ const std::set<IdentHash>& excluded) const
{
- std::shared_ptr<const RouterInfo> r;
- XORMetric minMetric;
IdentHash destKey = CreateRoutingKey (destination);
- if (closeThanUsOnly)
- minMetric = destKey ^ i2p::context.GetIdentHash ();
- else
- minMetric.SetMax ();
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
- for (const auto& it: m_Floodfills)
- {
- if (!it->IsUnreachable ())
+ return m_Floodfills.FindClosest (destKey, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool
{
- XORMetric m = destKey ^ it->GetIdentHash ();
- if (m < minMetric && !excluded.count (it->GetIdentHash ()))
- {
- minMetric = m;
- r = it;
- }
- }
- }
- return r;
+ return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () &&
+ !excluded.count (r->GetIdentHash ());
+ });
}
std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded, bool closeThanUsOnly) const
{
- struct Sorted
- {
- std::shared_ptr<const RouterInfo> r;
- XORMetric metric;
- bool operator< (const Sorted& other) const { return metric < other.metric; };
- };
-
- std::set<Sorted> sorted;
+ std::vector<IdentHash> res;
IdentHash destKey = CreateRoutingKey (destination);
- XORMetric ourMetric;
- if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash ();
+ std::vector<std::shared_ptr<RouterInfo> > v;
{
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
- for (const auto& it: m_Floodfills)
- {
- if (!it->IsUnreachable ())
+ v = m_Floodfills.FindClosest (destKey, num, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool
{
- XORMetric m = destKey ^ it->GetIdentHash ();
- if (closeThanUsOnly && ourMetric < m) continue;
- if (sorted.size () < num)
- sorted.insert ({it, m});
- else if (m < sorted.rbegin ()->metric)
- {
- sorted.insert ({it, m});
- sorted.erase (std::prev (sorted.end ()));
- }
- }
- }
+ return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () &&
+ !excluded.count (r->GetIdentHash ());
+ });
}
+ if (v.empty ()) return res;
- std::vector<IdentHash> res;
- size_t i = 0;
- for (const auto& it: sorted)
+ XORMetric ourMetric;
+ if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash ();
+ for (auto& it: v)
{
- if (i < num)
- {
- const auto& ident = it.r->GetIdentHash ();
- if (!excluded.count (ident))
- {
- res.push_back (ident);
- i++;
- }
- }
- else
- break;
+ if (closeThanUsOnly && ourMetric < (destKey ^ it->GetIdentHash ())) break;
+ res.push_back (it->GetIdentHash ());
}
return res;
}
@@ -1434,6 +1407,17 @@
return r;
}
+ void NetDb::ManageRouterInfos ()
+ {
+ auto ts = i2p::util::GetSecondsSinceEpoch ();
+ {
+ std::unique_lock<std::mutex> l(m_RouterInfosMutex);
+ for (auto& it: m_RouterInfos)
+ it.second->UpdateIntroducers (ts);
+ }
+ SaveUpdated ();
+ }
+
void NetDb::ManageLeaseSets ()
{
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
@@ -1450,10 +1434,11 @@
m_LeasesPool.CleanUpMt ();
}
- void NetDb::PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r)
+ bool NetDb::PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r)
{
- if (!r || r->GetBuffer ()) return;
- r->LoadBuffer (m_Storage.Path (r->GetIdentHashBase64 ()));
- }
+ if (!r) return false;
+ if (r->GetBuffer ()) return true;
+ return r->LoadBuffer (m_Storage.Path (r->GetIdentHashBase64 ()));
+ }
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/NetDb.hpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -12,7 +12,6 @@
#include <inttypes.h>
#include <set>
#include <unordered_map>
-#include <list>
#include <string>
#include <thread>
#include <mutex>
@@ -31,6 +30,7 @@
#include "Family.h"
#include "version.h"
#include "util.h"
+#include "KadDHT.h"
namespace i2p
{
@@ -38,16 +38,15 @@
{
const int NETDB_MIN_ROUTERS = 90;
const int NETDB_MIN_FLOODFILLS = 5;
+ const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1500;
+ const int NETDB_NUM_ROUTERS_THRESHOLD = 4*NETDB_NUM_FLOODFILLS_THRESHOLD;
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds
- const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65 * 60;
const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours
const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours
const int NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days
- const int NETDB_PUBLISH_INTERVAL = 60 * 40;
- const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
- const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
- const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 36); // 0.9.36
- const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 38); // 0.9.38
+ const int NETDB_EXPIRATION_TIMEOUT_THRESHOLD = 2*60; // 2 minutes
+ const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
+ const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
/** function for visiting a leaseset stored in a floodfill */
@@ -84,34 +83,28 @@
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
- void HandleDeliveryStatusMsg (std::shared_ptr<const I2NPMessage> msg);
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
- std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
- std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
- std::shared_ptr<const RouterInfo> GetRandomPeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
+ std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const;
+ std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const;
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
- std::shared_ptr<const RouterInfo> GetRandomSSUV6Router () const; // TODO: change to v6 peer test later
- std::shared_ptr<const RouterInfo> GetRandomIntroducer (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const;
- std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
+ std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily (FamilyID fam) const;
void SetUnreachable (const IdentHash& ident, bool unreachable);
+ void ExcludeReachableTransports (const IdentHash& ident, RouterInfo::CompatibleTransports transports);
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
- /** set hidden mode, aka don't publish our RI to netdb and don't explore */
- void SetHidden(bool hide);
-
void Reseed ();
Families& GetFamilies () { return m_Families; };
// for web interface
int GetNumRouters () const { return m_RouterInfos.size (); };
- int GetNumFloodfills () const { return m_Floodfills.size (); };
+ int GetNumFloodfills () const { return m_Floodfills.GetSize (); };
int GetNumLeaseSets () const { return m_LeaseSets.size (); };
/** visit all lease sets we currently store */
@@ -125,8 +118,18 @@
void ClearRouterInfos () { m_RouterInfos.clear (); };
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
- void PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
- std::shared_ptr<Lease> NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); };
+ bool PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
+ std::shared_ptr<RouterInfo::Address> NewRouterInfoAddress () { return m_RouterInfoAddressesPool.AcquireSharedMt (); };
+ boost::shared_ptr<RouterInfo::Addresses> NewRouterInfoAddresses ()
+ {
+ return boost::shared_ptr<RouterInfo::Addresses>(m_RouterInfoAddressVectorsPool.AcquireMt (),
+ std::bind <void (i2p::util::MemoryPoolMt<RouterInfo::Addresses>::*)(RouterInfo::Addresses *)>
+ (&i2p::util::MemoryPoolMt<RouterInfo::Addresses>::ReleaseMt,
+ &m_RouterInfoAddressVectorsPool, std::placeholders::_1));
+ };
+ std::shared_ptr<Lease> NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); };
+ std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) { return m_IdentitiesPool.AcquireSharedMt (buf, len); };
+ std::shared_ptr<RouterProfile> NewRouterProfile () { return m_RouterProfilesPool.AcquireSharedMt (); };
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
@@ -137,8 +140,8 @@
void SaveUpdated ();
void Run (); // exploratory thread
void Explore (int numDestinations);
- void Publish ();
void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg);
+ void ManageRouterInfos ();
void ManageLeaseSets ();
void ManageRequests ();
@@ -157,7 +160,7 @@
mutable std::mutex m_RouterInfosMutex;
std::unordered_map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
mutable std::mutex m_FloodfillsMutex;
- std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
+ DHTTable m_Floodfills;
bool m_IsRunning;
std::thread * m_Thread;
@@ -176,14 +179,15 @@
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
- /** true if in hidden mode */
- bool m_HiddenMode;
-
std::set<IdentHash> m_PublishExcluded;
uint32_t m_PublishReplyToken = 0;
i2p::util::MemoryPoolMt<RouterInfo::Buffer> m_RouterInfoBuffersPool;
+ i2p::util::MemoryPoolMt<RouterInfo::Address> m_RouterInfoAddressesPool;
+ i2p::util::MemoryPoolMt<RouterInfo::Addresses> m_RouterInfoAddressVectorsPool;
i2p::util::MemoryPoolMt<Lease> m_LeasesPool;
+ i2p::util::MemoryPoolMt<IdentityEx> m_IdentitiesPool;
+ i2p::util::MemoryPoolMt<RouterProfile> m_RouterProfilesPool;
};
extern NetDb netdb;
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/NetDbRequests.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -137,7 +137,7 @@
auto inbound = pool->GetNextInboundTunnel ();
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
if (nextFloodfill && outbound && inbound)
- outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
+ outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
dest->CreateRequestMessage (nextFloodfill, inbound));
else
{
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Profiling.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -7,34 +7,43 @@
*/
#include <sys/stat.h>
+#include <unordered_map>
+#include <list>
+#include <thread>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include "Base.h"
#include "FS.h"
#include "Log.h"
+#include "Timestamp.h"
+#include "NetDb.hpp"
#include "Profiling.h"
namespace i2p
{
namespace data
{
- i2p::fs::HashedStorage m_ProfilesStorage("peerProfiles", "p", "profile-", "txt");
+ static i2p::fs::HashedStorage g_ProfilesStorage("peerProfiles", "p", "profile-", "txt");
+ static std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > g_Profiles;
+ static std::mutex g_ProfilesMutex;
- RouterProfile::RouterProfile ():
- m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
- m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
- m_NumTimesTaken (0), m_NumTimesRejected (0)
+ static boost::posix_time::ptime GetTime ()
{
+ return boost::posix_time::second_clock::local_time();
}
- boost::posix_time::ptime RouterProfile::GetTime () const
+ RouterProfile::RouterProfile ():
+ m_LastUpdateTime (GetTime ()), m_IsUpdated (false),
+ m_LastDeclineTime (0), m_LastUnreachableTime (0),
+ m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
+ m_NumTimesTaken (0), m_NumTimesRejected (0), m_HasConnected (false)
{
- return boost::posix_time::second_clock::local_time();
}
void RouterProfile::UpdateTime ()
{
m_LastUpdateTime = GetTime ();
+ m_IsUpdated = true;
}
void RouterProfile::Save (const IdentHash& identHash)
@@ -47,15 +56,18 @@
boost::property_tree::ptree usage;
usage.put (PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken);
usage.put (PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected);
+ usage.put (PEER_PROFILE_USAGE_CONNECTED, m_HasConnected);
// fill property tree
boost::property_tree::ptree pt;
pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
+ if (m_LastUnreachableTime)
+ pt.put (PEER_PROFILE_LAST_UNREACHABLE_TIME, m_LastUnreachableTime);
pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation);
pt.put_child (PEER_PROFILE_SECTION_USAGE, usage);
// save to file
std::string ident = identHash.ToBase64 ();
- std::string path = m_ProfilesStorage.Path(ident);
+ std::string path = g_ProfilesStorage.Path(ident);
try {
boost::property_tree::write_ini (path, pt);
@@ -68,7 +80,7 @@
void RouterProfile::Load (const IdentHash& identHash)
{
std::string ident = identHash.ToBase64 ();
- std::string path = m_ProfilesStorage.Path(ident);
+ std::string path = g_ProfilesStorage.Path(ident);
boost::property_tree::ptree pt;
if (!i2p::fs::Exists(path))
@@ -94,6 +106,7 @@
m_LastUpdateTime = boost::posix_time::time_from_string (t);
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
{
+ m_LastUnreachableTime = pt.get (PEER_PROFILE_LAST_UNREACHABLE_TIME, 0);
try
{
// read participations
@@ -112,6 +125,7 @@
auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
+ m_HasConnected = usage.get (PEER_PROFILE_USAGE_CONNECTED, false);
}
catch (boost::property_tree::ptree_bad_path& ex)
{
@@ -131,14 +145,36 @@
{
UpdateTime ();
if (ret > 0)
+ {
m_NumTunnelsDeclined++;
+ m_LastDeclineTime = i2p::util::GetSecondsSinceEpoch ();
+ }
else
- m_NumTunnelsAgreed++;
+ {
+ m_NumTunnelsAgreed++;
+ m_LastDeclineTime = 0;
+ }
}
void RouterProfile::TunnelNonReplied ()
{
- m_NumTunnelsNonReplied++;
+ m_NumTunnelsNonReplied++;
+ UpdateTime ();
+ if (m_NumTunnelsNonReplied > 2*m_NumTunnelsAgreed && m_NumTunnelsNonReplied > 3)
+ {
+ m_LastDeclineTime = i2p::util::GetSecondsSinceEpoch ();
+ }
+ }
+
+ void RouterProfile::Unreachable (bool unreachable)
+ {
+ m_LastUnreachableTime = unreachable ? i2p::util::GetSecondsSinceEpoch () : 0;
+ UpdateTime ();
+ }
+
+ void RouterProfile::Connected ()
+ {
+ m_HasConnected = true;
UpdateTime ();
}
@@ -153,8 +189,19 @@
return m_NumTunnelsNonReplied > 10*(total + 1);
}
+ bool RouterProfile::IsDeclinedRecently ()
+ {
+ if (!m_LastDeclineTime) return false;
+ auto ts = i2p::util::GetSecondsSinceEpoch ();
+ if (ts > m_LastDeclineTime + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL ||
+ ts + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL < m_LastDeclineTime)
+ m_LastDeclineTime = 0;
+ return (bool)m_LastDeclineTime;
+ }
+
bool RouterProfile::IsBad ()
{
+ if (IsDeclinedRecently () || IsUnreachable ()) return true;
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
{
@@ -168,32 +215,103 @@
return isBad;
}
+ bool RouterProfile::IsUnreachable ()
+ {
+ if (!m_LastUnreachableTime) return false;
+ auto ts = i2p::util::GetSecondsSinceEpoch ();
+ if (ts > m_LastUnreachableTime + PEER_PROFILE_UNREACHABLE_INTERVAL ||
+ ts + PEER_PROFILE_UNREACHABLE_INTERVAL < m_LastUnreachableTime)
+ m_LastUnreachableTime = 0;
+ return (bool)m_LastUnreachableTime;
+ }
+
+ bool RouterProfile::IsUseful() const
+ {
+ return IsReal () || m_NumTunnelsNonReplied >= PEER_PROFILE_USEFUL_THRESHOLD;
+ }
+
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
{
- auto profile = std::make_shared<RouterProfile> ();
+ {
+ std::unique_lock<std::mutex> l(g_ProfilesMutex);
+ auto it = g_Profiles.find (identHash);
+ if (it != g_Profiles.end ())
+ return it->second;
+ }
+ auto profile = netdb.NewRouterProfile ();
profile->Load (identHash); // if possible
+ std::unique_lock<std::mutex> l(g_ProfilesMutex);
+ g_Profiles.emplace (identHash, profile);
return profile;
}
void InitProfilesStorage ()
{
- m_ProfilesStorage.SetPlace(i2p::fs::GetDataDir());
- m_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
+ g_ProfilesStorage.SetPlace(i2p::fs::GetDataDir());
+ g_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
+ }
+
+ void PersistProfiles ()
+ {
+ auto ts = GetTime ();
+ std::list<std::pair<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > > tmp;
+ {
+ std::unique_lock<std::mutex> l(g_ProfilesMutex);
+ for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
+ {
+ if ((ts - it->second->GetLastUpdateTime ()).total_seconds () > PEER_PROFILE_PERSIST_INTERVAL)
+ {
+ if (it->second->IsUpdated ())
+ tmp.push_back (std::make_pair (it->first, it->second));
+ it = g_Profiles.erase (it);
+ }
+ else
+ it++;
+ }
+ }
+ for (auto& it: tmp)
+ if (it.second) it.second->Save (it.first);
+ }
+
+ void SaveProfiles ()
+ {
+ std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > tmp;
+ {
+ std::unique_lock<std::mutex> l(g_ProfilesMutex);
+ tmp = g_Profiles;
+ g_Profiles.clear ();
+ }
+ auto ts = GetTime ();
+ for (auto& it: tmp)
+ if (it.second->IsUseful() && (it.second->IsUpdated () || (ts - it.second->GetLastUpdateTime ()).total_seconds () < PEER_PROFILE_EXPIRATION_TIMEOUT*3600))
+ it.second->Save (it.first);
}
void DeleteObsoleteProfiles ()
{
+ {
+ auto ts = GetTime ();
+ std::unique_lock<std::mutex> l(g_ProfilesMutex);
+ for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
+ {
+ if ((ts - it->second->GetLastUpdateTime ()).total_seconds () >= PEER_PROFILE_EXPIRATION_TIMEOUT*3600)
+ it = g_Profiles.erase (it);
+ else
+ it++;
+ }
+ }
+
struct stat st;
std::time_t now = std::time(nullptr);
std::vector<std::string> files;
- m_ProfilesStorage.Traverse(files);
+ g_ProfilesStorage.Traverse(files);
for (const auto& path: files) {
if (stat(path.c_str(), &st) != 0) {
LogPrint(eLogWarning, "Profiling: Can't stat(): ", path);
continue;
}
- if (((now - st.st_mtime) / 3600) >= PEER_PROFILE_EXPIRATION_TIMEOUT) {
+ if (now - st.st_mtime >= PEER_PROFILE_EXPIRATION_TIMEOUT*3600) {
LogPrint(eLogDebug, "Profiling: Removing expired peer profile: ", path);
i2p::fs::Remove(path);
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Profiling.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -22,43 +22,60 @@
const char PEER_PROFILE_SECTION_USAGE[] = "usage";
// params
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime";
+ const char PEER_PROFILE_LAST_UNREACHABLE_TIME[] = "lastunreachabletime";
const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined";
const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied";
const char PEER_PROFILE_USAGE_TAKEN[] = "taken";
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
-
- const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days)
- const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 24 * 3600; // in seconds (1 day)
- const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3 * 3600; // in seconds (3 hours)
+ const char PEER_PROFILE_USAGE_CONNECTED[] = "connected";
+
+ const int PEER_PROFILE_EXPIRATION_TIMEOUT = 36; // in hours (1.5 days)
+ const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 3 * 3600; // in seconds (3 hours)
+ const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3600; // in seconds (1 hour)
+ const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 150; // in seconds (2.5 minutes)
+ const int PEER_PROFILE_PERSIST_INTERVAL = 3300; // in seconds (55 minutes)
+ const int PEER_PROFILE_UNREACHABLE_INTERVAL = 2*3600; // on seconds (2 hours)
+ const int PEER_PROFILE_USEFUL_THRESHOLD = 3;
class RouterProfile
{
public:
RouterProfile ();
- RouterProfile& operator= (const RouterProfile& ) = default;
void Save (const IdentHash& identHash);
void Load (const IdentHash& identHash);
bool IsBad ();
+ bool IsUnreachable ();
+ bool IsReal () const { return m_HasConnected || m_NumTunnelsAgreed > 0 || m_NumTunnelsDeclined > 0; }
void TunnelBuildResponse (uint8_t ret);
void TunnelNonReplied ();
+ void Unreachable (bool unreachable);
+ void Connected ();
+
+ boost::posix_time::ptime GetLastUpdateTime () const { return m_LastUpdateTime; };
+ bool IsUpdated () const { return m_IsUpdated; };
+
+ bool IsUseful() const;
+
private:
- boost::posix_time::ptime GetTime () const;
void UpdateTime ();
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
bool IsLowPartcipationRate () const;
bool IsLowReplyRate () const;
+ bool IsDeclinedRecently ();
private:
- boost::posix_time::ptime m_LastUpdateTime;
+ boost::posix_time::ptime m_LastUpdateTime; // TODO: use std::chrono
+ bool m_IsUpdated;
+ uint64_t m_LastDeclineTime, m_LastUnreachableTime; // in seconds
// participation
uint32_t m_NumTunnelsAgreed;
uint32_t m_NumTunnelsDeclined;
@@ -66,11 +83,14 @@
// usage
uint32_t m_NumTimesTaken;
uint32_t m_NumTimesRejected;
+ bool m_HasConnected; // successful trusted(incoming or NTCP2) connection
};
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
void InitProfilesStorage ();
void DeleteObsoleteProfiles ();
+ void SaveProfiles ();
+ void PersistProfiles ();
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Reseed.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -153,7 +153,7 @@
return ProcessSU3Stream (s);
else
{
- LogPrint (eLogError, "Reseed: Can't open file ", filename);
+ LogPrint (eLogCritical, "Reseed: Can't open file ", filename);
return 0;
}
}
@@ -170,7 +170,7 @@
}
else
{
- LogPrint (eLogError, "Reseed: Can't open file ", filename);
+ LogPrint (eLogCritical, "Reseed: Can't open file ", filename);
return 0;
}
}
@@ -278,7 +278,7 @@
if (verify) // not verified
{
- LogPrint (eLogError, "Reseed: SU3 verification failed");
+ LogPrint (eLogCritical, "Reseed: SU3 verification failed");
return 0;
}
@@ -320,7 +320,7 @@
uint16_t fileNameLength, extraFieldLength;
s.read ((char *)&fileNameLength, 2);
fileNameLength = le16toh (fileNameLength);
- if ( fileNameLength > 255 ) {
+ if ( fileNameLength >= 255 ) {
// too big
LogPrint(eLogError, "Reseed: SU3 fileNameLength too large: ", fileNameLength);
return numFiles;
@@ -492,7 +492,7 @@
SSL_free (ssl);
}
else
- LogPrint (eLogError, "Reseed: Can't open certificate file ", filename);
+ LogPrint (eLogCritical, "Reseed: Can't open certificate file ", filename);
SSL_CTX_free (ctx);
}
@@ -534,17 +534,17 @@
}
// check for valid proxy url schema
if (proxyUrl.schema != "http" && proxyUrl.schema != "socks") {
- LogPrint(eLogError, "Reseed: Bad proxy url: ", proxy);
+ LogPrint(eLogCritical, "Reseed: Bad proxy url: ", proxy);
return "";
}
} else {
- LogPrint(eLogError, "Reseed: Bad proxy url: ", proxy);
+ LogPrint(eLogCritical, "Reseed: Bad proxy url: ", proxy);
return "";
}
}
i2p::http::URL url;
if (!url.parse(address)) {
- LogPrint(eLogError, "Reseed: Failed to parse url: ", address);
+ LogPrint(eLogCritical, "Reseed: Failed to parse url: ", address);
return "";
}
url.schema = "https";
@@ -687,12 +687,23 @@
while (it != end)
{
boost::asio::ip::tcp::endpoint ep = *it;
- if ((ep.address ().is_v4 () && i2p::context.SupportsV4 ()) ||
- (ep.address ().is_v6 () && i2p::context.SupportsV6 ()))
+ if (
+ (
+ !i2p::util::net::IsInReservedRange(ep.address ()) && (
+ (ep.address ().is_v4 () && i2p::context.SupportsV4 ()) ||
+ (ep.address ().is_v6 () && i2p::context.SupportsV6 ())
+ )
+ ) ||
+ (
+ i2p::util::net::IsYggdrasilAddress (ep.address ()) &&
+ i2p::context.SupportsMesh ()
+ )
+ )
{
s.lowest_layer().connect (ep, ecode);
if (!ecode)
{
+ LogPrint (eLogDebug, "Reseed: Resolved to ", ep.address ());
connected = true;
break;
}
@@ -780,17 +791,45 @@
boost::asio::io_service service;
boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6());
- if (url.host.length () < 2) return ""; // assume []
- auto host = url.host.substr (1, url.host.length () - 2);
- LogPrint (eLogDebug, "Reseed: Connecting to Yggdrasil ", url.host, ":", url.port);
- s.connect (boost::asio::ip::tcp::endpoint (boost::asio::ip::address_v6::from_string (host), url.port), ecode);
+ auto it = boost::asio::ip::tcp::resolver(service).resolve (
+ boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode);
+
+ if (!ecode)
+ {
+ bool connected = false;
+ boost::asio::ip::tcp::resolver::iterator end;
+ while (it != end)
+ {
+ boost::asio::ip::tcp::endpoint ep = *it;
+ if (
+ i2p::util::net::IsYggdrasilAddress (ep.address ()) &&
+ i2p::context.SupportsMesh ()
+ )
+ {
+ LogPrint (eLogDebug, "Reseed: Yggdrasil: Resolved to ", ep.address ());
+ s.connect (ep, ecode);
+ if (!ecode)
+ {
+ connected = true;
+ break;
+ }
+ }
+ it++;
+ }
+ if (!connected)
+ {
+ LogPrint(eLogError, "Reseed: Yggdrasil: Failed to connect to ", url.host);
+ return "";
+ }
+ }
+
if (!ecode)
{
- LogPrint (eLogDebug, "Reseed: Connected to Yggdrasil ", url.host, ":", url.port);
+ LogPrint (eLogDebug, "Reseed: Yggdrasil: Connected to ", url.host, ":", url.port);
return ReseedRequest (s, url.to_string());
}
else
- LogPrint (eLogError, "Reseed: Couldn't connect to Yggdrasil ", url.host, ": ", ecode.message ());
+ LogPrint (eLogError, "Reseed: Yggdrasil: Couldn't connect to ", url.host, ": ", ecode.message ());
return "";
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/RouterContext.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -20,6 +20,8 @@
#include "Log.h"
#include "Family.h"
#include "ECIESX25519AEADRatchetSession.h"
+#include "Transports.h"
+#include "Tunnel.h"
#include "RouterContext.h"
namespace i2p
@@ -29,7 +31,9 @@
RouterContext::RouterContext ():
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown),
- m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_NetID (I2PD_NET_ID)
+ m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone),
+ m_Testing (false), m_TestingV6 (false), m_NetID (I2PD_NET_ID),
+ m_PublishReplyToken (0), m_IsHiddenMode (false)
{
}
@@ -47,6 +51,34 @@
m_ECIESSession = std::make_shared<i2p::garlic::RouterIncomingRatchetSession>(m_InitialNoiseState);
}
+ void RouterContext::Start ()
+ {
+ if (!m_Service)
+ {
+ m_Service.reset (new RouterService);
+ m_Service->Start ();
+ if (!m_IsHiddenMode)
+ {
+ m_PublishTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
+ ScheduleInitialPublish ();
+ m_CongestionUpdateTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
+ ScheduleCongestionUpdate ();
+ }
+ }
+ }
+
+ void RouterContext::Stop ()
+ {
+ if (m_Service)
+ {
+ if (m_PublishTimer)
+ m_PublishTimer->cancel ();
+ if (m_CongestionUpdateTimer)
+ m_CongestionUpdateTimer->cancel ();
+ m_Service->Stop ();
+ }
+ }
+
void RouterContext::CreateNewRouter ()
{
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
@@ -63,7 +95,6 @@
if (!port) port = SelectRandomPort ();
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
- bool ssu; i2p::config::GetOption("ssu", ssu);
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
@@ -86,96 +117,103 @@
bool ssu2Published = false;
if (ssu2)
i2p::config::GetOption("ssu2.published", ssu2Published);
- uint8_t caps = 0, addressCaps = 0;
+ uint8_t caps = 0;
if (ipv4)
{
- std::string host = "127.0.0.1";
- if (!i2p::config::IsDefault("host"))
- i2p::config::GetOption("host", host);
- else if (!nat)
- {
+ std::string host;
+ if (!nat)
// we have no NAT so set external address from local address
- std::string address4; i2p::config::GetOption("address4", address4);
- if (!address4.empty ()) host = address4;
- }
+ i2p::config::GetOption("address4", host);
+ if (host.empty ()) i2p::config::GetOption("host", host);
if (ntcp2)
{
- if (ntcp2Published)
- routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v4::from_string (host), port);
- else // add non-published NTCP2 address
+ uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
+ if (!ntcp2Port) ntcp2Port = port;
+ if (ntcp2Published && ntcp2Port)
{
- addressCaps = i2p::data::RouterInfo::AddressCaps::eV4;
- routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
+ boost::asio::ip::address addr;
+ if (!host.empty ())
+ addr = boost::asio::ip::address::from_string (host);
+ if (!addr.is_v4())
+ addr = boost::asio::ip::address_v4 ();
+ routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
+ }
+ else
+ {
+ // add non-published NTCP2 address
+ uint8_t addressCaps = i2p::data::RouterInfo::AddressCaps::eV4;
+ if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
+ routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, addressCaps);
}
- }
- if (ssu)
- {
- routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
- caps |= i2p::data::RouterInfo::eReachable; // R
}
if (ssu2)
{
- if (ssu2Published)
- {
- uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
- if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port;
- routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v4::from_string (host), ssu2Port);
- }
+ uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
+ if (!ssu2Port) ssu2Port = port;
+ if (ssu2Published && ssu2Port)
+ {
+ boost::asio::ip::address addr;
+ if (!host.empty ())
+ addr = boost::asio::ip::address::from_string (host);
+ if (!addr.is_v4())
+ addr = boost::asio::ip::address_v4 ();
+ routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
+ }
else
{
- addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
- routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro);
+ uint8_t addressCaps = i2p::data::RouterInfo::AddressCaps::eV4;
+ if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
+ routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, addressCaps);
}
}
}
if (ipv6)
{
- std::string host = "::1";
- if (!i2p::config::IsDefault("host") && !ipv4) // override if v6 only
- i2p::config::GetOption("host", host);
- else
- {
- std::string address6; i2p::config::GetOption("address6", address6);
- if (!address6.empty ()) host = address6;
- }
+ std::string host; i2p::config::GetOption("address6", host);
+ if (host.empty () && !ipv4) i2p::config::GetOption("host", host); // use host for ipv6 only if ipv4 is not presented
if (ntcp2)
{
- if (ntcp2Published)
+ uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
+ if (!ntcp2Port) ntcp2Port = port;
+ if (ntcp2Published && ntcp2Port)
{
std::string ntcp2Host;
if (!i2p::config::IsDefault ("ntcp2.addressv6"))
i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host);
else
ntcp2Host = host;
- routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v6::from_string (ntcp2Host), port);
+ boost::asio::ip::address addr;
+ if (!ntcp2Host.empty ())
+ addr = boost::asio::ip::address::from_string (ntcp2Host);
+ if (!addr.is_v6())
+ addr = boost::asio::ip::address_v6 ();
+ routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
}
else
{
if (!ipv4) // no other ntcp2 addresses yet
- routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
- addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
+ routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::AddressCaps::eV6);
}
}
- if (ssu)
- {
- routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
- caps |= i2p::data::RouterInfo::eReachable; // R
- }
if (ssu2)
{
- if (ssu2Published)
- {
- uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
- if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port;
- routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v6::from_string (host), ssu2Port);
- }
+ uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
+ if (!ssu2Port) ssu2Port = port;
+ if (ssu2Published && ssu2Port)
+ {
+ boost::asio::ip::address addr;
+ if (!host.empty ())
+ addr = boost::asio::ip::address::from_string (host);
+ if (!addr.is_v6())
+ addr = boost::asio::ip::address_v6 ();
+ routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
+ }
else
{
if (!ipv4) // no other ssu2 addresses yet
- routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro);
- addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
+ routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::AddressCaps::eV6);
}
}
}
@@ -186,23 +224,27 @@
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, yggaddr, port);
}
- if (addressCaps)
- routerInfo.SetUnreachableAddressesTransportCaps (addressCaps);
routerInfo.UpdateCaps (caps); // caps + L
routerInfo.SetProperty ("netId", std::to_string (m_NetID));
routerInfo.SetProperty ("router.version", I2P_VERSION);
routerInfo.CreateBuffer (m_Keys);
m_RouterInfo.SetRouterIdentity (GetIdentity ());
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
+ m_RouterInfo.SetUnreachable (false);
}
uint16_t RouterContext::SelectRandomPort () const
{
- uint16_t port = rand () % (30777 - 9111) + 9111; // I2P network ports range
- if (port == 9150) port = 9151; // Tor browser
+ uint16_t port;
+ do
+ {
+ port = rand () % (30777 - 9111) + 9111; // I2P network ports range
+ }
+ while(i2p::util::net::IsPortInReservedRange(port));
+
return port;
- }
-
+ }
+
void RouterContext::UpdateRouterInfo ()
{
m_RouterInfo.CreateBuffer (m_Keys);
@@ -236,19 +278,32 @@
fk.write ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
}
- bool RouterContext::IsSSU2Only () const
+ void RouterContext::SetTesting (bool testing)
{
- auto transports = m_RouterInfo.GetCompatibleTransports (false);
- return (transports & (i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6)) &&
- !(transports & (i2p::data::RouterInfo::eSSUV4 | i2p::data::RouterInfo::eSSUV6));
+ if (testing != m_Testing)
+ {
+ m_Testing = testing;
+ if (m_Testing)
+ m_Error = eRouterErrorNone;
+ }
+ }
+
+ void RouterContext::SetTestingV6 (bool testing)
+ {
+ if (testing != m_TestingV6)
+ {
+ m_TestingV6 = testing;
+ if (m_TestingV6)
+ m_ErrorV6 = eRouterErrorNone;
+ }
}
void RouterContext::SetStatus (RouterStatus status)
{
+ SetTesting (false);
if (status != m_Status)
{
m_Status = status;
- m_Error = eRouterErrorNone;
switch (m_Status)
{
case eRouterStatusOK:
@@ -263,18 +318,12 @@
}
}
- void RouterContext::SetStatusSSU2 (RouterStatus status)
- {
- if (IsSSU2Only ())
- SetStatus (status);
- }
-
void RouterContext::SetStatusV6 (RouterStatus status)
{
+ SetTestingV6 (false);
if (status != m_StatusV6)
{
m_StatusV6 = status;
- m_ErrorV6 = eRouterErrorNone;
switch (m_StatusV6)
{
case eRouterStatusOK:
@@ -289,18 +338,14 @@
}
}
- void RouterContext::SetStatusV6SSU2 (RouterStatus status)
- {
- if (IsSSU2Only ())
- SetStatusV6 (status);
- }
-
void RouterContext::UpdatePort (int port)
{
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (!addresses) return;
bool updated = false;
- for (auto& address : m_RouterInfo.GetAddresses ())
+ for (auto& address : *addresses)
{
- if (address->port != port && (address->transportStyle == i2p::data::RouterInfo::eTransportSSU || IsSSU2Only ()))
+ if (address && address->port != port)
{
address->port = port;
updated = true;
@@ -310,85 +355,89 @@
UpdateRouterInfo ();
}
+ void RouterContext::PublishNTCP2Address (std::shared_ptr<i2p::data::RouterInfo::Address> address,
+ int port, bool publish) const
+ {
+ if (!address) return;
+ if (!port && !address->port) port = SelectRandomPort ();
+ if (port) address->port = port;
+ address->published = publish;
+ memcpy (address->i, m_NTCP2Keys->iv, 16);
+ }
+
void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg)
{
if (!m_NTCP2Keys) return;
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (!addresses) return;
bool updated = false;
- for (auto& address : m_RouterInfo.GetAddresses ())
+ if (v4)
{
- if (address->IsNTCP2 () && (address->port != port || address->published != publish))
+ auto addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V4Idx];
+ if (addr && (addr->port != port || addr->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) port = SelectRandomPort ();
- if (port) address->port = port;
- address->published = publish;
- memcpy (address->i, m_NTCP2Keys->iv, 16);
- updated = true;
- }
+ PublishNTCP2Address (addr, port, publish);
+ updated = true;
}
}
- if (updated)
- UpdateRouterInfo ();
- }
-
- void RouterContext::UpdateNTCP2Address (bool enable)
- {
- auto& addresses = m_RouterInfo.GetAddresses ();
- bool found = false, updated = false;
- for (auto it = addresses.begin (); it != addresses.end ();)
+ if (v6)
{
- if ((*it)->IsNTCP2 ())
+ auto addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6Idx];
+ if (addr && (addr->port != port || addr->published != publish))
{
- found = true;
- if (enable)
- {
- (*it)->s = m_NTCP2Keys->staticPublicKey;
- memcpy ((*it)->i, m_NTCP2Keys->iv, 16);
- it++;
- }
- else
- it = addresses.erase (it);
+ PublishNTCP2Address (addr, port, publish);
updated = true;
}
- else
- it++;
}
- if (enable && !found)
+ if (ygg)
{
- m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
- updated = true;
+ auto addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6MeshIdx];
+ if (addr && (addr->port != port || addr->published != publish))
+ {
+ PublishNTCP2Address (addr, port, publish);
+ updated = true;
+ }
}
+
if (updated)
UpdateRouterInfo ();
}
+ void RouterContext::UpdateNTCP2Keys ()
+ {
+ if (!m_NTCP2Keys) return;
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (!addresses) return;
+ for (auto& it: *addresses)
+ {
+ if (it && it->IsNTCP2 ())
+ {
+ it->s = m_NTCP2Keys->staticPublicKey;
+ memcpy (it->i, m_NTCP2Keys->iv, 16);
+ }
+ }
+ }
+
void RouterContext::PublishSSU2Address (int port, bool publish, bool v4, bool v6)
{
if (!m_SSU2Keys) return;
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (!addresses) return;
int newPort = 0;
if (!port)
{
- for (const auto& address : m_RouterInfo.GetAddresses ())
- if (address->port)
+ for (const auto& address : *addresses)
+ if (address && address->port)
{
newPort = address->port;
break;
- }
+ }
if (!newPort) newPort = SelectRandomPort ();
- }
+ }
bool updated = false;
- for (auto& address : m_RouterInfo.GetAddresses ())
+ for (auto& address : *addresses)
{
- if (address->IsSSU2 () && (!address->port || address->port != port || address->published != publish) &&
+ if (address && address->IsSSU2 () && (!address->port || address->port != port || address->published != publish) &&
((v4 && address->IsV4 ()) || (v6 && address->IsV6 ())))
{
if (port) address->port = port;
@@ -405,106 +454,80 @@
UpdateRouterInfo ();
}
- void RouterContext::UpdateSSU2Address (bool enable)
+ void RouterContext::UpdateSSU2Keys ()
{
- auto& addresses = m_RouterInfo.GetAddresses ();
- bool found = false, updated = false;
- for (auto it = addresses.begin (); it != addresses.end ();)
+ if (!m_SSU2Keys) return;
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (!addresses) return;
+ for (auto& it: *addresses)
{
- if ((*it)->IsSSU2 ())
+ if (it && it->IsSSU2 ())
{
- found = true;
- if (enable)
- {
- (*it)->s = m_SSU2Keys->staticPublicKey;
- (*it)->i = m_SSU2Keys->intro;
- it++;
- }
- else
- it = addresses.erase (it);
- updated = true;
+ it->s = m_SSU2Keys->staticPublicKey;
+ it->i = m_SSU2Keys->intro;
}
- else
- it++;
}
- if (enable && !found)
- {
- bool ipv4; i2p::config::GetOption("ipv4", ipv4);
- bool ipv6; i2p::config::GetOption("ipv6", ipv6);
- bool published; i2p::config::GetOption("ntcp2.published", published);
- if (published)
- {
- if (ipv4) m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::AddressCaps::eV4);
- if (ipv6) m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::AddressCaps::eV6);
- }
- else
- {
- uint8_t addressCaps = 0;
- if (ipv4) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
- if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
- m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addressCaps);
- }
- updated = true;
- }
- if (updated)
- UpdateRouterInfo ();
}
void RouterContext::UpdateAddress (const boost::asio::ip::address& host)
{
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (!addresses) return;
bool updated = false;
- for (auto& address : m_RouterInfo.GetAddresses ())
+ if (host.is_v4 ())
+ {
+ auto addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V4Idx];
+ if (addr && addr->host != host)
+ {
+ addr->host = host;
+ updated = true;
+ }
+ addr = (*addresses)[i2p::data::RouterInfo::eSSU2V4Idx];
+ if (addr && addr->host != host)
+ {
+ addr->host = host;
+ updated = true;
+ }
+ }
+ else if (host.is_v6 ())
{
- if (address->host != host && address->IsCompatible (host) &&
- !i2p::util::net::IsYggdrasilAddress (address->host))
+ auto addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6Idx];
+ if (addr && addr->host != host)
{
- // update host
- address->host = host;
+ addr->host = host;
updated = true;
}
- if (host.is_v6 () && address->IsV6 () && address->ssu &&
- (!address->ssu->mtu || updated))
+ addr = (*addresses)[i2p::data::RouterInfo::eSSU2V6Idx];
+ if (addr && (addr->host != host || !addr->ssu->mtu))
{
- // update MTU
- auto mtu = i2p::util::net::GetMTU (host);
- if (mtu)
+ addr->host = host;
+ if (m_StatusV6 != eRouterStatusProxy)
{
- LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu);
- int maxMTU = i2p::util::net::GetMaxMTU (host.to_v6 ());
- if (mtu > maxMTU)
- {
- mtu = maxMTU;
- LogPrint(eLogWarning, "Router: MTU dropped to upper limit of ", maxMTU, " bytes");
+ // update MTU
+ auto mtu = i2p::util::net::GetMTU (host);
+ if (mtu)
+ {
+ LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu);
+ int maxMTU = i2p::util::net::GetMaxMTU (host.to_v6 ());
+ if (mtu > maxMTU)
+ {
+ mtu = maxMTU;
+ LogPrint(eLogWarning, "Router: MTU dropped to upper limit of ", maxMTU, " bytes");
+ }
+ addr->ssu->mtu = mtu;
}
- if (mtu && !address->IsSSU2 ()) // SSU1
- mtu = (mtu >> 4) << 4; // round to multiple of 16
- address->ssu->mtu = mtu;
- updated = true;
}
+ updated = true;
}
}
+
auto ts = i2p::util::GetSecondsSinceEpoch ();
if (updated || ts > m_LastUpdateTime + ROUTER_INFO_UPDATE_INTERVAL)
UpdateRouterInfo ();
}
- bool RouterContext::AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer)
- {
- bool ret = m_RouterInfo.AddIntroducer (introducer);
- if (ret)
- UpdateRouterInfo ();
- return ret;
- }
-
- void RouterContext::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
- {
- if (m_RouterInfo.RemoveIntroducer (e))
- UpdateRouterInfo ();
- }
-
bool RouterContext::AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4)
{
- if (!IsSSU2Only ()) return false;
bool ret = m_RouterInfo.AddSSU2Introducer (introducer, v4);
if (ret)
UpdateRouterInfo ();
@@ -513,26 +536,20 @@
void RouterContext::RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4)
{
- if (!IsSSU2Only ()) return;
if (m_RouterInfo.RemoveSSU2Introducer (h, v4))
UpdateRouterInfo ();
}
void RouterContext::ClearSSU2Introducers (bool v4)
{
- bool updated = false;
- auto& addresses = m_RouterInfo.GetAddresses ();
- for (auto& addr : addresses)
- if (addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ())) &&
- addr->ssu && !addr->ssu->introducers.empty ())
- {
- addr->ssu->introducers.clear ();
- updated = true;
- }
- if (updated)
+ auto addr = m_RouterInfo.GetSSU2Address (v4);
+ if (addr && !addr->ssu->introducers.empty ())
+ {
+ addr->ssu->introducers.clear ();
UpdateRouterInfo ();
- }
-
+ }
+ }
+
void RouterContext::SetFloodfill (bool floodfill)
{
m_IsFloodfill = floodfill;
@@ -577,15 +594,15 @@
/* detect parameters */
switch (L)
{
- case i2p::data::CAPS_FLAG_LOW_BANDWIDTH1 : limit = 12; type = low; break;
- case i2p::data::CAPS_FLAG_LOW_BANDWIDTH2 : limit = 48; type = low; break;
- case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH1 : limit = 64; type = high; break;
- case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH2 : limit = 128; type = high; break;
- case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH3 : limit = 256; type = high; break;
- case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1 : limit = 2048; type = extra; break;
+ case i2p::data::CAPS_FLAG_LOW_BANDWIDTH1 : limit = 12; type = low; break;
+ case i2p::data::CAPS_FLAG_LOW_BANDWIDTH2 : limit = i2p::data::LOW_BANDWIDTH_LIMIT; type = low; break; // 48
+ case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH1 : limit = 64; type = high; break;
+ case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH2 : limit = 128; type = high; break;
+ case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH3 : limit = i2p::data::HIGH_BANDWIDTH_LIMIT; type = high; break; // 256
+ case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1 : limit = i2p::data::EXTRA_BANDWIDTH_LIMIT; type = extra; break; // 2048
case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2 : limit = 1000000; type = unlim; break; // 1Gbyte/s
default:
- limit = 48; type = low;
+ limit = i2p::data::LOW_BANDWIDTH_LIMIT; type = low; // 48
}
/* update caps & flags in RI */
auto caps = m_RouterInfo.GetCaps ();
@@ -631,50 +648,6 @@
return m_RouterInfo.GetCaps () & i2p::data::RouterInfo::eUnreachable;
}
- void RouterContext::RemoveNTCPAddress (bool v4only)
- {
- bool updated = false;
- auto& addresses = m_RouterInfo.GetAddresses ();
- for (auto it = addresses.begin (); it != addresses.end ();)
- {
- if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportNTCP && !(*it)->IsNTCP2 () &&
- (!v4only || (*it)->host.is_v4 ()))
- {
- it = addresses.erase (it);
- updated = true;
- if (v4only) break; // otherwise might be more than one address
- }
- else
- ++it;
- }
- if (updated)
- m_RouterInfo.UpdateSupportedTransports ();
- }
-
- void RouterContext::RemoveSSUAddress ()
- {
- bool updated = false;
- auto& addresses = m_RouterInfo.GetAddresses ();
- for (auto it = addresses.begin (); it != addresses.end ();)
- {
- if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportSSU)
- {
- it = addresses.erase (it);
- updated = true;
- }
- else
- ++it;
- }
- if (updated)
- m_RouterInfo.UpdateSupportedTransports ();
- }
-
- void RouterContext::SetUnreachableSSU2 (bool v4, bool v6)
- {
- if (IsSSU2Only ())
- SetUnreachable (v4, v6);
- }
-
void RouterContext::SetUnreachable (bool v4, bool v6)
{
if (v4 || (v6 && !SupportsV4 ()))
@@ -689,16 +662,18 @@
}
uint16_t port = 0;
// delete previous introducers
- auto& addresses = m_RouterInfo.GetAddresses ();
- for (auto& addr : addresses)
- if (addr->ssu && (!addr->IsSSU2 () || IsSSU2Only ()) &&
- ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
- {
- addr->published = false;
- addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer
- addr->ssu->introducers.clear ();
- port = addr->port;
- }
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (addresses)
+ {
+ for (auto& addr : *addresses)
+ if (addr && addr->ssu && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
+ {
+ addr->published = false;
+ addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer
+ addr->ssu->introducers.clear ();
+ port = addr->port;
+ }
+ }
// unpublish NTCP2 addreeses
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
if (ntcp2)
@@ -722,20 +697,19 @@
}
uint16_t port = 0;
// delete previous introducers
- bool isSSU2Published = IsSSU2Only (); // TODO
- if (isSSU2Published)
- i2p::config::GetOption ("ssu2.published", isSSU2Published);
- auto& addresses = m_RouterInfo.GetAddresses ();
- for (auto& addr : addresses)
- if (addr->ssu && (!addr->IsSSU2 () || isSSU2Published) &&
- ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
- {
- addr->published = true;
- addr->caps |= i2p::data::RouterInfo::eSSUIntroducer;
- addr->ssu->introducers.clear ();
- if (addr->port && (!addr->IsSSU2 () || IsSSU2Only ()))
- port = addr->port;
- }
+ bool isSSU2Published; i2p::config::GetOption ("ssu2.published", isSSU2Published);
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (addresses)
+ {
+ for (auto& addr : *addresses)
+ if (addr && addr->ssu && isSSU2Published && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
+ {
+ addr->published = true;
+ addr->caps |= i2p::data::RouterInfo::eSSUIntroducer;
+ addr->ssu->introducers.clear ();
+ if (addr->port) port = addr->port;
+ }
+ }
// publish NTCP2
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
if (ntcp2)
@@ -758,81 +732,98 @@
if (supportsV6)
{
// insert v6 addresses if necessary
- bool foundSSU = false, foundNTCP2 = false, foundSSU2 = false;
+ bool foundNTCP2 = false, foundSSU2 = false;
uint16_t port = 0;
- auto& addresses = m_RouterInfo.GetAddresses ();
- for (auto& addr: addresses)
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (addresses)
{
- if (addr->IsV6 () && !i2p::util::net::IsYggdrasilAddress (addr->host))
+ for (auto& addr: *addresses)
{
- switch (addr->transportStyle)
+ if (addr && addr->IsV6 () && !i2p::util::net::IsYggdrasilAddress (addr->host))
{
- case i2p::data::RouterInfo::eTransportSSU:
- foundSSU = true;
- break;
- case i2p::data::RouterInfo::eTransportNTCP:
- foundNTCP2 = true;
- break;
- case i2p::data::RouterInfo::eTransportSSU2:
- foundSSU2 = true;
- break;
- default: ;
+ switch (addr->transportStyle)
+ {
+ case i2p::data::RouterInfo::eTransportNTCP2:
+ foundNTCP2 = true;
+ break;
+ case i2p::data::RouterInfo::eTransportSSU2:
+ foundSSU2 = true;
+ break;
+ default: ;
+ }
}
+ if (addr) port = addr->port;
}
- port = addr->port;
}
- if (!port)
- {
+ if (!port)
+ {
i2p::config::GetOption("port", port);
if (!port) port = SelectRandomPort ();
- }
- // SSU
- bool ssu; i2p::config::GetOption("ssu", ssu);
- if (!foundSSU && ssu)
- {
- std::string host = "::1"; // TODO: read host
- m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr);
}
// NTCP2
- if (!foundNTCP2)
+ bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
+ if (ntcp2)
{
- bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
- bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
- if (ntcp2)
+ if (!foundNTCP2)
{
+ uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
+ if (!ntcp2Port) ntcp2Port = port;
+ bool added = false;
+ bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
if (ntcp2Published)
{
std::string ntcp2Host;
if (!i2p::config::IsDefault ("ntcp2.addressv6"))
i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host);
else
- ntcp2Host = "::1";
- 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 (ntcp2Host), ntcp2Port);
+ i2p::config::GetOption("host", ntcp2Host);
+ if (!ntcp2Host.empty () && ntcp2Port)
+ {
+ auto addr = boost::asio::ip::address::from_string (ntcp2Host);
+ if (addr.is_v6 ())
+ {
+ m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
+ added = true;
+ }
+ }
}
- else
- m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV6);
+ if (!added)
+ m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::eV6);
}
}
+ else
+ m_RouterInfo.RemoveNTCP2Address (false);
// SSU2
- if (!foundSSU2)
+ bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
+ if (ssu2)
{
- bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
- if (ssu2)
+ if (!foundSSU2)
{
+ uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
+ if (!ssu2Port) ssu2Port = port;
+ bool added = false;
bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
- if (ssu2Published)
+ if (ssu2Published && ssu2Port)
{
- uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
- if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port;
- m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("::1"), ssu2Port);
+ std::string host; i2p::config::GetOption("host", host);
+ if (!host.empty ())
+ {
+ auto addr = boost::asio::ip::address::from_string (host);
+ if (addr.is_v6 ())
+ {
+ m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
+ added = true;
+ }
+ }
}
- else
- m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV6);
+ if (!added)
+ m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::eV6);
}
}
- m_RouterInfo.EnableV6 ();
+ else
+ m_RouterInfo.RemoveSSU2Address (false);
+ if (ntcp2 || ssu2)
+ m_RouterInfo.EnableV6 ();
}
else
m_RouterInfo.DisableV6 ();
@@ -841,81 +832,97 @@
void RouterContext::SetSupportsV4 (bool supportsV4)
{
- // check if updates
- if (supportsV4 && SupportsV4 ()) return;
- if (!supportsV4 && !SupportsV4 ()) return;
- // update
if (supportsV4)
{
- bool foundSSU = false, foundNTCP2 = false, foundSSU2 = false;
- std::string host = "127.0.0.1";
+ bool foundNTCP2 = false, foundSSU2 = false;
uint16_t port = 0;
- auto& addresses = m_RouterInfo.GetAddresses ();
- for (auto& addr: addresses)
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (addresses)
{
- if (addr->IsV4 ())
+ for (auto& addr: *addresses)
{
- switch (addr->transportStyle)
+ if (addr && addr->IsV4 ())
{
- case i2p::data::RouterInfo::eTransportSSU:
- foundSSU = true;
- break;
- case i2p::data::RouterInfo::eTransportNTCP:
- foundNTCP2 = true;
- break;
- case i2p::data::RouterInfo::eTransportSSU2:
- foundSSU2 = true;
- break;
- default: ;
+ switch (addr->transportStyle)
+ {
+ case i2p::data::RouterInfo::eTransportNTCP2:
+ foundNTCP2 = true;
+ break;
+ case i2p::data::RouterInfo::eTransportSSU2:
+ foundSSU2 = true;
+ break;
+ default: ;
+ }
}
+ if (addr && addr->port) port = addr->port;
}
- if (addr->port) port = addr->port;
}
- if (!port)
- {
+ if (!port)
+ {
i2p::config::GetOption("port", port);
if (!port) port = SelectRandomPort ();
- }
- // SSU
- bool ssu; i2p::config::GetOption("ssu", ssu);
- if (!foundSSU && ssu)
- m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr);
-
+ }
// NTCP2
- if (!foundNTCP2)
+ bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
+ if (ntcp2)
{
- bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
- if (ntcp2)
+ if (!foundNTCP2)
{
+ uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
+ if (!ntcp2Port) ntcp2Port = port;
+ bool added = false;
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
- if (ntcp2Published)
+ if (ntcp2Published && ntcp2Port)
{
- 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);
+ std::string host; i2p::config::GetOption("host", host);
+ if (!host.empty ())
+ {
+ auto addr = boost::asio::ip::address::from_string (host);
+ if (addr.is_v4 ())
+ {
+ m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
+ added = true;
+ }
+ }
}
- else
- m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV4);
+ if (!added)
+ m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::eV4);
}
}
+ else
+ m_RouterInfo.RemoveNTCP2Address (true);
// SSU2
- if (!foundSSU2)
+ bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
+ if (ssu2)
{
- bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
- if (ssu2)
+ if (!foundSSU2)
{
+ uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
+ if (!ssu2Port) ssu2Port = port;
+ bool added = false;
bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
- if (ssu2Published)
+ std::string host; i2p::config::GetOption("host", host);
+ if (ssu2Published && ssu2Port)
{
- uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
- if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port;
- m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("127.0.0.1"), ssu2Port);
+ std::string host; i2p::config::GetOption("host", host);
+ if (!host.empty ())
+ {
+ auto addr = boost::asio::ip::address::from_string (host);
+ if (addr.is_v4 ())
+ {
+ m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
+ added = true;
+ }
+ }
}
- else
- m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV4);
+ if (!added)
+ m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::eV4);
}
}
- m_RouterInfo.EnableV4 ();
+ else
+ m_RouterInfo.RemoveSSU2Address (true);
+ if (ntcp2 || ssu2)
+ m_RouterInfo.EnableV4 ();
}
else
m_RouterInfo.DisableV4 ();
@@ -926,23 +933,26 @@
{
if (supportsmesh)
{
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (!addresses) return;
m_RouterInfo.EnableMesh ();
+ if ((*addresses)[i2p::data::RouterInfo::eNTCP2V6MeshIdx]) return; // we have mesh address already
uint16_t port = 0;
i2p::config::GetOption ("ntcp2.port", port);
if (!port) i2p::config::GetOption("port", port);
- bool foundMesh = false;
- auto& addresses = m_RouterInfo.GetAddresses ();
- for (auto& addr: addresses)
+ if (!port)
{
- if (!port) port = addr->port;
- if (i2p::util::net::IsYggdrasilAddress (addr->host))
+ for (auto& addr: *addresses)
{
- foundMesh = true;
- break;
+ if (addr && addr->port)
+ {
+ port = addr->port;
+ break;
+ }
}
}
- if (!foundMesh)
- m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, host, port);
+ if (!port) port = SelectRandomPort ();
+ m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, host, port);
}
else
m_RouterInfo.DisableMesh ();
@@ -952,64 +962,32 @@
void RouterContext::SetMTU (int mtu, bool v4)
{
if (mtu < 1280 || mtu > 1500) return;
- auto& addresses = m_RouterInfo.GetAddresses ();
- for (auto& addr: addresses)
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (!addresses) return;
+ for (auto& addr: *addresses)
{
- if (addr->ssu && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ())))
+ if (addr && addr->ssu && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ())))
{
- if (!addr->IsSSU2 ()) // SSU1
- {
- // round to multiple of 16
- if (v4)
- {
- if (mtu > 1484) mtu = 1484;
- else
- {
- mtu -= 12;
- mtu = (mtu >> 4) << 4;
- mtu += 12;
- }
- }
- else
- {
- if (mtu > 1488) mtu = 1488;
- else
- mtu = (mtu >> 4) << 4;
- }
- }
- if (mtu)
- {
- addr->ssu->mtu = mtu;
- LogPrint (eLogDebug, "Router: MTU for ", v4 ? "ipv4" : "ipv6", " address ", addr->host.to_string(), " is set to ", mtu);
- }
+ addr->ssu->mtu = mtu;
+ LogPrint (eLogDebug, "Router: MTU for ", v4 ? "ipv4" : "ipv6", " address ", addr->host.to_string(), " is set to ", mtu);
}
}
}
void RouterContext::UpdateNTCP2V6Address (const boost::asio::ip::address& host)
{
- bool isYgg = i2p::util::net::IsYggdrasilAddress (host);
- bool updated = false;
- auto& addresses = m_RouterInfo.GetAddresses ();
- for (auto& addr: addresses)
+ auto addresses = m_RouterInfo.GetAddresses ();
+ if (!addresses) return;
+ std::shared_ptr<i2p::data::RouterInfo::Address> addr;
+ if (i2p::util::net::IsYggdrasilAddress (host)) // yggdrasil
+ addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6MeshIdx];
+ else if (host.is_v6 ())
+ addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6Idx];
+ if (addr && addr->IsPublishedNTCP2 () && addr->host != host)
{
- if (addr->IsPublishedNTCP2 ())
- {
- bool isYgg1 = i2p::util::net::IsYggdrasilAddress (addr->host);
- if (addr->IsV6 () && ((isYgg && isYgg1) || (!isYgg && !isYgg1)))
- {
- if (addr->host != host)
- {
- addr->host = host;
- updated = true;
- }
- break;
- }
- }
- }
-
- if (updated)
+ addr->host = host;
UpdateRouterInfo ();
+ }
}
void RouterContext::UpdateStats ()
@@ -1077,6 +1055,20 @@
}
n2k.close ();
}
+ // read SSU2 keys if available
+ std::ifstream s2k (i2p::fs::DataDirPath (SSU2_KEYS), std::ifstream::in | std::ifstream::binary);
+ if (s2k)
+ {
+ s2k.seekg (0, std::ios::end);
+ size_t len = s2k.tellg();
+ s2k.seekg (0, std::ios::beg);
+ if (len == sizeof (SSU2PrivateKeys))
+ {
+ m_SSU2Keys.reset (new SSU2PrivateKeys ());
+ s2k.read ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
+ }
+ s2k.close ();
+ }
// read RouterInfo
m_RouterInfo.SetRouterIdentity (oldIdentity ? oldIdentity : GetIdentity ());
i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO));
@@ -1097,40 +1089,28 @@
if (IsUnreachable ())
SetReachable (true, true); // we assume reachable until we discover firewall through peer tests
- // read NTCP2
+ bool updated = false;
+ // create new NTCP2 keys if required
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
- if (ntcp2 || ygg)
+ if ((ntcp2 || ygg) && !m_NTCP2Keys)
{
- if (!m_NTCP2Keys) NewNTCP2Keys ();
- UpdateNTCP2Address (true); // enable NTCP2
+ NewNTCP2Keys ();
+ UpdateNTCP2Keys ();
+ updated = true;
}
- else
- UpdateNTCP2Address (false); // disable NTCP2
-
- // read SSU2
+ // create new SSU2 keys if required
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
- if (ssu2)
+ if (ssu2 && !m_SSU2Keys)
{
- // read SSU2 keys if available
- std::ifstream s2k (i2p::fs::DataDirPath (SSU2_KEYS), std::ifstream::in | std::ifstream::binary);
- if (s2k)
- {
- s2k.seekg (0, std::ios::end);
- size_t len = s2k.tellg();
- s2k.seekg (0, std::ios::beg);
- if (len == sizeof (SSU2PrivateKeys))
- {
- m_SSU2Keys.reset (new SSU2PrivateKeys ());
- s2k.read ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
- }
- s2k.close ();
- }
- if (!m_SSU2Keys) NewSSU2Keys ();
- UpdateSSU2Address (true); // enable SSU2
+ NewSSU2Keys ();
+ UpdateSSU2Keys ();
+ updated = true;
}
- else
- UpdateSSU2Address (false); // disable SSU2
+ if (m_RouterInfo.UpdateCongestion (i2p::data::RouterInfo::eLowCongestion))
+ updated = true;
+ if (updated)
+ UpdateRouterInfo ();
return true;
}
@@ -1151,6 +1131,13 @@
return i2p::tunnel::tunnels.GetExploratoryPool ();
}
+ bool RouterContext::IsHighCongestion () const
+ {
+ return i2p::tunnel::tunnels.IsTooManyTransitTunnels () ||
+ i2p::transport::transports.IsBandwidthExceeded () ||
+ i2p::transport::transports.IsTransitBandwidthExceeded ();
+ }
+
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len)
{
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len)));
@@ -1164,10 +1151,16 @@
return true;
}
-
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{
- std::unique_lock<std::mutex> l(m_GarlicMutex);
+ if (m_Service)
+ m_Service->GetService ().post (std::bind (&RouterContext::PostGarlicMessage, this, msg));
+ else
+ LogPrint (eLogError, "Router: service is NULL");
+ }
+
+ void RouterContext::PostGarlicMessage (std::shared_ptr<I2NPMessage> msg)
+ {
uint8_t * buf = msg->GetPayload ();
uint32_t len = bufbe32toh (buf);
if (len > msg->GetLength ())
@@ -1184,23 +1177,38 @@
else
LogPrint (eLogError, "Router: Session is not set for ECIES router");
}
- }
-
+ }
+
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{
- if (i2p::data::netdb.GetPublishReplyToken () == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
- i2p::data::netdb.PostI2NPMsg (msg);
+ if (m_Service)
+ m_Service->GetService ().post (std::bind (&RouterContext::PostDeliveryStatusMessage, this, msg));
else
+ LogPrint (eLogError, "Router: service is NULL");
+ }
+
+ void RouterContext::PostDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
+ {
+ if (m_PublishReplyToken == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
{
- std::unique_lock<std::mutex> l(m_GarlicMutex);
+ LogPrint (eLogInfo, "Router: Publishing confirmed. reply token=", m_PublishReplyToken);
+ m_PublishExcluded.clear ();
+ m_PublishReplyToken = 0;
+ SchedulePublish ();
+ }
+ else
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
- }
}
-
+
void RouterContext::CleanupDestination ()
{
- std::unique_lock<std::mutex> l(m_GarlicMutex);
- i2p::garlic::GarlicDestination::CleanupExpiredTags ();
+ if (m_Service)
+ m_Service->GetService ().post ([this]()
+ {
+ this->i2p::garlic::GarlicDestination::CleanupExpiredTags ();
+ });
+ else
+ LogPrint (eLogError, "Router: service is NULL");
}
uint32_t RouterContext::GetUptime () const
@@ -1275,4 +1283,152 @@
}
return *m_SSU2StaticKeys;
}
+
+ void RouterContext::ScheduleInitialPublish ()
+ {
+ if (m_PublishTimer)
+ {
+ m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_INITIAL_PUBLISH_INTERVAL));
+ m_PublishTimer->async_wait (std::bind (&RouterContext::HandleInitialPublishTimer,
+ this, std::placeholders::_1));
+ }
+ else
+ LogPrint (eLogError, "Router: Publish timer is NULL");
+ }
+
+ void RouterContext::HandleInitialPublishTimer (const boost::system::error_code& ecode)
+ {
+ if (ecode != boost::asio::error::operation_aborted)
+ {
+ if (m_RouterInfo.IsReachableBy (i2p::data::RouterInfo::eAllTransports))
+ HandlePublishTimer (ecode);
+ else
+ ScheduleInitialPublish ();
+ }
+ }
+
+ void RouterContext::SchedulePublish ()
+ {
+ if (m_PublishTimer)
+ {
+ m_PublishTimer->cancel ();
+ m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_PUBLISH_INTERVAL +
+ rand () % ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE));
+ m_PublishTimer->async_wait (std::bind (&RouterContext::HandlePublishTimer,
+ this, std::placeholders::_1));
+ }
+ else
+ LogPrint (eLogError, "Router: Publish timer is NULL");
+ }
+
+ void RouterContext::HandlePublishTimer (const boost::system::error_code& ecode)
+ {
+ if (ecode != boost::asio::error::operation_aborted)
+ {
+ m_PublishExcluded.clear ();
+ m_PublishReplyToken = 0;
+ if (IsFloodfill ())
+ {
+ UpdateStats (); // for floodfill
+ m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // don't publish to ourselves
+ }
+ UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
+ Publish ();
+ SchedulePublishResend ();
+ }
+ }
+
+ void RouterContext::Publish ()
+ {
+ if (!i2p::transport::transports.IsOnline ()) return;
+ if (m_PublishExcluded.size () > ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS)
+ {
+ LogPrint (eLogError, "Router: Couldn't publish our RouterInfo to ", ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again");
+ m_PublishExcluded.clear ();
+ UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
+ }
+
+ auto floodfill = i2p::data::netdb.GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
+ if (floodfill)
+ {
+ uint32_t replyToken;
+ RAND_bytes ((uint8_t *)&replyToken, 4);
+ LogPrint (eLogInfo, "Router: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
+ if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
+ i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
+ // send directly
+ i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
+ else
+ {
+ // otherwise through exploratory
+ auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
+ auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
+ auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
+ if (inbound && outbound)
+ {
+ // encrypt for floodfill
+ auto msg = CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound);
+ outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0,
+ i2p::garlic::WrapECIESX25519MessageForRouter (msg, floodfill->GetIdentity ()->GetEncryptionPublicKey ()));
+ }
+ else
+ LogPrint (eLogInfo, "Router: Can't publish our RouterInfo. No tunnles. Try again in ", ROUTER_INFO_CONFIRMATION_TIMEOUT, " seconds");
+ }
+ m_PublishExcluded.insert (floodfill->GetIdentHash ());
+ m_PublishReplyToken = replyToken;
+ }
+ else
+ LogPrint (eLogInfo, "Router: Can't find floodfill to publish our RouterInfo");
+ }
+
+ void RouterContext::SchedulePublishResend ()
+ {
+ if (m_PublishTimer)
+ {
+ m_PublishTimer->cancel ();
+ m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CONFIRMATION_TIMEOUT));
+ m_PublishTimer->async_wait (std::bind (&RouterContext::HandlePublishResendTimer,
+ this, std::placeholders::_1));
+ }
+ else
+ LogPrint (eLogError, "Router: Publish timer is NULL");
+ }
+
+ void RouterContext::HandlePublishResendTimer (const boost::system::error_code& ecode)
+ {
+ if (ecode != boost::asio::error::operation_aborted)
+ {
+ i2p::context.UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
+ Publish ();
+ SchedulePublishResend ();
+ }
+ }
+
+ void RouterContext::ScheduleCongestionUpdate ()
+ {
+ if (m_CongestionUpdateTimer)
+ {
+ m_CongestionUpdateTimer->cancel ();
+ m_CongestionUpdateTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CONGESTION_UPDATE_INTERVAL));
+ m_CongestionUpdateTimer->async_wait (std::bind (&RouterContext::HandleCongestionUpdateTimer,
+ this, std::placeholders::_1));
+ }
+ else
+ LogPrint (eLogError, "Router: Congestion update timer is NULL");
+ }
+
+ void RouterContext::HandleCongestionUpdateTimer (const boost::system::error_code& ecode)
+ {
+ if (ecode != boost::asio::error::operation_aborted)
+ {
+ auto c = i2p::data::RouterInfo::eLowCongestion;
+ if (!AcceptsTunnels ())
+ c = i2p::data::RouterInfo::eRejectAll;
+ else if (IsHighCongestion ())
+ c = i2p::data::RouterInfo::eHighCongestion;
+ if (m_RouterInfo.UpdateCongestion (c))
+ UpdateRouterInfo ();
+ ScheduleCongestionUpdate ();
+ }
+ }
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/RouterContext.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -12,12 +12,13 @@
#include <inttypes.h>
#include <string>
#include <memory>
-#include <mutex>
#include <chrono>
+#include <set>
#include <boost/asio.hpp>
#include "Identity.h"
#include "RouterInfo.h"
#include "Garlic.h"
+#include "util.h"
namespace i2p
{
@@ -30,17 +31,21 @@
const char ROUTER_KEYS[] = "router.keys";
const char NTCP2_KEYS[] = "ntcp2.keys";
const char SSU2_KEYS[] = "ssu2.keys";
- const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
+ const int ROUTER_INFO_UPDATE_INTERVAL = 30*60; // 30 minutes
+ const int ROUTER_INFO_PUBLISH_INTERVAL = 39*60; // in seconds
+ const int ROUTER_INFO_INITIAL_PUBLISH_INTERVAL = 10; // in seconds
+ const int ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE = 105;// in seconds
+ const int ROUTER_INFO_CONFIRMATION_TIMEOUT = 5; // in seconds
+ const int ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
+ const int ROUTER_INFO_CONGESTION_UPDATE_INTERVAL = 12*60; // in seconds
enum RouterStatus
{
eRouterStatusOK = 0,
- eRouterStatusTesting = 1,
- eRouterStatusFirewalled = 2,
- eRouterStatusError = 3,
- eRouterStatusUnknown = 4,
- eRouterStatusProxy = 5,
- eRouterStatusMesh = 6
+ eRouterStatusFirewalled = 1,
+ eRouterStatusUnknown = 2,
+ eRouterStatusProxy = 3,
+ eRouterStatusMesh = 4
};
enum RouterError
@@ -48,7 +53,9 @@
eRouterErrorNone = 0,
eRouterErrorClockSkew = 1,
eRouterErrorOffline = 2,
- eRouterErrorSymmetricNAT = 3
+ eRouterErrorSymmetricNAT = 3,
+ eRouterErrorFullConeNAT = 4,
+ eRouterErrorNoDescriptors = 5
};
class RouterContext: public i2p::garlic::GarlicDestination
@@ -69,11 +76,23 @@
uint8_t intro[32];
};
+ class RouterService: public i2p::util::RunnableServiceWithWork
+ {
+ public:
+
+ RouterService (): RunnableServiceWithWork ("Router") {};
+ boost::asio::io_service& GetService () { return GetIOService (); };
+ void Start () { StartIOService (); };
+ void Stop () { StopIOService (); };
+ };
+
public:
RouterContext ();
void Init ();
-
+ void Start ();
+ void Stop ();
+
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
i2p::data::LocalRouterInfo& GetRouterInfo () { return m_RouterInfo; };
std::shared_ptr<i2p::data::RouterInfo> GetSharedRouterInfo ()
@@ -101,37 +120,32 @@
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
uint64_t GetBandwidthLimit () const { return m_BandwidthLimit; };
uint64_t GetTransitBandwidthLimit () const { return (m_BandwidthLimit*m_ShareRatio)/100LL; };
+ bool GetTesting () const { return m_Testing; };
+ void SetTesting (bool testing);
RouterStatus GetStatus () const { return m_Status; };
void SetStatus (RouterStatus status);
- void SetStatusSSU2 (RouterStatus status);
RouterError GetError () const { return m_Error; };
- void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
+ void SetError (RouterError error) { m_Error = error; };
+ bool GetTestingV6 () const { return m_TestingV6; };
+ void SetTestingV6 (bool testing);
RouterStatus GetStatusV6 () const { return m_StatusV6; };
void SetStatusV6 (RouterStatus status);
- void SetStatusV6SSU2 (RouterStatus status);
RouterError GetErrorV6 () const { return m_ErrorV6; };
- void SetErrorV6 (RouterError error) { m_StatusV6 = eRouterStatusError; m_ErrorV6 = error; };
+ void SetErrorV6 (RouterError error) { m_ErrorV6 = error; };
int GetNetID () const { return m_NetID; };
void SetNetID (int netID) { m_NetID = netID; };
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data);
bool DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data);
void UpdatePort (int port); // called from Daemon
- void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
+ void UpdateAddress (const boost::asio::ip::address& host); // called from SSU2 or Daemon
void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg);
- void UpdateNTCP2Address (bool enable);
void PublishSSU2Address (int port, bool publish, bool v4, bool v6);
- void UpdateSSU2Address (bool enable);
- void RemoveNTCPAddress (bool v4only = true); // delete NTCP address for older routers. TODO: remove later
- void RemoveSSUAddress (); // delete SSU address for older routers
- bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
- void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
bool AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4);
void RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4);
void ClearSSU2Introducers (bool v4);
bool IsUnreachable () const;
void SetUnreachable (bool v4, bool v6);
- void SetUnreachableSSU2 (bool v4, bool v6);
void SetReachable (bool v4, bool v6);
bool IsFloodfill () const { return m_IsFloodfill; };
void SetFloodfill (bool floodfill);
@@ -142,6 +156,7 @@
void SetShareRatio (int percents); // 0 - 100
bool AcceptsTunnels () const { return m_AcceptsTunnels; };
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
+ bool IsHighCongestion () const;
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
bool SupportsV4 () const { return m_RouterInfo.IsV4 (); };
bool SupportsMesh () const { return m_RouterInfo.IsMesh (); };
@@ -149,6 +164,8 @@
void SetSupportsV4 (bool supportsV4);
void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host);
void SetMTU (int mtu, bool v4);
+ void SetHidden(bool hide) { m_IsHiddenMode = hide; };
+ bool IsHidden() const { return m_IsHiddenMode; };
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
@@ -183,13 +200,27 @@
void UpdateRouterInfo ();
void NewNTCP2Keys ();
void NewSSU2Keys ();
- bool IsSSU2Only () const; // SSU2 and no SSU
+ void UpdateNTCP2Keys ();
+ void UpdateSSU2Keys ();
bool Load ();
void SaveKeys ();
uint16_t SelectRandomPort () const;
+ void PublishNTCP2Address (std::shared_ptr<i2p::data::RouterInfo::Address> address, int port, bool publish) const;
bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize);
+ void PostGarlicMessage (std::shared_ptr<I2NPMessage> msg);
+ void PostDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
+ void ScheduleInitialPublish ();
+ void HandleInitialPublishTimer (const boost::system::error_code& ecode);
+ void SchedulePublish ();
+ void HandlePublishTimer (const boost::system::error_code& ecode);
+ void Publish ();
+ void SchedulePublishResend ();
+ void HandlePublishResendTimer (const boost::system::error_code& ecode);
+ void ScheduleCongestionUpdate ();
+ void HandleCongestionUpdateTimer (const boost::system::error_code& ecode);
+
private:
i2p::data::LocalRouterInfo m_RouterInfo;
@@ -203,13 +234,19 @@
int m_ShareRatio;
RouterStatus m_Status, m_StatusV6;
RouterError m_Error, m_ErrorV6;
+ bool m_Testing, m_TestingV6;
int m_NetID;
- std::mutex m_GarlicMutex;
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
std::unique_ptr<SSU2PrivateKeys> m_SSU2Keys;
std::unique_ptr<i2p::crypto::X25519Keys> m_NTCP2StaticKeys, m_SSU2StaticKeys;
// for ECIESx25519
i2p::crypto::NoiseSymmetricState m_InitialNoiseState, m_CurrentNoiseState;
+ // publish
+ std::unique_ptr<RouterService> m_Service;
+ std::unique_ptr<boost::asio::deadline_timer> m_PublishTimer, m_CongestionUpdateTimer;
+ std::set<i2p::data::IdentHash> m_PublishExcluded;
+ uint32_t m_PublishReplyToken;
+ bool m_IsHiddenMode; // not publish
};
extern RouterContext context;
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/RouterInfo.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -43,7 +43,7 @@
RouterInfo::RouterInfo (const std::string& fullPath):
m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false),
m_SupportedTransports (0),m_ReachableTransports (0),
- m_Caps (0), m_Version (0)
+ m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
{
m_Addresses = boost::make_shared<Addresses>(); // create empty list
m_Buffer = NewBuffer (); // always RouterInfo's
@@ -53,7 +53,7 @@
RouterInfo::RouterInfo (std::shared_ptr<Buffer>&& buf, size_t len):
m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false),
m_SupportedTransports (0), m_ReachableTransports (0),
- m_Caps (0), m_Version (0)
+ m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
{
if (len <= MAX_RI_BUFFER_SIZE)
{
@@ -79,13 +79,12 @@
{
}
- void RouterInfo::Update (const uint8_t * buf, size_t len)
+ bool RouterInfo::Update (const uint8_t * buf, size_t len)
{
if (len > MAX_RI_BUFFER_SIZE)
{
- LogPrint (eLogError, "RouterInfo: Buffer is too long ", len);
- m_IsUnreachable = true;
- return;
+ LogPrint (eLogWarning, "RouterInfo: Updated buffer is too long ", len, ". Not changed");
+ return false;
}
// verify signature since we have identity already
int l = len - m_RouterIdentity->GetSignatureLen ();
@@ -99,20 +98,21 @@
m_Caps = 0;
// don't clean up m_Addresses, it will be replaced in ReadFromStream
ClearProperties ();
- // copy buffer
- UpdateBuffer (buf, len);
// skip identity
size_t identityLen = m_RouterIdentity->GetFullLen ();
// read new RI
- std::stringstream str (std::string ((char *)m_Buffer->data () + identityLen, m_BufferLen - identityLen));
+ std::stringstream str (std::string ((char *)buf + identityLen, len - identityLen));
ReadFromStream (str);
+ if (!m_IsUnreachable)
+ UpdateBuffer (buf, len); // save buffer
// don't delete buffer until saved to the file
}
else
- {
- LogPrint (eLogError, "RouterInfo: Signature verification failed");
- m_IsUnreachable = true;
- }
+ {
+ LogPrint (eLogWarning, "RouterInfo: Updated signature verification failed. Not changed");
+ return false;
+ }
+ return true;
}
void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
@@ -161,7 +161,7 @@
m_IsUnreachable = true;
return;
}
- m_RouterIdentity = std::make_shared<IdentityEx>(m_Buffer->data (), m_BufferLen);
+ m_RouterIdentity = NewIdentity (m_Buffer->data (), m_BufferLen);
size_t identityLen = m_RouterIdentity->GetFullLen ();
if (identityLen >= m_BufferLen)
{
@@ -186,7 +186,6 @@
m_IsUnreachable = true;
return;
}
- m_RouterIdentity->DropVerifier ();
}
// parse RI
std::stringstream str;
@@ -202,30 +201,28 @@
void RouterInfo::ReadFromStream (std::istream& s)
{
if (!s) return;
- m_Caps = 0;
+ m_Caps = 0; m_Congestion = eLowCongestion;
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
m_Timestamp = be64toh (m_Timestamp);
// read addresses
- auto addresses = boost::make_shared<Addresses>();
+ auto addresses = NewAddresses ();
uint8_t numAddresses;
s.read ((char *)&numAddresses, sizeof (numAddresses));
- addresses->reserve (numAddresses);
for (int i = 0; i < numAddresses; i++)
{
uint8_t supportedTransports = 0;
- auto address = std::make_shared<Address> ();
+ auto address = NewAddress ();
uint8_t cost; // ignore
s.read ((char *)&cost, sizeof (cost));
s.read ((char *)&address->date, sizeof (address->date));
- bool isHost = false, isIntroKey = false, isStaticKey = false, isV2 = false;
- Tag<32> iV2; // for 'i' field in SSU, TODO: remove later
+ bool isHost = false, isStaticKey = false, isV2 = false;
char transportStyle[6];
ReadString (transportStyle, 6, s);
if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2
- address->transportStyle = eTransportNTCP;
+ address->transportStyle = eTransportNTCP2;
else if (!strncmp (transportStyle, "SSU", 3)) // SSU or SSU2
{
- address->transportStyle = (transportStyle[3] == '2') ? eTransportSSU2 : eTransportSSU;
+ address->transportStyle = eTransportSSU2;
address->ssu.reset (new SSUExt ());
address->ssu->mtu = 0;
}
@@ -254,30 +251,50 @@
{
boost::system::error_code ecode;
address->host = boost::asio::ip::address::from_string (value, ecode);
- if (!ecode && !address->host.is_unspecified ()) isHost = true;
+ if (!ecode && !address->host.is_unspecified ())
+ {
+ if (!i2p::util::net::IsInReservedRange (address->host) ||
+ i2p::util::net::IsYggdrasilAddress (address->host))
+ isHost = true;
+ else
+ // we consider such address as invalid
+ address->transportStyle = eTransportUnknown;
+ }
}
else if (!strcmp (key, "port"))
- address->port = boost::lexical_cast<int>(value);
- else if (!strcmp (key, "mtu"))
{
- if (address->ssu)
- address->ssu->mtu = boost::lexical_cast<int>(value);
- else
- LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP");
+ try
+ {
+ address->port = boost::lexical_cast<int>(value);
+ }
+ catch (std::exception& ex)
+ {
+ LogPrint (eLogWarning, "RouterInfo: 'port' exception ", ex.what ());
+ }
}
- else if (!strcmp (key, "key"))
+ else if (!strcmp (key, "mtu"))
{
if (address->ssu)
- isIntroKey = (Base64ToByteStream (value, strlen (value), address->i, 32) == 32);
+ {
+ try
+ {
+ address->ssu->mtu = boost::lexical_cast<int>(value);
+ }
+ catch (std::exception& ex)
+ {
+ LogPrint (eLogWarning, "RouterInfo: 'mtu' exception ", ex.what ());
+ }
+ }
else
- LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP");
+ LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP2");
}
else if (!strcmp (key, "caps"))
address->caps = ExtractAddressCaps (value);
else if (!strcmp (key, "s")) // ntcp2 or ssu2 static key
{
Base64ToByteStream (value, strlen (value), address->s, 32);
- isStaticKey = true;
+ if (!(address->s[31] & 0x80)) // check if x25519 public key
+ isStaticKey = true;
}
else if (!strcmp (key, "i")) // ntcp2 iv or ssu2 intro
{
@@ -288,8 +305,6 @@
}
else if (address->IsSSU2 ())
Base64ToByteStream (value, strlen (value), address->i, 32);
- else
- Base64ToByteStream (value, strlen (value), iV2, 32);
}
else if (!strcmp (key, "v"))
{
@@ -321,27 +336,39 @@
address->ssu->introducers.resize (index + 1);
}
Introducer& introducer = address->ssu->introducers.at (index);
- if (!strcmp (key, "ihost"))
+ if (!strcmp (key, "itag"))
{
- boost::system::error_code ecode;
- introducer.iHost = boost::asio::ip::address::from_string (value, ecode);
+ try
+ {
+ introducer.iTag = boost::lexical_cast<uint32_t>(value);
+ }
+ catch (std::exception& ex)
+ {
+ LogPrint (eLogWarning, "RouterInfo: 'itag' exception ", ex.what ());
+ }
}
- else if (!strcmp (key, "iport"))
- introducer.iPort = boost::lexical_cast<int>(value);
- else if (!strcmp (key, "itag"))
- introducer.iTag = boost::lexical_cast<uint32_t>(value);
- else if (!strcmp (key, "ikey") || !strcmp (key, "ih"))
- Base64ToByteStream (value, strlen (value), introducer.iKey, 32);
+ else if (!strcmp (key, "ih"))
+ Base64ToByteStream (value, strlen (value), introducer.iH, 32);
else if (!strcmp (key, "iexp"))
- introducer.iExp = boost::lexical_cast<uint32_t>(value);
+ {
+ try
+ {
+ introducer.iExp = boost::lexical_cast<uint32_t>(value);
+ }
+ catch (std::exception& ex)
+ {
+ LogPrint (eLogWarning, "RouterInfo: 'iexp' exception ", ex.what ());
+ }
+ }
}
if (!s) return;
}
- if (address->transportStyle == eTransportNTCP)
+
+ if (address->transportStyle == eTransportNTCP2)
{
if (isStaticKey)
{
- if (isHost)
+ if (isHost && address->port)
{
if (address->host.is_v6 ())
supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6);
@@ -349,8 +376,9 @@
supportedTransports |= eNTCP2V4;
m_ReachableTransports |= supportedTransports;
}
- else if (!address->published)
+ else
{
+ address->published = false;
if (address->caps)
{
if (address->caps & AddressCaps::eV4) supportedTransports |= eNTCP2V4;
@@ -361,107 +389,37 @@
}
}
}
- else if (address->transportStyle == eTransportSSU)
- {
- if (isIntroKey)
- {
- if (isHost)
- supportedTransports |= address->host.is_v4 () ? eSSUV4 : eSSUV6;
- else if (address->caps & AddressCaps::eV6)
- {
- supportedTransports |= eSSUV6;
- if (address->caps & AddressCaps::eV4) supportedTransports |= eSSUV4; // in additional to v6
- }
- else
- supportedTransports |= eSSUV4; // in case if host or 6 caps is not preasented, we assume 4
- if (address->ssu && !address->ssu->introducers.empty ())
- {
- // exclude invalid introducers
- uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
- int numValid = 0;
- for (auto& it: address->ssu->introducers)
- {
- if (!it.iExp) it.iExp = m_Timestamp/1000 + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT;
- if (ts <= it.iExp && it.iPort > 0 &&
- ((it.iHost.is_v4 () && address->IsV4 ()) || (it.iHost.is_v6 () && address->IsV6 ())))
- numValid++;
- else
- {
- it.iPort = 0;
- if (isV2) numValid++;
- }
- }
- if (numValid)
- m_ReachableTransports |= supportedTransports;
- else
- address->ssu->introducers.resize (0);
- }
- else if (isHost && address->port)
- {
- address->published = true;
- m_ReachableTransports |= supportedTransports;
- }
- }
- }
- if (address->transportStyle == eTransportSSU2 || (isV2 && address->transportStyle == eTransportSSU))
+ else if (address->transportStyle == eTransportSSU2 && isV2 && isStaticKey)
{
if (address->IsV4 ()) supportedTransports |= eSSU2V4;
if (address->IsV6 ()) supportedTransports |= eSSU2V6;
- if (address->port)
+ if (isHost && address->port)
{
if (address->host.is_v4 ()) m_ReachableTransports |= eSSU2V4;
if (address->host.is_v6 ()) m_ReachableTransports |= eSSU2V6;
+ address->published = true;
}
- if (address->transportStyle == eTransportSSU2)
- {
- if (address->port) address->published = true;
- if (address->ssu && !address->ssu->introducers.empty ())
- {
- // exclude invalid introducers
- uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
- int numValid = 0;
- for (auto& it: address->ssu->introducers)
- {
- if (it.iTag && ts <= it.iExp)
- numValid++;
- else
- it.iTag = 0;
- }
- if (numValid)
- m_ReachableTransports |= supportedTransports;
- else
- address->ssu->introducers.resize (0);
- }
- }
- else
+ if (address->ssu && !address->ssu->introducers.empty ())
{
- // create additional SSU2 address. TODO: remove later
- auto ssu2addr = std::make_shared<Address> ();
- ssu2addr->transportStyle = eTransportSSU2;
- ssu2addr->host = address->host; ssu2addr->port = address->port;
- ssu2addr->s = address->s; ssu2addr->i = iV2;
- ssu2addr->date = address->date; ssu2addr->caps = address->caps;
- ssu2addr->published = address->published;
- ssu2addr->ssu.reset (new SSUExt ()); ssu2addr->ssu->mtu = address->ssu->mtu;
+ // exclude invalid introducers
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
- if (!address->ssu->introducers.empty ())
- {
- for (const auto& introducer: address->ssu->introducers)
- if (!introducer.iPort && introducer.iHost.is_unspecified () && ts < introducer.iExp) // SSU2
- ssu2addr->ssu->introducers.push_back (introducer);
- if (!ssu2addr->ssu->introducers.empty ())
- m_ReachableTransports |= supportedTransports;
- }
- addresses->push_back(ssu2addr);
- }
+ UpdateIntroducers (address, ts);
+ if (!address->ssu->introducers.empty ()) // still has something
+ m_ReachableTransports |= supportedTransports;
+ }
}
if (supportedTransports)
{
if (!(m_SupportedTransports & supportedTransports)) // avoid duplicates
- addresses->push_back(address);
+ {
+ for (uint8_t i = 0; i < eNumTransports; i++)
+ if ((1 << i) & supportedTransports)
+ (*addresses)[i] = address;
+ }
m_SupportedTransports |= supportedTransports;
}
}
+ // update addresses
#if (BOOST_VERSION >= 105300)
boost::atomic_store (&m_Addresses, addresses);
#else
@@ -527,7 +485,10 @@
if (netdb.GetFamilies ().VerifyFamily (family, GetIdentHash (), value))
m_FamilyID = netdb.GetFamilies ().GetFamilyID (family);
else
+ {
LogPrint (eLogWarning, "RouterInfo: Family ", family, " signature verification failed");
+ SetUnreachable (true);
+ }
}
if (!s) return;
@@ -570,6 +531,15 @@
case CAPS_FLAG_UNREACHABLE:
m_Caps |= Caps::eUnreachable;
break;
+ case CAPS_FLAG_MEDIUM_CONGESTION:
+ m_Congestion = eMediumCongestion;
+ break;
+ case CAPS_FLAG_HIGH_CONGESTION:
+ m_Congestion = eHighCongestion;
+ break;
+ case CAPS_FLAG_REJECT_ALL_CONGESTION:
+ m_Congestion = eRejectAll;
+ break;
default: ;
}
cap++;
@@ -590,10 +560,10 @@
case CAPS_FLAG_V6:
caps |= AddressCaps::eV6;
break;
- case CAPS_FLAG_SSU_TESTING:
+ case CAPS_FLAG_SSU2_TESTING:
caps |= AddressCaps::eSSUTesting;
break;
- case CAPS_FLAG_SSU_INTRODUCER:
+ case CAPS_FLAG_SSU2_INTRODUCER:
caps |= AddressCaps::eSSUIntroducer;
break;
default: ;
@@ -603,6 +573,21 @@
return caps;
}
+ void RouterInfo::UpdateIntroducers (std::shared_ptr<Address> address, uint64_t ts)
+ {
+ if (!address || !address->ssu) return;
+ int numValid = 0;
+ for (auto& it: address->ssu->introducers)
+ {
+ if (it.iTag && ts < it.iExp && !it.iH.IsZero ())
+ numValid++;
+ else
+ it.iTag = 0;
+ }
+ if (!numValid)
+ address->ssu->introducers.resize (0);
+ }
+
bool RouterInfo::IsNewer (const uint8_t * buf, size_t len) const
{
if (!m_RouterIdentity) return false;
@@ -617,20 +602,24 @@
{
if (LoadFile (fullPath))
LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
+ else
+ return nullptr;
}
return m_Buffer->data ();
}
bool RouterInfo::SaveToFile (const std::string& fullPath)
{
+ if (m_IsUnreachable) return false; // don't save bad router
if (!m_Buffer)
{
- LogPrint (eLogError, "RouterInfo: Can't save, m_Buffer == NULL");
+ LogPrint (eLogWarning, "RouterInfo: Can't save, m_Buffer == NULL");
return false;
}
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
- if (!f.is_open ()) {
- LogPrint(eLogError, "RouterInfo: Can't save to ", fullPath);
+ if (!f.is_open ())
+ {
+ LogPrint (eLogError, "RouterInfo: Can't save to ", fullPath);
return false;
}
f.write ((char *)m_Buffer->data (), m_BufferLen);
@@ -656,68 +645,106 @@
return l+1;
}
-
- void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu)
+ void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,int port, uint8_t caps)
{
auto addr = std::make_shared<Address>();
- addr->host = boost::asio::ip::address::from_string (host);
addr->port = port;
- addr->transportStyle = eTransportSSU;
- addr->published = true;
- addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
+ addr->transportStyle = eTransportNTCP2;
+ addr->caps = caps;
addr->date = 0;
- addr->ssu.reset (new SSUExt ());
- addr->ssu->mtu = mtu;
- if (key)
- memcpy (addr->i, key, 32);
- else
- RAND_bytes (addr->i, 32);
- for (const auto& it: *m_Addresses) // don't insert same address twice
- if (*it == *addr) return;
- m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
- m_ReachableTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
- m_Addresses->push_back(std::move(addr));
+ addr->published = false;
+ memcpy (addr->s, staticKey, 32);
+ memcpy (addr->i, iv, 16);
+ if (addr->IsV4 ())
+ {
+ m_SupportedTransports |= eNTCP2V4;
+ (*m_Addresses)[eNTCP2V4Idx] = addr;
+ }
+ if (addr->IsV6 ())
+ {
+ m_SupportedTransports |= eNTCP2V6;
+ (*m_Addresses)[eNTCP2V6Idx] = addr;
+ }
}
void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
- const boost::asio::ip::address& host, int port, uint8_t caps)
+ const boost::asio::ip::address& host, int port)
{
auto addr = std::make_shared<Address>();
addr->host = host;
addr->port = port;
- addr->transportStyle = eTransportNTCP;
- addr->caps = caps;
+ addr->transportStyle = eTransportNTCP2;
addr->date = 0;
- if (port) addr->published = true;
+ addr->published = true;
memcpy (addr->s, staticKey, 32);
memcpy (addr->i, iv, 16);
+ addr->caps = 0;
+ if (host.is_unspecified ())
+ {
+ if (host.is_v4 ()) addr->caps |= eV4;
+ if (host.is_v6 ()) addr->caps |= eV6;
+ }
if (addr->IsV4 ())
{
m_SupportedTransports |= eNTCP2V4;
- if (addr->published) m_ReachableTransports |= eNTCP2V4;
+ m_ReachableTransports |= eNTCP2V4;
+ (*m_Addresses)[eNTCP2V4Idx] = addr;
}
if (addr->IsV6 ())
{
- m_SupportedTransports |= eNTCP2V6;
- if (addr->published) m_ReachableTransports |= eNTCP2V6;
+ if (i2p::util::net::IsYggdrasilAddress (addr->host))
+ {
+ m_SupportedTransports |= eNTCP2V6Mesh;
+ m_ReachableTransports |= eNTCP2V6Mesh;
+ (*m_Addresses)[eNTCP2V6MeshIdx] = addr;
+ }
+ else
+ {
+ m_SupportedTransports |= eNTCP2V6;
+ m_ReachableTransports |= eNTCP2V6;
+ (*m_Addresses)[eNTCP2V6Idx] = addr;
+ }
}
- m_Addresses->push_back(std::move(addr));
}
- void RouterInfo::AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, uint8_t caps)
+ void RouterInfo::RemoveNTCP2Address (bool v4)
+ {
+ if (v4)
+ {
+ if ((*m_Addresses)[eNTCP2V6Idx])
+ (*m_Addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4;
+ (*m_Addresses)[eNTCP2V4Idx].reset ();
+ }
+ else
+ {
+ if ((*m_Addresses)[eNTCP2V4Idx])
+ (*m_Addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6;
+ (*m_Addresses)[eNTCP2V6Idx].reset ();
+ }
+ UpdateSupportedTransports ();
+ }
+
+ void RouterInfo::AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, int port, uint8_t caps)
{
auto addr = std::make_shared<Address>();
addr->transportStyle = eTransportSSU2;
- addr->port = 0;
+ addr->port = port;
addr->caps = caps;
addr->date = 0;
addr->ssu.reset (new SSUExt ());
addr->ssu->mtu = 0;
memcpy (addr->s, staticKey, 32);
memcpy (addr->i, introKey, 32);
- if (addr->IsV4 ()) m_SupportedTransports |= eSSU2V4;
- if (addr->IsV6 ()) m_SupportedTransports |= eSSU2V6;
- m_Addresses->push_back(std::move(addr));
+ if (addr->IsV4 ())
+ {
+ m_SupportedTransports |= eSSU2V4;
+ (*m_Addresses)[eSSU2V4Idx] = addr;
+ }
+ if (addr->IsV6 ())
+ {
+ m_SupportedTransports |= eSSU2V6;
+ (*m_Addresses)[eSSU2V6Idx] = addr;
+ }
}
void RouterInfo::AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey,
@@ -728,68 +755,48 @@
addr->host = host;
addr->port = port;
addr->published = true;
- addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
addr->date = 0;
addr->ssu.reset (new SSUExt ());
addr->ssu->mtu = 0;
memcpy (addr->s, staticKey, 32);
memcpy (addr->i, introKey, 32);
+ if (!host.is_unspecified ())
+ addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
+ else
+ {
+ addr->caps = 0;
+ if (host.is_v4 ()) addr->caps |= eV4;
+ if (host.is_v6 ()) addr->caps |= eV6;
+ }
if (addr->IsV4 ())
{
m_SupportedTransports |= eSSU2V4;
m_ReachableTransports |= eSSU2V4;
+ (*m_Addresses)[eSSU2V4Idx] = addr;
}
if (addr->IsV6 ())
{
m_SupportedTransports |= eSSU2V6;
m_ReachableTransports |= eSSU2V6;
+ (*m_Addresses)[eSSU2V6Idx] = addr;
}
- m_Addresses->push_back(std::move(addr));
}
- bool RouterInfo::AddIntroducer (const Introducer& introducer)
+ void RouterInfo::RemoveSSU2Address (bool v4)
{
- for (auto& addr : *m_Addresses)
+ if (v4)
{
- if (addr->transportStyle == eTransportSSU &&
- ((addr->IsV4 () && introducer.iHost.is_v4 ()) || (addr->IsV6 () && introducer.iHost.is_v6 ())))
- {
- for (auto& intro: addr->ssu->introducers)
- if (intro.iTag == introducer.iTag) return false; // already presented
- addr->ssu->introducers.push_back (introducer);
- m_ReachableTransports |= (addr->IsV4 () ? eSSUV4 : eSSUV6);
- return true;
- }
+ if ((*m_Addresses)[eSSU2V6Idx])
+ (*m_Addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4;
+ (*m_Addresses)[eSSU2V4Idx].reset ();
}
- return false;
- }
-
- bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
- {
- for (auto& addr: *m_Addresses)
+ else
{
- if (addr->transportStyle == eTransportSSU &&
- ((addr->IsV4 () && e.address ().is_v4 ()) || (addr->IsV6 () && e.address ().is_v6 ())))
- {
- for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
- if (boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e)
- {
- addr->ssu->introducers.erase (it);
- if (addr->ssu->introducers.empty ())
- m_ReachableTransports &= ~(addr->IsV4 () ? eSSUV4 : eSSUV6);
- return true;
- }
- }
+ if ((*m_Addresses)[eSSU2V4Idx])
+ (*m_Addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6;
+ (*m_Addresses)[eSSU2V6Idx].reset ();
}
- return false;
- }
-
- bool RouterInfo::IsSSU (bool v4only) const
- {
- if (v4only)
- return m_SupportedTransports & eSSUV4;
- else
- return m_SupportedTransports & (eSSUV4 | eSSUV6);
+ UpdateSupportedTransports ();
}
bool RouterInfo::IsNTCP2 (bool v4only) const
@@ -828,21 +835,17 @@
{
if (IsV6 ())
{
- for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
+ if ((*m_Addresses)[eNTCP2V6Idx])
{
- auto addr = *it;
- if (addr->IsV6 ())
- {
- if (addr->IsV4 ())
- {
- addr->caps &= ~AddressCaps::eV6;
- ++it;
- }
- else
- it = m_Addresses->erase (it);
- }
- else
- ++it;
+ if ((*m_Addresses)[eNTCP2V6Idx]->IsV4 () && (*m_Addresses)[eNTCP2V4Idx])
+ (*m_Addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6;
+ (*m_Addresses)[eNTCP2V6Idx].reset ();
+ }
+ if ((*m_Addresses)[eSSU2V6Idx])
+ {
+ if ((*m_Addresses)[eSSU2V6Idx]->IsV4 () && (*m_Addresses)[eSSU2V4Idx])
+ (*m_Addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6;
+ (*m_Addresses)[eSSU2V6Idx].reset ();
}
UpdateSupportedTransports ();
}
@@ -852,21 +855,17 @@
{
if (IsV4 ())
{
- for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
+ if ((*m_Addresses)[eNTCP2V4Idx])
{
- auto addr = *it;
- if (addr->IsV4 ())
- {
- if (addr->IsV6 ())
- {
- addr->caps &= ~AddressCaps::eV4;
- ++it;
- }
- else
- it = m_Addresses->erase (it);
- }
- else
- ++it;
+ if ((*m_Addresses)[eNTCP2V4Idx]->IsV6 () && (*m_Addresses)[eNTCP2V6Idx])
+ (*m_Addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4;
+ (*m_Addresses)[eNTCP2V4Idx].reset ();
+ }
+ if ((*m_Addresses)[eSSU2V4Idx])
+ {
+ if ((*m_Addresses)[eSSU2V4Idx]->IsV6 () && (*m_Addresses)[eSSU2V6Idx])
+ (*m_Addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4;
+ (*m_Addresses)[eSSU2V4Idx].reset ();
}
UpdateSupportedTransports ();
}
@@ -887,57 +886,24 @@
{
m_SupportedTransports &= ~eNTCP2V6Mesh;
m_ReachableTransports &= ~eNTCP2V6Mesh;
- for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
- {
- auto addr = *it;
- if (i2p::util::net::IsYggdrasilAddress (addr->host))
- it = m_Addresses->erase (it);
- else
- ++it;
- }
+ (*m_Addresses)[eNTCP2V6MeshIdx].reset ();
}
}
- std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUAddress (bool v4only) const
- {
- return GetAddress (
- [v4only](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return (address->transportStyle == eTransportSSU) && (!v4only || address->IsV4 ());
- });
- }
-
- std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUV6Address () const
- {
- return GetAddress (
- [](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return (address->transportStyle == eTransportSSU) && address->IsV6();
- });
- }
-
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2V4Address () const
{
- return GetAddress (
- [](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return (address->transportStyle == eTransportSSU2) && address->IsV4();
- });
+ return (*GetAddresses ())[eSSU2V4Idx];
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2V6Address () const
{
- return GetAddress (
- [](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return (address->transportStyle == eTransportSSU2) && address->IsV6();
- });
+ return (*GetAddresses ())[eSSU2V6Idx];
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2Address (bool v4) const
{
if (v4)
- {
+ {
if (m_SupportedTransports & eSSU2V4)
return GetSSU2V4Address ();
}
@@ -945,10 +911,19 @@
{
if (m_SupportedTransports & eSSU2V6)
return GetSSU2V6Address ();
- }
+ }
return nullptr;
- }
-
+ }
+
+ boost::shared_ptr<RouterInfo::Addresses> RouterInfo::GetAddresses () const
+ {
+#if (BOOST_VERSION >= 105300)
+ return boost::atomic_load (&m_Addresses);
+#else
+ return m_Addresses;
+#endif
+ }
+
template<typename Filter>
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (Filter filter) const
{
@@ -959,65 +934,49 @@
auto addresses = m_Addresses;
#endif
for (const auto& address : *addresses)
- if (filter (address)) return address;
+ if (address && filter (address)) return address;
return nullptr;
}
- std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2AddressWithStaticKey (const uint8_t * key) const
+ std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2V4Address () const
{
- if (!key) return nullptr;
- return GetAddress (
- [key](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return address->IsNTCP2 () && !memcmp (address->s, key, 32);
- });
+ return (*GetAddresses ())[eNTCP2V4Idx];
}
- std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2AddressWithStaticKey (const uint8_t * key, bool isV6) const
+ std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2V6Address () const
{
- if (!key) return nullptr;
- return GetAddress (
- [key, isV6](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return address->IsSSU2 () && !memcmp (address->s, key, 32) &&
- ((isV6 && address->IsV6 ()) || (!isV6 && address->IsV4 ()));
- });
+ return (*GetAddresses ())[eNTCP2V6Idx];
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetPublishedNTCP2V4Address () const
{
- return GetAddress (
- [](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return address->IsPublishedNTCP2 () && address->host.is_v4 ();
- });
+ auto addr = (*GetAddresses ())[eNTCP2V4Idx];
+ if (addr && addr->IsPublishedNTCP2 ()) return addr;
+ return nullptr;
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetPublishedNTCP2V6Address () const
{
- return GetAddress (
- [](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return address->IsPublishedNTCP2 () && address->host.is_v6 () &&
- !i2p::util::net::IsYggdrasilAddress (address->host);
- });
+ auto addr = (*GetAddresses ())[eNTCP2V6Idx];
+ if (addr && addr->IsPublishedNTCP2 ()) return addr;
+ return nullptr;
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetYggdrasilAddress () const
{
- return GetAddress (
- [](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return address->IsPublishedNTCP2 () && i2p::util::net::IsYggdrasilAddress (address->host);
- });
+ return (*GetAddresses ())[eNTCP2V6MeshIdx];
}
std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
{
- if (!m_Profile)
- m_Profile = GetRouterProfile (GetIdentHash ());
- return m_Profile;
+ auto profile = m_Profile;
+ if (!profile)
+ {
+ profile = GetRouterProfile (GetIdentHash ());
+ m_Profile = profile;
+ }
+ return profile;
}
void RouterInfo::Encrypt (const uint8_t * data, uint8_t * encrypted) const
@@ -1029,61 +988,42 @@
bool RouterInfo::IsEligibleFloodfill () const
{
- // floodfill must be reachable by ipv4, >= 0.9.38 and not DSA
- return IsReachableBy (eNTCP2V4 | eSSUV4) && m_Version >= NETDB_MIN_FLOODFILL_VERSION &&
+ // floodfill must have published ipv4, >= 0.9.38 and not DSA
+ return m_Version >= NETDB_MIN_FLOODFILL_VERSION && IsPublished (true) &&
GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
}
- bool RouterInfo::IsPeerTesting (bool v4) const
- {
- if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false;
- return (bool)GetAddress (
- [v4](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return (address->transportStyle == eTransportSSU) && address->IsPeerTesting () &&
- ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && address->IsReachableSSU ();
- });
- }
-
- bool RouterInfo::IsSSU2PeerTesting (bool v4) const
+ bool RouterInfo::IsPublished (bool v4) const
{
- if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false;
- return (bool)GetAddress (
- [v4](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return (address->IsSSU2 ()) && address->IsPeerTesting () &&
- ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && address->IsReachableSSU ();
- });
+ if (m_Caps & (eUnreachable | eHidden)) return false; // if router sets U or H we assume that all addreses are not published
+ auto addr = GetAddresses ();
+ if (v4)
+ return ((*addr)[eNTCP2V4Idx] && ((*addr)[eNTCP2V4Idx])->published) ||
+ ((*addr)[eSSU2V4Idx] && ((*addr)[eSSU2V4Idx])->published);
+ else
+ return ((*addr)[eNTCP2V6Idx] && ((*addr)[eNTCP2V6Idx])->published) ||
+ ((*addr)[eSSU2V6Idx] && ((*addr)[eSSU2V6Idx])->published);
}
- bool RouterInfo::IsIntroducer (bool v4) const
+ bool RouterInfo::IsSSU2PeerTesting (bool v4) const
{
- if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false;
- return (bool)GetAddress (
- [v4](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return (address->transportStyle == eTransportSSU) && address->IsIntroducer () &&
- ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && !address->host.is_unspecified ();
- });
+ if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false;
+ auto addr = (*GetAddresses ())[v4 ? eSSU2V4Idx : eSSU2V6Idx];
+ return addr && addr->IsPeerTesting () && addr->IsReachableSSU ();
}
bool RouterInfo::IsSSU2Introducer (bool v4) const
{
if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false;
- return (bool)GetAddress (
- [v4](std::shared_ptr<const RouterInfo::Address> address)->bool
- {
- return (address->IsSSU2 ()) && address->IsIntroducer () &&
- ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && !address->host.is_unspecified ();
- });
+ auto addr = (*GetAddresses ())[v4 ? eSSU2V4Idx : eSSU2V6Idx];
+ return addr && addr->IsIntroducer () && !addr->host.is_unspecified () && addr->port;
}
-
+
void RouterInfo::SetUnreachableAddressesTransportCaps (uint8_t transports)
{
for (auto& addr: *m_Addresses)
{
- // TODO: implement SSU
- if (!addr->published && (addr->transportStyle == eTransportNTCP || addr->transportStyle == eTransportSSU2))
+ if (addr && !addr->published)
{
addr->caps &= ~(eV4 | eV6);
addr->caps |= transports;
@@ -1097,34 +1037,54 @@
m_ReachableTransports = 0;
for (const auto& addr: *m_Addresses)
{
+ if (!addr) continue;
uint8_t transports = 0;
switch (addr->transportStyle)
- {
- case eTransportNTCP:
+ {
+ case eTransportNTCP2:
if (addr->IsV4 ()) transports |= eNTCP2V4;
if (addr->IsV6 ())
transports |= (i2p::util::net::IsYggdrasilAddress (addr->host) ? eNTCP2V6Mesh : eNTCP2V6);
if (addr->IsPublishedNTCP2 ())
m_ReachableTransports |= transports;
break;
- case eTransportSSU:
- if (addr->IsV4 ()) transports |= eSSUV4;
- if (addr->IsV6 ()) transports |= eSSUV6;
- if (addr->IsReachableSSU ())
- m_ReachableTransports |= transports;
- break;
case eTransportSSU2:
if (addr->IsV4 ()) transports |= eSSU2V4;
if (addr->IsV6 ()) transports |= eSSU2V6;
if (addr->IsReachableSSU ())
m_ReachableTransports |= transports;
- break;
- default: ;
- }
+ break;
+ default: ;
+ }
m_SupportedTransports |= transports;
}
}
+ void RouterInfo::UpdateIntroducers (uint64_t ts)
+ {
+ if (ts*1000 < m_Timestamp + INTRODUCER_UPDATE_INTERVAL) return;
+ if (m_ReachableTransports & eSSU2V4)
+ {
+ auto addr = (*GetAddresses ())[eSSU2V4Idx];
+ if (addr && addr->UsesIntroducer ())
+ {
+ UpdateIntroducers (addr, ts);
+ if (!addr->UsesIntroducer ()) // no more valid introducers
+ m_ReachableTransports &= ~eSSU2V4;
+ }
+ }
+ if (m_ReachableTransports & eSSU2V6)
+ {
+ auto addr = (*GetAddresses ())[eSSU2V6Idx];
+ if (addr && addr->UsesIntroducer ())
+ {
+ UpdateIntroducers (addr, ts);
+ if (!addr->UsesIntroducer ()) // no more valid introducers
+ m_ReachableTransports &= ~eSSU2V6;
+ }
+ }
+ }
+
void RouterInfo::UpdateBuffer (const uint8_t * buf, size_t len)
{
if (!m_Buffer)
@@ -1139,11 +1099,47 @@
return netdb.NewRouterInfoBuffer ();
}
+ std::shared_ptr<RouterInfo::Address> RouterInfo::NewAddress () const
+ {
+ return netdb.NewRouterInfoAddress ();
+ }
+
+ boost::shared_ptr<RouterInfo::Addresses> RouterInfo::NewAddresses () const
+ {
+ return netdb.NewRouterInfoAddresses ();
+ }
+
+ std::shared_ptr<IdentityEx> RouterInfo::NewIdentity (const uint8_t * buf, size_t len) const
+ {
+ return netdb.NewIdentity (buf, len);
+ }
+
void RouterInfo::RefreshTimestamp ()
{
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
}
+ bool RouterInfo::IsHighCongestion (bool highBandwidth) const
+ {
+ switch (m_Congestion)
+ {
+ case eLowCongestion:
+ return false;
+ break;
+ case eMediumCongestion:
+ return highBandwidth;
+ break;
+ case eHighCongestion:
+ return i2p::util::GetMillisecondsSinceEpoch () < m_Timestamp + HIGH_CONGESTION_INTERVAL*1000LL;
+ break;
+ case eRejectAll:
+ return true;
+ break;
+ default:
+ return false;
+ }
+ }
+
void LocalRouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
{
RefreshTimestamp ();
@@ -1195,107 +1191,101 @@
if (c & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
if (c & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
+ switch (GetCongestion ())
+ {
+ case eMediumCongestion:
+ caps += CAPS_FLAG_MEDIUM_CONGESTION;
+ break;
+ case eHighCongestion:
+ caps += CAPS_FLAG_HIGH_CONGESTION;
+ break;
+ case eRejectAll:
+ caps += CAPS_FLAG_REJECT_ALL_CONGESTION;
+ break;
+ default: ;
+ };
+
SetProperty ("caps", caps);
}
+ bool LocalRouterInfo::UpdateCongestion (Congestion c)
+ {
+ if (c != GetCongestion ())
+ {
+ SetCongestion (c);
+ UpdateCapsProperty ();
+ return true;
+ }
+ return false;
+ }
+
void LocalRouterInfo::WriteToStream (std::ostream& s) const
{
+ auto addresses = GetAddresses ();
+ if (!addresses) return;
+
uint64_t ts = htobe64 (GetTimestamp ());
s.write ((const char *)&ts, sizeof (ts));
-
// addresses
- const Addresses& addresses = GetAddresses ();
- uint8_t numAddresses = addresses.size ();
+ uint8_t numAddresses = 0;
+ for (size_t idx = 0; idx < addresses->size(); idx++)
+ {
+ auto addr_ptr = (*addresses)[idx];
+ if (!addr_ptr) continue;
+ if (idx == eNTCP2V6Idx && addr_ptr == (*addresses)[eNTCP2V4Idx]) continue;
+ if (idx == eSSU2V6Idx && addr_ptr == (*addresses)[eSSU2V4Idx]) continue;
+ numAddresses++;
+ }
s.write ((char *)&numAddresses, sizeof (numAddresses));
- for (const auto& addr_ptr : addresses)
+ for (size_t idx = 0; idx < addresses->size(); idx++)
{
+ auto addr_ptr = (*addresses)[idx];
+ if (!addr_ptr) continue;
+ if (idx == eNTCP2V6Idx && addr_ptr == (*addresses)[eNTCP2V4Idx]) continue;
+ if (idx == eSSU2V6Idx && addr_ptr == (*addresses)[eSSU2V4Idx]) continue;
const Address& address = *addr_ptr;
// calculate cost
uint8_t cost = 0x7f;
- if (address.transportStyle == eTransportNTCP)
+ if (address.transportStyle == eTransportNTCP2)
cost = address.published ? COST_NTCP2_PUBLISHED : COST_NTCP2_NON_PUBLISHED;
- else if (address.transportStyle == eTransportSSU)
- cost = address.published ? COST_SSU_DIRECT : COST_SSU_THROUGH_INTRODUCERS;
else if (address.transportStyle == eTransportSSU2)
cost = address.published ? COST_SSU2_DIRECT : COST_SSU2_NON_PUBLISHED;
+ else
+ continue; // skip unknown address
s.write ((const char *)&cost, sizeof (cost));
s.write ((const char *)&address.date, sizeof (address.date));
std::stringstream properties;
- bool isPublished = false;
- if (address.transportStyle == eTransportNTCP)
+ bool isPublished = address.published && !address.host.is_unspecified () && address.port;
+ if (address.transportStyle == eTransportNTCP2)
{
- if (address.IsNTCP2 ())
- {
- WriteString ("NTCP2", s);
- if (address.IsPublishedNTCP2 () && !address.host.is_unspecified () && address.port)
- isPublished = true;
- else
- {
- WriteString ("caps", properties);
- properties << '=';
- std::string caps;
- if (address.IsV4 ()) caps += CAPS_FLAG_V4;
- if (address.IsV6 ()) caps += CAPS_FLAG_V6;
- if (caps.empty ()) caps += CAPS_FLAG_V4;
- WriteString (caps, properties);
- properties << ';';
- }
- }
- else
- continue; // don't write NTCP address
- }
- else if (address.transportStyle == eTransportSSU)
- {
- WriteString ("SSU", s);
+ WriteString ("NTCP2", s);
// caps
- WriteString ("caps", properties);
- properties << '=';
- std::string caps;
- if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING;
- if (address.host.is_v4 ())
- {
- if (address.published)
- {
- isPublished = true;
- if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
- }
- else
- caps += CAPS_FLAG_V4;
- }
- else if (address.host.is_v6 ())
- {
- if (address.published)
- {
- isPublished = true;
- if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
- }
- else
- caps += CAPS_FLAG_V6;
- }
- else
+ if (!isPublished)
{
+ WriteString ("caps", properties);
+ properties << '=';
+ std::string caps;
if (address.IsV4 ()) caps += CAPS_FLAG_V4;
- if (address.IsV6 ()) caps += CAPS_FLAG_V6;
+ if (address.IsV6 () || address.host.is_v6 ()) caps += CAPS_FLAG_V6; // we set 6 for unspecified ipv6
if (caps.empty ()) caps += CAPS_FLAG_V4;
+ WriteString (caps, properties);
+ properties << ';';
}
- WriteString (caps, properties);
- properties << ';';
}
else if (address.transportStyle == eTransportSSU2)
{
WriteString ("SSU2", s);
// caps
std::string caps;
- if (address.published)
+ if (isPublished)
{
- isPublished = true;
- if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING;
- if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
+ if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU2_TESTING;
+ if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU2_INTRODUCER;
}
else
{
if (address.IsV4 ()) caps += CAPS_FLAG_V4;
- if (address.IsV6 ()) caps += CAPS_FLAG_V6;
+ if (address.IsV6 () || address.host.is_v6 ()) caps += CAPS_FLAG_V6; // we set 6 for unspecified ipv6
if (caps.empty ()) caps += CAPS_FLAG_V4;
}
if (!caps.empty ())
@@ -1323,7 +1313,7 @@
size_t len = address.IsSSU2 () ? 32 : 16;
WriteString (address.i.ToBase64 (len), properties); properties << ';';
}
- if (address.transportStyle == eTransportSSU || address.IsSSU2 ())
+ if (address.transportStyle == eTransportSSU2)
{
// write introducers if any
if (address.ssu && !address.ssu->introducers.empty())
@@ -1331,6 +1321,7 @@
int i = 0;
for (const auto& introducer: address.ssu->introducers)
{
+ if (!introducer.iTag) continue;
if (introducer.iExp) // expiration is specified
{
WriteString ("iexp" + boost::lexical_cast<std::string>(i), properties);
@@ -1340,48 +1331,23 @@
}
i++;
}
- if (address.transportStyle == eTransportSSU)
- {
- i = 0;
- for (const auto& introducer: address.ssu->introducers)
- {
- WriteString ("ihost" + boost::lexical_cast<std::string>(i), properties);
- properties << '=';
- WriteString (introducer.iHost.to_string (), properties);
- properties << ';';
- i++;
- }
- }
i = 0;
for (const auto& introducer: address.ssu->introducers)
{
- if (address.IsSSU2 ())
- WriteString ("ih" + boost::lexical_cast<std::string>(i), properties);
- else
- WriteString ("ikey" + boost::lexical_cast<std::string>(i), properties);
+ if (!introducer.iTag) continue;
+ WriteString ("ih" + boost::lexical_cast<std::string>(i), properties);
properties << '=';
char value[64];
- size_t l = ByteStreamToBase64 (introducer.iKey, 32, value, 64);
+ size_t l = ByteStreamToBase64 (introducer.iH, 32, value, 64);
value[l] = 0;
WriteString (value, properties);
properties << ';';
i++;
}
- if (address.transportStyle == eTransportSSU)
- {
- i = 0;
- for (const auto& introducer: address.ssu->introducers)
- {
- WriteString ("iport" + boost::lexical_cast<std::string>(i), properties);
- properties << '=';
- WriteString (boost::lexical_cast<std::string>(introducer.iPort), properties);
- properties << ';';
- i++;
- }
- }
i = 0;
for (const auto& introducer: address.ssu->introducers)
{
+ if (!introducer.iTag) continue;
WriteString ("itag" + boost::lexical_cast<std::string>(i), properties);
properties << '=';
WriteString (boost::lexical_cast<std::string>(introducer.iTag), properties);
@@ -1390,18 +1356,8 @@
}
}
}
- if (address.transportStyle == eTransportSSU)
- {
- // write intro key
- WriteString ("key", properties);
- properties << '=';
- char value[64];
- size_t l = ByteStreamToBase64 (address.i, 32, value, 64);
- value[l] = 0;
- WriteString (value, properties);
- properties << ';';
- }
- if (address.transportStyle == eTransportSSU || address.IsSSU2 ())
+
+ if (address.transportStyle == eTransportSSU2)
{
// write mtu
if (address.ssu && address.ssu->mtu)
@@ -1412,7 +1368,7 @@
properties << ';';
}
}
- if ((isPublished || (address.ssu && !address.IsSSU2 ())) && address.port)
+ if (isPublished && address.port)
{
WriteString ("port", properties);
properties << '=';
@@ -1481,39 +1437,54 @@
return std::make_shared<Buffer> ();
}
+ std::shared_ptr<RouterInfo::Address> LocalRouterInfo::NewAddress () const
+ {
+ return std::make_shared<Address> ();
+ }
+
+ boost::shared_ptr<RouterInfo::Addresses> LocalRouterInfo::NewAddresses () const
+ {
+ return boost::make_shared<Addresses> ();
+ }
+
+ std::shared_ptr<IdentityEx> LocalRouterInfo::NewIdentity (const uint8_t * buf, size_t len) const
+ {
+ return std::make_shared<IdentityEx> (buf, len);
+ }
+
bool LocalRouterInfo::AddSSU2Introducer (const Introducer& introducer, bool v4)
{
- for (auto& addr : GetAddresses ())
- {
- if (addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ())))
- {
- for (auto& intro: addr->ssu->introducers)
- if (intro.iTag == introducer.iTag) return false; // already presented
- addr->ssu->introducers.push_back (introducer);
- SetReachableTransports (GetReachableTransports () | ((addr->IsV4 () ? eSSU2V4 : eSSU2V6)));
- return true;
- }
+ auto addresses = GetAddresses ();
+ if (!addresses) return false;
+ auto addr = (*addresses)[v4 ? eSSU2V4Idx : eSSU2V6Idx];
+ if (addr)
+ {
+ for (auto& intro: addr->ssu->introducers)
+ if (intro.iTag == introducer.iTag) return false; // already presented
+ addr->ssu->introducers.push_back (introducer);
+ SetReachableTransports (GetReachableTransports () | ((addr->IsV4 () ? eSSU2V4 : eSSU2V6)));
+ return true;
}
return false;
- }
+ }
bool LocalRouterInfo::RemoveSSU2Introducer (const IdentHash& h, bool v4)
{
- for (auto& addr: GetAddresses ())
- {
- if (addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ())))
- {
- for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
- if (h == it->iKey)
- {
- addr->ssu->introducers.erase (it);
- if (addr->ssu->introducers.empty ())
- SetReachableTransports (GetReachableTransports () & ~(addr->IsV4 () ? eSSU2V4 : eSSU2V6));
- return true;
- }
- }
+ auto addresses = GetAddresses ();
+ if (!addresses) return false;
+ auto addr = (*addresses)[v4 ? eSSU2V4Idx : eSSU2V6Idx];
+ if (addr)
+ {
+ for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
+ if (h == it->iH)
+ {
+ addr->ssu->introducers.erase (it);
+ if (addr->ssu->introducers.empty ())
+ SetReachableTransports (GetReachableTransports () & ~(addr->IsV4 () ? eSSU2V4 : eSSU2V6));
+ return true;
+ }
}
return false;
- }
+ }
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/RouterInfo.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -42,35 +42,54 @@
const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M'; /* 48-64 KBps */
const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N'; /* 64-128 KBps */
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */
- const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */
- const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */
-
+ const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2048 KBps */
+ const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2048 KBps */
+ // bandwidth limits in kBps
+ const uint32_t LOW_BANDWIDTH_LIMIT = 48;
+ const uint32_t HIGH_BANDWIDTH_LIMIT = 256;
+ const uint32_t EXTRA_BANDWIDTH_LIMIT = 2048;
+ // congesion flags
+ const char CAPS_FLAG_MEDIUM_CONGESTION = 'D';
+ const char CAPS_FLAG_HIGH_CONGESTION = 'E';
+ const char CAPS_FLAG_REJECT_ALL_CONGESTION = 'G';
+
const char CAPS_FLAG_V4 = '4';
const char CAPS_FLAG_V6 = '6';
- const char CAPS_FLAG_SSU_TESTING = 'B';
- const char CAPS_FLAG_SSU_INTRODUCER = 'C';
+ const char CAPS_FLAG_SSU2_TESTING = 'B';
+ const char CAPS_FLAG_SSU2_INTRODUCER = 'C';
const uint8_t COST_NTCP2_PUBLISHED = 3;
const uint8_t COST_NTCP2_NON_PUBLISHED = 14;
const uint8_t COST_SSU2_DIRECT = 8;
- const uint8_t COST_SSU_DIRECT = 9;
- const uint8_t COST_SSU_THROUGH_INTRODUCERS = 11;
const uint8_t COST_SSU2_NON_PUBLISHED = 15;
const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later
+ const int HIGH_CONGESTION_INTERVAL = 15*60; // in seconds, 15 minutes
+ const int INTRODUCER_UPDATE_INTERVAL = 20*60*1000; // in milliseconds, 20 minutes
+
class RouterInfo: public RoutingDestination
{
public:
+ enum SupportedTransportsIdx
+ {
+ eNTCP2V4Idx = 0,
+ eNTCP2V6Idx,
+ eSSU2V4Idx,
+ eSSU2V6Idx,
+ eNTCP2V6MeshIdx,
+ eNumTransports
+ };
+
+#define TransportBit(tr) e##tr = (1 << e##tr##Idx)
+
enum SupportedTransports
{
- eNTCP2V4 = 0x01,
- eNTCP2V6 = 0x02,
- eSSUV4 = 0x04,
- eSSUV6 = 0x08,
- eNTCP2V6Mesh = 0x10,
- eSSU2V4 = 0x20,
- eSSU2V6 = 0x40,
+ TransportBit(NTCP2V4), // 0x01
+ TransportBit(NTCP2V6), // 0x02
+ TransportBit(SSU2V4), // 0x04
+ TransportBit(SSU2V6), // 0x08
+ TransportBit(NTCP2V6Mesh), // 0x10
eAllTransports = 0xFF
};
typedef uint8_t CompatibleTransports;
@@ -85,6 +104,14 @@
eUnreachable = 0x20
};
+ enum Congestion
+ {
+ eLowCongestion = 0,
+ eMediumCongestion,
+ eHighCongestion,
+ eRejectAll
+ };
+
enum AddressCaps
{
eV4 = 0x01,
@@ -96,18 +123,14 @@
enum TransportStyle
{
eTransportUnknown = 0,
- eTransportNTCP,
- eTransportSSU,
+ eTransportNTCP2,
eTransportSSU2
};
- typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey
struct Introducer
{
- Introducer (): iPort (0), iExp (0) {};
- boost::asio::ip::address iHost;
- int iPort;
- IntroKey iKey; // or ih for SSU2
+ Introducer (): iTag (0), iExp (0) { iH.Fill(0); };
+ IdentHash iH;
uint32_t iTag;
uint32_t iExp;
};
@@ -146,7 +169,7 @@
return !(*this == other);
}
- bool IsNTCP2 () const { return transportStyle == eTransportNTCP; };
+ bool IsNTCP2 () const { return transportStyle == eTransportNTCP2; };
bool IsSSU2 () const { return transportStyle == eTransportSSU2; };
bool IsPublishedNTCP2 () const { return IsNTCP2 () && published; };
bool IsReachableSSU () const { return (bool)ssu && (published || UsesIntroducer ()); };
@@ -167,7 +190,7 @@
Buffer (const uint8_t * buf, size_t len);
};
- typedef std::vector<std::shared_ptr<Address> > Addresses;
+ typedef std::array<std::shared_ptr<Address>, eNumTransports> Addresses;
RouterInfo (const std::string& fullPath);
RouterInfo (const RouterInfo& ) = default;
@@ -183,39 +206,36 @@
int GetVersion () const { return m_Version; };
virtual void SetProperty (const std::string& key, const std::string& value) {};
virtual void ClearProperties () {};
- Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr
- std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey (const uint8_t * key) const;
- std::shared_ptr<const Address> GetSSU2AddressWithStaticKey (const uint8_t * key, bool isV6) const;
+ boost::shared_ptr<Addresses> GetAddresses () const; // should be called for local RI only, otherwise must return shared_ptr
+ std::shared_ptr<const Address> GetNTCP2V4Address () const;
+ std::shared_ptr<const Address> GetNTCP2V6Address () const;
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
- std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const;
- std::shared_ptr<const Address> GetSSUV6Address () const;
std::shared_ptr<const Address> GetYggdrasilAddress () const;
std::shared_ptr<const Address> GetSSU2V4Address () const;
std::shared_ptr<const Address> GetSSU2V6Address () const;
std::shared_ptr<const Address> GetSSU2Address (bool v4) const;
- void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
+ void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,int port, uint8_t caps); // non published
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
- const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0);
- void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, uint8_t caps = 0); // non published
+ const boost::asio::ip::address& host, int port); // published
+ void RemoveNTCP2Address (bool v4);
+ void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, int port, uint8_t caps); // non published
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey,
const boost::asio::ip::address& host, int port); // published
- bool AddIntroducer (const Introducer& introducer);
- bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
+ void RemoveSSU2Address (bool v4);
void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps
void UpdateSupportedTransports ();
+ void UpdateIntroducers (uint64_t ts); // ts in seconds
bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; };
- bool IsReachable () const { return m_Caps & Caps::eReachable; };
+ void ResetFlooldFill () { m_Caps &= ~Caps::eFloodfill; };
bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
- bool IsSSU (bool v4only = true) const;
- bool IsSSUV6 () const { return m_SupportedTransports & eSSUV6; };
bool IsNTCP2 (bool v4only = true) const;
bool IsNTCP2V6 () const { return m_SupportedTransports & eNTCP2V6; };
bool IsSSU2V4 () const { return m_SupportedTransports & eSSU2V4; };
bool IsSSU2V6 () const { return m_SupportedTransports & eSSU2V6; };
- bool IsV6 () const { return m_SupportedTransports & (eSSUV6 | eNTCP2V6 | eSSU2V6); };
- bool IsV4 () const { return m_SupportedTransports & (eSSUV4 | eNTCP2V4 | eSSU2V4); };
+ bool IsV6 () const { return m_SupportedTransports & (eNTCP2V6 | eSSU2V6); };
+ bool IsV4 () const { return m_SupportedTransports & (eNTCP2V4 | eSSU2V4); };
bool IsMesh () const { return m_SupportedTransports & eNTCP2V6Mesh; };
void EnableV6 ();
void DisableV6 ();
@@ -232,18 +252,21 @@
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
bool IsEligibleFloodfill () const;
- bool IsPeerTesting (bool v4) const;
+ bool IsPublished (bool v4) const;
bool IsSSU2PeerTesting (bool v4) const;
- bool IsIntroducer (bool v4) const;
bool IsSSU2Introducer (bool v4) const;
+ bool IsHighCongestion (bool highBandwidth) const;
uint8_t GetCaps () const { return m_Caps; };
void SetCaps (uint8_t caps) { m_Caps = caps; };
+ Congestion GetCongestion () const { return m_Congestion; };
+
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
bool IsUnreachable () const { return m_IsUnreachable; };
+ void ExcludeReachableTransports (CompatibleTransports transports) { m_ReachableTransports &= ~transports; };
- const uint8_t * GetBuffer () const { return m_Buffer->data (); };
+ const uint8_t * GetBuffer () const { return m_Buffer ? m_Buffer->data () : nullptr; };
const uint8_t * LoadBuffer (const std::string& fullPath); // load if necessary
size_t GetBufferLen () const { return m_BufferLen; };
@@ -252,9 +275,9 @@
bool SaveToFile (const std::string& fullPath);
std::shared_ptr<RouterProfile> GetProfile () const;
- void SaveProfile () { if (m_Profile) m_Profile->Save (GetIdentHash ()); };
+ void DropProfile () { m_Profile = nullptr; };
- void Update (const uint8_t * buf, size_t len);
+ bool Update (const uint8_t * buf, size_t len);
void DeleteBuffer () { m_Buffer = nullptr; };
bool IsNewer (const uint8_t * buf, size_t len) const;
@@ -274,10 +297,10 @@
void UpdateBuffer (const uint8_t * buf, size_t len);
void SetBufferLen (size_t len) { m_BufferLen = len; };
void RefreshTimestamp ();
- const Addresses& GetAddresses () const { return *m_Addresses; };
CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; };
- void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; };
-
+ void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; };
+ void SetCongestion (Congestion c) { m_Congestion = c; };
+
private:
bool LoadFile (const std::string& fullPath);
@@ -287,9 +310,13 @@
size_t ReadString (char* str, size_t len, std::istream& s) const;
void ExtractCaps (const char * value);
uint8_t ExtractAddressCaps (const char * value) const;
+ void UpdateIntroducers (std::shared_ptr<Address> address, uint64_t ts);
template<typename Filter>
std::shared_ptr<const Address> GetAddress (Filter filter) const;
virtual std::shared_ptr<Buffer> NewBuffer () const;
+ virtual std::shared_ptr<Address> NewAddress () const;
+ virtual boost::shared_ptr<Addresses> NewAddresses () const;
+ virtual std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) const;
private:
@@ -297,12 +324,13 @@
std::shared_ptr<const IdentityEx> m_RouterIdentity;
std::shared_ptr<Buffer> m_Buffer;
size_t m_BufferLen;
- uint64_t m_Timestamp;
+ uint64_t m_Timestamp; // in milliseconds
boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9
bool m_IsUpdated, m_IsUnreachable;
CompatibleTransports m_SupportedTransports, m_ReachableTransports;
uint8_t m_Caps;
int m_Version;
+ Congestion m_Congestion;
mutable std::shared_ptr<RouterProfile> m_Profile;
};
@@ -313,6 +341,7 @@
LocalRouterInfo () = default;
void CreateBuffer (const PrivateKeys& privateKeys);
void UpdateCaps (uint8_t caps);
+ bool UpdateCongestion (Congestion c); // returns true if updated
void SetProperty (const std::string& key, const std::string& value) override;
void DeleteProperty (const std::string& key);
@@ -321,13 +350,16 @@
bool AddSSU2Introducer (const Introducer& introducer, bool v4);
bool RemoveSSU2Introducer (const IdentHash& h, bool v4);
-
+
private:
void WriteToStream (std::ostream& s) const;
void UpdateCapsProperty ();
void WriteString (const std::string& str, std::ostream& s) const;
std::shared_ptr<Buffer> NewBuffer () const override;
+ std::shared_ptr<Address> NewAddress () const override;
+ boost::shared_ptr<Addresses> NewAddresses () const override;
+ std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) const override;
private:
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/SSU2.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022, The PurpleI2P Project
+* Copyright (c) 2022-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -17,14 +17,15 @@
namespace i2p
{
namespace transport
-{
+{
SSU2Server::SSU2Server ():
RunnableServiceWithWork ("SSU2"), m_ReceiveService ("SSU2r"),
m_SocketV4 (m_ReceiveService.GetService ()), m_SocketV6 (m_ReceiveService.GetService ()),
m_AddressV4 (boost::asio::ip::address_v4()), m_AddressV6 (boost::asio::ip::address_v6()),
- m_TerminationTimer (GetService ()), m_ResendTimer (GetService ()),
+ m_TerminationTimer (GetService ()), m_CleanupTimer (GetService ()), m_ResendTimer (GetService ()),
m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()),
- m_IsPublished (true), m_IsSyncClockFromPeers (true)
+ m_IsPublished (true), m_IsSyncClockFromPeers (true), m_PendingTimeOffset (0),
+ m_IsThroughProxy (false)
{
}
@@ -36,12 +37,32 @@
i2p::config::GetOption ("ssu2.published", m_IsPublished);
i2p::config::GetOption("nettime.frompeers", m_IsSyncClockFromPeers);
bool found = false;
- auto& addresses = i2p::context.GetRouterInfo ().GetAddresses ();
- for (const auto& address: addresses)
+ auto addresses = i2p::context.GetRouterInfo ().GetAddresses ();
+ if (!addresses) return;
+ for (const auto& address: *addresses)
{
if (!address) continue;
if (address->transportStyle == i2p::data::RouterInfo::eTransportSSU2)
{
+ if (m_IsThroughProxy)
+ {
+ found = true;
+ if (address->IsV6 ())
+ {
+ uint16_t mtu; i2p::config::GetOption ("ssu2.mtu6", mtu);
+ if (!mtu || mtu > SSU2_MAX_PACKET_SIZE - SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE)
+ mtu = SSU2_MAX_PACKET_SIZE - SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE;
+ i2p::context.SetMTU (mtu, false);
+ }
+ else
+ {
+ uint16_t mtu; i2p::config::GetOption ("ssu2.mtu4", mtu);
+ if (!mtu || mtu > SSU2_MAX_PACKET_SIZE - SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE)
+ mtu = SSU2_MAX_PACKET_SIZE - SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE;
+ i2p::context.SetMTU (mtu, true);
+ }
+ continue; // we don't need port for proxy
+ }
auto port = address->port;
if (!port)
{
@@ -49,9 +70,8 @@
if (ssu2Port) port = ssu2Port;
else
{
- bool ssu; i2p::config::GetOption("ssu", ssu);
uint16_t p; i2p::config::GetOption ("port", p);
- if (p) port = ssu ? (p + 1) : p;
+ if (p) port = p;
}
}
if (port)
@@ -59,6 +79,7 @@
if (address->IsV4 ())
{
found = true;
+ LogPrint (eLogDebug, "SSU2: Opening IPv4 socket at Start");
OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV4, port));
m_ReceiveService.GetService ().post(
[this]()
@@ -70,6 +91,7 @@
if (address->IsV6 ())
{
found = true;
+ LogPrint (eLogDebug, "SSU2: Opening IPv6 socket at Start");
OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV6, port));
m_ReceiveService.GetService ().post(
[this]()
@@ -80,37 +102,50 @@
}
}
else
- LogPrint (eLogError, "SSU2: Can't start server because port not specified");
+ LogPrint (eLogCritical, "SSU2: Can't start server because port not specified");
}
}
if (found)
+ {
+ if (m_IsThroughProxy)
+ ConnectToProxy ();
m_ReceiveService.Start ();
+ }
ScheduleTermination ();
+ ScheduleCleanup ();
+ ScheduleResend (false);
}
}
void SSU2Server::Stop ()
{
if (IsRunning ())
- {
+ {
m_TerminationTimer.cancel ();
+ m_CleanupTimer.cancel ();
m_ResendTimer.cancel ();
m_IntroducersUpdateTimer.cancel ();
m_IntroducersUpdateTimerV6.cancel ();
- }
-
+ }
+
auto sessions = m_Sessions;
for (auto& it: sessions)
- {
+ {
it.second->RequestTermination (eSSU2TerminationReasonRouterShutdown);
it.second->Done ();
- }
-
+ }
+
if (context.SupportsV4 () || context.SupportsV6 ())
m_ReceiveService.Stop ();
m_SocketV4.close ();
m_SocketV6.close ();
-
+
+ if (m_UDPAssociateSocket)
+ {
+ m_UDPAssociateSocket->close ();
+ m_UDPAssociateSocket.reset (nullptr);
+ }
+
StopIOService ();
m_Sessions.clear ();
@@ -125,45 +160,77 @@
{
if (localAddress.is_unspecified ()) return;
if (localAddress.is_v4 ())
- {
+ {
m_AddressV4 = localAddress;
- int mtu = i2p::util::net::GetMTU (localAddress);
+ uint16_t mtu; i2p::config::GetOption ("ssu2.mtu4", mtu);
+ if (!mtu) mtu = i2p::util::net::GetMTU (localAddress);
if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE;
if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE;
i2p::context.SetMTU (mtu, true);
- }
+ }
else if (localAddress.is_v6 ())
- {
+ {
m_AddressV6 = localAddress;
- int maxMTU = i2p::util::net::GetMaxMTU (localAddress.to_v6 ());
- int mtu = i2p::util::net::GetMTU (localAddress);
- if (mtu > maxMTU) mtu = maxMTU;
+ uint16_t mtu; i2p::config::GetOption ("ssu2.mtu6", mtu);
+ if (!mtu)
+ {
+ int maxMTU = i2p::util::net::GetMaxMTU (localAddress.to_v6 ());
+ mtu = i2p::util::net::GetMTU (localAddress);
+ if (mtu > maxMTU) mtu = maxMTU;
+ }
+ else
+ if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE;
if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE;
i2p::context.SetMTU (mtu, false);
- }
- }
+ }
+ }
bool SSU2Server::IsSupported (const boost::asio::ip::address& addr) const
{
+ if (m_IsThroughProxy)
+ return m_SocketV4.is_open ();
if (addr.is_v4 ())
- {
- if (m_SocketV4.is_open ())
+ {
+ if (m_SocketV4.is_open ())
return true;
- }
+ }
else if (addr.is_v6 ())
- {
- if (m_SocketV6.is_open ())
+ {
+ if (m_SocketV6.is_open ())
return true;
}
return false;
- }
+ }
uint16_t SSU2Server::GetPort (bool v4) const
{
boost::system::error_code ec;
- boost::asio::ip::udp::endpoint ep = v4 ? m_SocketV4.local_endpoint (ec) : m_SocketV6.local_endpoint (ec);
+ boost::asio::ip::udp::endpoint ep = (v4 || m_IsThroughProxy) ? m_SocketV4.local_endpoint (ec) : m_SocketV6.local_endpoint (ec);
if (ec) return 0;
return ep.port ();
+ }
+
+ void SSU2Server::AdjustTimeOffset (int64_t offset)
+ {
+ if (offset)
+ {
+ if (m_PendingTimeOffset) // one more
+ {
+ if (std::abs (m_PendingTimeOffset - offset) < SSU2_CLOCK_SKEW)
+ {
+ offset = (m_PendingTimeOffset + offset)/2; // average
+ LogPrint (eLogWarning, "SSU2: Clock adjusted by ", offset, " seconds");
+ i2p::util::AdjustTimeOffset (offset);
+ }
+ else
+ LogPrint (eLogWarning, "SSU2: Time offsets are too different. Clock not adjusted");
+ m_PendingTimeOffset = 0;
+ }
+ else
+ m_PendingTimeOffset = offset; // first
+ }
+ else
+ m_PendingTimeOffset = 0; // reset
}
boost::asio::ip::udp::socket& SSU2Server::OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint)
@@ -171,6 +238,8 @@
boost::asio::ip::udp::socket& socket = localEndpoint.address ().is_v6 () ? m_SocketV6 : m_SocketV4;
try
{
+ if (socket.is_open ())
+ socket.close ();
socket.open (localEndpoint.protocol ());
if (localEndpoint.address ().is_v6 ())
socket.set_option (boost::asio::ip::v6_only (true));
@@ -181,7 +250,7 @@
}
catch (std::exception& ex )
{
- LogPrint (eLogError, "SSU2: Failed to bind to ", localEndpoint, ": ", ex.what());
+ LogPrint (eLogCritical, "SSU2: Failed to bind to ", localEndpoint, ": ", ex.what());
ThrowFatal ("Unable to start SSU2 transport on ", localEndpoint, ": ", ex.what ());
}
return socket;
@@ -197,7 +266,21 @@
void SSU2Server::HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred,
Packet * packet, boost::asio::ip::udp::socket& socket)
{
- if (!ecode)
+ if (!ecode
+ || ecode == boost::asio::error::connection_refused
+ || ecode == boost::asio::error::connection_reset
+ || ecode == boost::asio::error::network_reset
+ || ecode == boost::asio::error::network_unreachable
+ || ecode == boost::asio::error::host_unreachable
+#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO
+ || ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
+ || ecode.value() == boost::winapi::WSAENETRESET_ // 10052
+ || ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
+ || ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
+#endif
+ )
+ // just try continue reading when received ICMP response otherwise socket can crash,
+ // but better to find out which host were sent it and mark that router as unreachable
{
i2p::transport::transports.UpdateReceivedBytes (bytes_transferred);
packet->len = bytes_transferred;
@@ -238,10 +321,20 @@
if (ecode != boost::asio::error::operation_aborted)
{
LogPrint (eLogError, "SSU2: Receive error: code ", ecode.value(), ": ", ecode.message ());
- auto ep = socket.local_endpoint ();
- socket.close ();
- OpenSocket (ep);
- Receive (socket);
+ if (m_IsThroughProxy)
+ {
+ m_UDPAssociateSocket.reset (nullptr);
+ m_ProxyRelayEndpoint.reset (nullptr);
+ m_SocketV4.close ();
+ ConnectToProxy ();
+ }
+ else
+ {
+ auto ep = socket.local_endpoint ();
+ LogPrint (eLogCritical, "SSU2: Reopening socket in HandleReceivedFrom: code ", ecode.value(), ": ", ecode.message ());
+ OpenSocket (ep);
+ Receive (socket);
+ }
}
}
}
@@ -250,19 +343,26 @@
{
if (packet)
{
- ProcessNextPacket (packet->buf, packet->len, packet->from);
+ if (m_IsThroughProxy)
+ ProcessNextPacketFromProxy (packet->buf, packet->len);
+ else
+ ProcessNextPacket (packet->buf, packet->len, packet->from);
m_PacketsPool.ReleaseMt (packet);
- if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated)
+ if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated)
m_LastSession->FlushData ();
}
}
void SSU2Server::HandleReceivedPackets (std::vector<Packet *> packets)
{
- for (auto& packet: packets)
- ProcessNextPacket (packet->buf, packet->len, packet->from);
+ if (m_IsThroughProxy)
+ for (auto& packet: packets)
+ ProcessNextPacketFromProxy (packet->buf, packet->len);
+ else
+ for (auto& packet: packets)
+ ProcessNextPacket (packet->buf, packet->len, packet->from);
m_PacketsPool.ReleaseMt (packets);
- if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated)
+ if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated)
m_LastSession->FlushData ();
}
@@ -288,7 +388,7 @@
m_Sessions.erase (it);
}
}
-
+
void SSU2Server::AddSessionByRouterHash (std::shared_ptr<SSU2Session> session)
{
if (session)
@@ -313,6 +413,7 @@
bool SSU2Server::AddPendingOutgoingSession (std::shared_ptr<SSU2Session> session)
{
if (!session) return false;
+ std::unique_lock<std::mutex> l(m_PendingOutgoingSessionsMutex);
return m_PendingOutgoingSessions.emplace (session->GetRemoteEndpoint (), session).second;
}
@@ -322,10 +423,11 @@
if (it != m_SessionsByRouterHash.end ())
return it->second;
return nullptr;
- }
+ }
std::shared_ptr<SSU2Session> SSU2Server::FindPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) const
- {
+ {
+ std::unique_lock<std::mutex> l(m_PendingOutgoingSessionsMutex);
auto it = m_PendingOutgoingSessions.find (ep);
if (it != m_PendingOutgoingSessions.end ())
return it->second;
@@ -334,9 +436,10 @@
void SSU2Server::RemovePendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep)
{
+ std::unique_lock<std::mutex> l(m_PendingOutgoingSessionsMutex);
m_PendingOutgoingSessions.erase (ep);
- }
-
+ }
+
std::shared_ptr<SSU2Session> SSU2Server::GetRandomSession (
i2p::data::RouterInfo::CompatibleTransports remoteTransports, const i2p::data::IdentHash& excluded) const
{
@@ -348,23 +451,23 @@
std::advance (it, ind);
while (it != m_Sessions.end ())
{
- if ((it->second->GetRemoteTransports () & remoteTransports) &&
+ if ((it->second->GetRemoteTransports () & remoteTransports) &&
it->second->GetRemoteIdentity ()->GetIdentHash () != excluded)
return it->second;
it++;
}
- // not found, try from begining
+ // not found, try from beginning
it = m_Sessions.begin ();
while (it != m_Sessions.end () && ind)
{
- if ((it->second->GetRemoteTransports () & remoteTransports) &&
+ if ((it->second->GetRemoteTransports () & remoteTransports) &&
it->second->GetRemoteIdentity ()->GetIdentHash () != excluded)
return it->second;
it++; ind--;
- }
+ }
return nullptr;
- }
-
+ }
+
void SSU2Server::AddRelay (uint32_t tag, std::shared_ptr<SSU2Session> relay)
{
m_Relays.emplace (tag, relay);
@@ -408,41 +511,42 @@
switch (m_LastSession->GetState ())
{
case eSSU2SessionStateEstablished:
- case eSSU2SessionStateSessionConfirmedSent:
- m_LastSession->ProcessData (buf, len);
+ case eSSU2SessionStateSessionConfirmedSent:
+ m_LastSession->ProcessData (buf, len, senderEndpoint);
break;
case eSSU2SessionStateSessionCreatedSent:
if (!m_LastSession->ProcessSessionConfirmed (buf, len))
{
m_LastSession->Done ();
m_LastSession = nullptr;
- }
+ }
break;
case eSSU2SessionStateIntroduced:
- if (m_LastSession->GetRemoteEndpoint ().address ().is_unspecified ())
+ if (m_LastSession->GetRemoteEndpoint ().address ().is_unspecified ())
m_LastSession->SetRemoteEndpoint (senderEndpoint);
- if (m_LastSession->GetRemoteEndpoint () == senderEndpoint)
+ if (m_LastSession->GetRemoteEndpoint ().address () == senderEndpoint.address ()) // port might be different
m_LastSession->ProcessHolePunch (buf, len);
else
{
- LogPrint (eLogWarning, "SSU2: HolePunch endpoint ", senderEndpoint,
- " doesn't match RelayResponse ", m_LastSession->GetRemoteEndpoint ());
+ LogPrint (eLogWarning, "SSU2: HolePunch address ", senderEndpoint.address (),
+ " doesn't match RelayResponse ", m_LastSession->GetRemoteEndpoint ().address ());
m_LastSession->Done ();
- m_LastSession = nullptr;
- }
+ m_LastSession = nullptr;
+ }
break;
case eSSU2SessionStatePeerTest:
m_LastSession->SetRemoteEndpoint (senderEndpoint);
m_LastSession->ProcessPeerTest (buf, len);
break;
case eSSU2SessionStateClosing:
- m_LastSession->ProcessData (buf, len); // we might receive termintaion block
- if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated)
+ m_LastSession->ProcessData (buf, len, senderEndpoint); // we might receive termintaion block
+ if (m_LastSession && m_LastSession->GetState () == eSSU2SessionStateClosing)
m_LastSession->RequestTermination (eSSU2TerminationReasonIdleTimeout); // send termination again
- break;
+ break;
+ case eSSU2SessionStateClosingConfirmed:
case eSSU2SessionStateTerminated:
m_LastSession = nullptr;
- break;
+ break;
default:
LogPrint (eLogWarning, "SSU2: Invalid session state ", (int)m_LastSession->GetState ());
}
@@ -455,33 +559,52 @@
{
if (it1->second->GetState () == eSSU2SessionStateSessionRequestSent &&
it1->second->ProcessSessionCreated (buf, len))
- m_PendingOutgoingSessions.erase (it1); // we are done with that endpoint
+ {
+ std::unique_lock<std::mutex> l(m_PendingOutgoingSessionsMutex);
+ m_PendingOutgoingSessions.erase (it1); // we are done with that endpoint
+ }
else
it1->second->ProcessRetry (buf, len);
}
- else
+ else if (!i2p::util::net::IsInReservedRange(senderEndpoint.address ()) && senderEndpoint.port ())
{
// assume new incoming session
auto session = std::make_shared<SSU2Session> (*this);
session->SetRemoteEndpoint (senderEndpoint);
session->ProcessFirstIncomingMessage (connID, buf, len);
}
+ else
+ LogPrint (eLogError, "SSU2: Incoming packet received from invalid endpoint ", senderEndpoint);
}
}
void SSU2Server::Send (const uint8_t * header, size_t headerLen, const uint8_t * payload, size_t payloadLen,
const boost::asio::ip::udp::endpoint& to)
{
+ if (m_IsThroughProxy)
+ {
+ SendThroughProxy (header, headerLen, nullptr, 0, payload, payloadLen, to);
+ return;
+ }
+
std::vector<boost::asio::const_buffer> bufs
{
boost::asio::buffer (header, headerLen),
boost::asio::buffer (payload, payloadLen)
};
+
boost::system::error_code ec;
if (to.address ().is_v6 ())
+ {
+ if (!m_SocketV6.is_open ()) return;
m_SocketV6.send_to (bufs, to, 0, ec);
+ }
else
+ {
+ if (!m_SocketV4.is_open ()) return;
m_SocketV4.send_to (bufs, to, 0, ec);
+ }
+
if (!ec)
i2p::transport::transports.UpdateSentBytes (headerLen + payloadLen);
else
@@ -491,17 +614,30 @@
void SSU2Server::Send (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen,
const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to)
{
+ if (m_IsThroughProxy)
+ {
+ SendThroughProxy (header, headerLen, headerX, headerXLen, payload, payloadLen, to);
+ return;
+ }
+
std::vector<boost::asio::const_buffer> bufs
{
boost::asio::buffer (header, headerLen),
boost::asio::buffer (headerX, headerXLen),
boost::asio::buffer (payload, payloadLen)
};
+
boost::system::error_code ec;
if (to.address ().is_v6 ())
+ {
+ if (!m_SocketV6.is_open ()) return;
m_SocketV6.send_to (bufs, to, 0, ec);
+ }
else
+ {
+ if (!m_SocketV4.is_open ()) return;
m_SocketV4.send_to (bufs, to, 0, ec);
+ }
if (!ec)
i2p::transport::transports.UpdateSentBytes (headerLen + headerXLen + payloadLen);
@@ -523,41 +659,41 @@
{
auto session = it->second;
GetService ().post ([session]() { session->SendPeerTest (); });
- }
+ }
return false;
- }
+ }
// check is no pending session
bool isValidEndpoint = !address->host.is_unspecified () && address->port;
if (isValidEndpoint)
- {
+ {
if (i2p::util::net::IsInReservedRange(address->host)) return false;
auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (address->host, address->port));
if (s)
- {
+ {
if (peerTest)
{
// if peer test requested add it to the list for pending session
auto onEstablished = s->GetOnEstablished ();
if (onEstablished)
- s->SetOnEstablished ([s, onEstablished]()
- {
- onEstablished ();
- s->SendPeerTest ();
- });
- else
+ s->SetOnEstablished ([s, onEstablished]()
+ {
+ onEstablished ();
+ s->SendPeerTest ();
+ });
+ else
s->SetOnEstablished ([s]() { s->SendPeerTest (); });
- }
+ }
return false;
- }
- }
-
+ }
+ }
+
auto session = std::make_shared<SSU2Session> (*this, router, address);
if (peerTest)
session->SetOnEstablished ([session]() {session->SendPeerTest (); });
if (address->UsesIntroducer ())
GetService ().post (std::bind (&SSU2Server::ConnectThroughIntroducer, this, session));
- else if (isValidEndpoint) // we can't connect without endpoint
+ else if (isValidEndpoint) // we can't connect without endpoint
GetService ().post ([session]() { session->Connect (); });
else
return false;
@@ -576,7 +712,7 @@
// try to find existing session first
for (auto& it: address->ssu->introducers)
{
- auto it1 = m_SessionsByRouterHash.find (it.iKey);
+ auto it1 = m_SessionsByRouterHash.find (it.iH);
if (it1 != m_SessionsByRouterHash.end ())
{
it1->second->Introduce (session, it.iTag);
@@ -588,26 +724,26 @@
std::shared_ptr<i2p::data::RouterInfo> r;
uint32_t relayTag = 0;
if (!address->ssu->introducers.empty ())
- {
- std::vector<int> indicies;
- for (int i = 0; i < (int)address->ssu->introducers.size (); i++) indicies.push_back(i);
- if (indicies.size () > 1)
- std::shuffle (indicies.begin(), indicies.end(), std::mt19937(std::random_device()()));
+ {
+ std::vector<int> indices;
+ for (int i = 0; i < (int)address->ssu->introducers.size (); i++) indices.push_back(i);
+ if (indices.size () > 1)
+ std::shuffle (indices.begin(), indices.end(), std::mt19937(std::random_device()()));
- for (auto i: indicies)
+ for (auto i: indices)
{
- const auto& introducer = address->ssu->introducers[indicies[i]];
+ const auto& introducer = address->ssu->introducers[indices[i]];
if (introducer.iTag && ts < introducer.iExp)
- {
- r = i2p::data::netdb.FindRouter (introducer.iKey);
+ {
+ r = i2p::data::netdb.FindRouter (introducer.iH);
if (r && r->IsReachableFrom (i2p::context.GetRouterInfo ()))
{
relayTag = introducer.iTag;
if (relayTag) break;
}
- }
+ }
}
- }
+ }
if (r)
{
if (relayTag)
@@ -619,10 +755,10 @@
bool isValidEndpoint = !addr->host.is_unspecified () && addr->port &&
!i2p::util::net::IsInReservedRange(addr->host);
if (isValidEndpoint)
- {
+ {
auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (addr->host, addr->port));
if (!s)
- {
+ {
s = std::make_shared<SSU2Session> (*this, r, addr);
s->SetOnEstablished ([session, s, relayTag]() { s->Introduce (session, relayTag); });
s->Connect ();
@@ -636,10 +772,10 @@
onEstablished ();
s->Introduce (session, relayTag);
});
- else
+ else
s->SetOnEstablished ([session, s, relayTag]() {s->Introduce (session, relayTag); });
- }
- }
+ }
+ }
}
}
}
@@ -648,7 +784,7 @@
// introducers not found, try to request them
for (auto& it: address->ssu->introducers)
if (it.iTag && ts < it.iExp)
- i2p::data::netdb.RequestDestination (it.iKey);
+ i2p::data::netdb.RequestDestination (it.iH);
}
}
@@ -663,15 +799,15 @@
auto s = it->second;
if (it->second->IsEstablished ())
GetService ().post ([s]() { s->SendPeerTest (); });
- else
- s->SetOnEstablished ([s]() { s->SendPeerTest (); });
- return true;
+ else
+ s->SetOnEstablished ([s]() { s->SendPeerTest (); });
+ return true;
}
- else
+ else
CreateSession (router, addr, true);
return true;
- }
-
+ }
+
void SSU2Server::ScheduleTermination ()
{
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(SSU2_TERMINATION_CHECK_TIMEOUT));
@@ -689,6 +825,7 @@
if (it->second->IsTerminationTimeoutExpired (ts))
{
//it->second->Terminate ();
+ std::unique_lock<std::mutex> l(m_PendingOutgoingSessionsMutex);
it = m_PendingOutgoingSessions.erase (it);
}
else
@@ -717,16 +854,32 @@
it = m_SessionsByRouterHash.erase (it);
else
it++;
- }
+ }
+ ScheduleTermination ();
+ }
+ }
+
+ void SSU2Server::ScheduleCleanup ()
+ {
+ m_CleanupTimer.expires_from_now (boost::posix_time::seconds(SSU2_CLEANUP_INTERVAL));
+ m_CleanupTimer.async_wait (std::bind (&SSU2Server::HandleCleanupTimer,
+ this, std::placeholders::_1));
+ }
+
+ void SSU2Server::HandleCleanupTimer (const boost::system::error_code& ecode)
+ {
+ if (ecode != boost::asio::error::operation_aborted)
+ {
+ auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = m_Relays.begin (); it != m_Relays.begin ();)
{
if (it->second && it->second->GetState () == eSSU2SessionStateTerminated)
it = m_Relays.erase (it);
else
it++;
- }
-
+ }
+
for (auto it = m_IncomingTokens.begin (); it != m_IncomingTokens.end (); )
{
if (ts > it->second.second)
@@ -742,16 +895,19 @@
else
it++;
}
-
+
m_PacketsPool.CleanUpMt ();
m_SentPacketsPool.CleanUp ();
- ScheduleTermination ();
+ m_IncompleteMessagesPool.CleanUp ();
+ m_FragmentsPool.CleanUp ();
+ ScheduleCleanup ();
}
}
- void SSU2Server::ScheduleResend ()
+ void SSU2Server::ScheduleResend (bool more)
{
- m_ResendTimer.expires_from_now (boost::posix_time::milliseconds(SSU2_RESEND_CHECK_TIMEOUT));
+ m_ResendTimer.expires_from_now (boost::posix_time::milliseconds (more ? SSU2_RESEND_CHECK_MORE_TIMEOUT :
+ (SSU2_RESEND_CHECK_TIMEOUT + rand () % SSU2_RESEND_CHECK_TIMEOUT_VARIANCE)));
m_ResendTimer.async_wait (std::bind (&SSU2Server::HandleResendTimer,
this, std::placeholders::_1));
}
@@ -760,12 +916,16 @@
{
if (ecode != boost::asio::error::operation_aborted)
{
+ size_t resentPacketsNum = 0;
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it: m_Sessions)
- it.second->Resend (ts);
+ {
+ resentPacketsNum += it.second->Resend (ts);
+ if (resentPacketsNum > SSU2_MAX_RESEND_PACKETS) break;
+ }
for (auto it: m_PendingOutgoingSessions)
it.second->Resend (ts);
- ScheduleResend ();
+ ScheduleResend (resentPacketsNum > SSU2_MAX_RESEND_PACKETS);
}
}
@@ -774,26 +934,36 @@
m_OutgoingTokens[ep] = {token, exp};
}
- uint64_t SSU2Server::FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep) const
+ uint64_t SSU2Server::FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep)
{
auto it = m_OutgoingTokens.find (ep);
if (it != m_OutgoingTokens.end ())
{
if (i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_THRESHOLD > it->second.second)
- return 0; // token expired
+ {
+ // token expired
+ m_OutgoingTokens.erase (it);
+ return 0;
+ }
return it->second.first;
- }
+ }
return 0;
}
uint64_t SSU2Server::GetIncomingToken (const boost::asio::ip::udp::endpoint& ep)
{
+ auto ts = i2p::util::GetSecondsSinceEpoch ();
auto it = m_IncomingTokens.find (ep);
if (it != m_IncomingTokens.end ())
- return it->second.first;
+ {
+ if (ts + SSU2_TOKEN_EXPIRATION_THRESHOLD <= it->second.second)
+ return it->second.first;
+ else // token expired
+ m_IncomingTokens.erase (it);
+ }
uint64_t token;
RAND_bytes ((uint8_t *)&token, 8);
- m_IncomingTokens.emplace (ep, std::make_pair (token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT));
+ m_IncomingTokens.emplace (ep, std::make_pair (token, uint32_t(ts + SSU2_TOKEN_EXPIRATION_TIMEOUT)));
return token;
}
@@ -802,23 +972,23 @@
m_IncomingTokens.erase (ep); // drop previous
uint64_t token;
RAND_bytes ((uint8_t *)&token, 8);
- auto ret = std::make_pair (token, i2p::util::GetSecondsSinceEpoch () + SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT);
+ auto ret = std::make_pair (token, uint32_t(i2p::util::GetSecondsSinceEpoch () + SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT));
m_IncomingTokens.emplace (ep, ret);
return ret;
- }
+ }
- std::list<std::shared_ptr<SSU2Session> > SSU2Server::FindIntroducers (int maxNumIntroducers,
+ std::list<std::shared_ptr<SSU2Session> > SSU2Server::FindIntroducers (int maxNumIntroducers,
bool v4, const std::set<i2p::data::IdentHash>& excluded) const
{
std::list<std::shared_ptr<SSU2Session> > ret;
for (const auto& s : m_Sessions)
{
- if (s.second->IsEstablished () && (s.second->GetRelayTag () && s.second->IsOutgoing ()) &&
+ if (s.second->IsEstablished () && (s.second->GetRelayTag () && s.second->IsOutgoing ()) &&
!excluded.count (s.second->GetRemoteIdentity ()->GetIdentHash ()) &&
((v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V4)) ||
- (!v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V6))))
+ (!v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V6))))
ret.push_back (s.second);
- }
+ }
if ((int)ret.size () > maxNumIntroducers)
{
// shink ret randomly
@@ -832,35 +1002,42 @@
}
}
return ret;
- }
+ }
void SSU2Server::UpdateIntroducers (bool v4)
{
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
- std::list<i2p::data::IdentHash> newList;
+ std::list<i2p::data::IdentHash> newList, impliedList;
auto& introducers = v4 ? m_Introducers : m_IntroducersV6;
std::set<i2p::data::IdentHash> excluded;
for (const auto& it : introducers)
{
std::shared_ptr<SSU2Session> session;
auto it1 = m_SessionsByRouterHash.find (it);
- if (it1 != m_SessionsByRouterHash.end ())
- {
+ if (it1 != m_SessionsByRouterHash.end ())
+ {
session = it1->second;
excluded.insert (it);
- }
- if (session && session->IsEstablished ())
+ }
+ if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ()) // still session with introducer?
{
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION)
+ {
session->SendKeepAlive ();
- if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
- newList.push_back (it);
+ if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
+ newList.push_back (it);
+ else
+ {
+ impliedList.push_back (it); // keep in introducers list, but not publish
+ session = nullptr;
+ }
+ }
else
session = nullptr;
- }
+ }
if (!session)
- i2p::context.RemoveSSU2Introducer (it, v4);
- }
+ i2p::context.RemoveSSU2Introducer (it, v4);
+ }
if (newList.size () < SSU2_MAX_NUM_INTRODUCERS)
{
auto sessions = FindIntroducers (SSU2_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded);
@@ -868,41 +1045,43 @@
{
// bump creation time for previous introducers if no new sessions found
LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing");
+ impliedList.clear ();
for (auto& it : introducers)
- {
+ {
auto it1 = m_SessionsByRouterHash.find (it);
if (it1 != m_SessionsByRouterHash.end ())
{
auto session = it1->second;
- if (session->IsEstablished ())
- {
+ if (session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ())
+ {
session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION);
- if (std::find (newList.begin (), newList.end (), it) == newList.end ())
- {
- newList.push_back (it);
+ if (std::find (newList.begin (), newList.end (), it) == newList.end ())
sessions.push_back (session);
- }
- }
- }
- }
- }
-
+ }
+ }
+ }
+ }
+
for (const auto& it : sessions)
{
+ uint32_t tag = it->GetRelayTag ();
+ uint32_t exp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION;
+ if (!tag || ts + SSU2_TO_INTRODUCER_SESSION_DURATION/2 > exp)
+ continue; // don't pick too old session for introducer
i2p::data::RouterInfo::Introducer introducer;
- introducer.iTag = it->GetRelayTag ();
- introducer.iKey = it->GetRemoteIdentity ()->GetIdentHash ();
- introducer.iExp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION;
+ introducer.iTag = tag;
+ introducer.iH = it->GetRemoteIdentity ()->GetIdentHash ();
+ introducer.iExp = exp;
excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ());
if (i2p::context.AddSSU2Introducer (introducer, v4))
{
- LogPrint (eLogDebug, "SSU2: Introducer added ", it->GetRelayTag (), " at ",
+ LogPrint (eLogDebug, "SSU2: Introducer added ", it->GetRelayTag (), " at ",
i2p::data::GetIdentHashAbbreviation (it->GetRemoteIdentity ()->GetIdentHash ()));
newList.push_back (it->GetRemoteIdentity ()->GetIdentHash ());
if (newList.size () >= SSU2_MAX_NUM_INTRODUCERS) break;
- }
- }
- }
+ }
+ }
+ }
introducers = newList;
if (introducers.size () < SSU2_MAX_NUM_INTRODUCERS)
@@ -926,17 +1105,19 @@
}
}
}
+ introducers.splice (introducers.end (), impliedList); // insert non-published, but non-expired introducers back
}
void SSU2Server::ScheduleIntroducersUpdateTimer ()
{
if (m_IsPublished)
- {
- m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL));
+ {
+ m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(
+ SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE));
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
this, std::placeholders::_1, true));
- }
- }
+ }
+ }
void SSU2Server::RescheduleIntroducersUpdateTimer ()
{
@@ -945,21 +1126,23 @@
m_IntroducersUpdateTimer.cancel ();
i2p::context.ClearSSU2Introducers (true);
m_Introducers.clear ();
- m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2));
+ m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(
+ (SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE)/2));
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
this, std::placeholders::_1, true));
- }
+ }
}
void SSU2Server::ScheduleIntroducersUpdateTimerV6 ()
{
if (m_IsPublished)
- {
- m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL));
+ {
+ m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(
+ SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE));
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
this, std::placeholders::_1, false));
- }
- }
+ }
+ }
void SSU2Server::RescheduleIntroducersUpdateTimerV6 ()
{
@@ -968,12 +1151,13 @@
m_IntroducersUpdateTimerV6.cancel ();
i2p::context.ClearSSU2Introducers (false);
m_IntroducersV6.clear ();
- m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2));
+ m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(
+ (SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE)/2));
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
this, std::placeholders::_1, false));
- }
+ }
}
-
+
void SSU2Server::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4)
{
if (ecode != boost::asio::error::operation_aborted)
@@ -981,7 +1165,7 @@
// timeout expired
if (v4)
{
- if (i2p::context.GetStatus () == eRouterStatusTesting)
+ if (i2p::context.GetTesting ())
{
// we still don't know if we need introducers
ScheduleIntroducersUpdateTimer ();
@@ -997,14 +1181,14 @@
// we are firewalled
auto addr = i2p::context.GetRouterInfo ().GetSSU2V4Address ();
if (addr && addr->ssu && addr->ssu->introducers.empty ())
- i2p::context.SetUnreachableSSU2 (true, false); // v4
-
+ i2p::context.SetUnreachable (true, false); // v4
+
UpdateIntroducers (true);
ScheduleIntroducersUpdateTimer ();
}
else
{
- if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
+ if (i2p::context.GetTestingV6 ())
{
// we still don't know if we need introducers
ScheduleIntroducersUpdateTimerV6 ();
@@ -1020,12 +1204,275 @@
// we are firewalled
auto addr = i2p::context.GetRouterInfo ().GetSSU2V6Address ();
if (addr && addr->ssu && addr->ssu->introducers.empty ())
- i2p::context.SetUnreachableSSU2 (false, true); // v6
-
+ i2p::context.SetUnreachable (false, true); // v6
+
UpdateIntroducers (false);
ScheduleIntroducersUpdateTimerV6 ();
- }
+ }
}
- }
+ }
+
+ void SSU2Server::SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen,
+ const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to)
+ {
+ if (!m_ProxyRelayEndpoint) return;
+ size_t requestHeaderSize = 0;
+ memset (m_UDPRequestHeader, 0, 3);
+ if (to.address ().is_v6 ())
+ {
+ m_UDPRequestHeader[3] = SOCKS5_ATYP_IPV6;
+ memcpy (m_UDPRequestHeader + 4, to.address ().to_v6().to_bytes().data(), 16);
+ requestHeaderSize = SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE;
+ }
+ else
+ {
+ m_UDPRequestHeader[3] = SOCKS5_ATYP_IPV4;
+ memcpy (m_UDPRequestHeader + 4, to.address ().to_v4().to_bytes().data(), 4);
+ requestHeaderSize = SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE;
+ }
+ htobe16buf (m_UDPRequestHeader + requestHeaderSize - 2, to.port ());
+
+ std::vector<boost::asio::const_buffer> bufs;
+ bufs.push_back (boost::asio::buffer (m_UDPRequestHeader, requestHeaderSize));
+ bufs.push_back (boost::asio::buffer (header, headerLen));
+ if (headerX) bufs.push_back (boost::asio::buffer (headerX, headerXLen));
+ bufs.push_back (boost::asio::buffer (payload, payloadLen));
+
+ boost::system::error_code ec;
+ m_SocketV4.send_to (bufs, *m_ProxyRelayEndpoint, 0, ec); // TODO: implement ipv6 proxy
+ if (!ec)
+ i2p::transport::transports.UpdateSentBytes (headerLen + payloadLen);
+ else
+ LogPrint (eLogError, "SSU2: Send exception: ", ec.message (), " to ", to);
+ }
+
+ void SSU2Server::ProcessNextPacketFromProxy (uint8_t * buf, size_t len)
+ {
+ if (buf[2]) // FRAG
+ {
+ LogPrint (eLogWarning, "SSU2: Proxy packet fragmentation is not supported");
+ return;
+ }
+ size_t offset = 0;
+ boost::asio::ip::udp::endpoint ep;
+ switch (buf[3]) // ATYP
+ {
+ case SOCKS5_ATYP_IPV4:
+ {
+ offset = SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE;
+ if (offset > len) return;
+ boost::asio::ip::address_v4::bytes_type bytes;
+ memcpy (bytes.data (), buf + 4, 4);
+ uint16_t port = bufbe16toh (buf + 8);
+ ep = boost::asio::ip::udp::endpoint (boost::asio::ip::address_v4 (bytes), port);
+ break;
+ }
+ case SOCKS5_ATYP_IPV6:
+ {
+ offset = SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE;
+ if (offset > len) return;
+ boost::asio::ip::address_v6::bytes_type bytes;
+ memcpy (bytes.data (), buf + 4, 16);
+ uint16_t port = bufbe16toh (buf + 20);
+ ep = boost::asio::ip::udp::endpoint (boost::asio::ip::address_v6 (bytes), port);
+ break;
+ }
+ default:
+ {
+ LogPrint (eLogWarning, "SSU2: Unknown ATYP ", (int)buf[3], " from proxy relay");
+ return;
+ }
+ }
+ ProcessNextPacket (buf + offset, len - offset, ep);
+ }
+
+ void SSU2Server::ConnectToProxy ()
+ {
+ if (!m_ProxyEndpoint) return;
+ m_UDPAssociateSocket.reset (new boost::asio::ip::tcp::socket (m_ReceiveService.GetService ()));
+ m_UDPAssociateSocket->async_connect (*m_ProxyEndpoint,
+ [this] (const boost::system::error_code& ecode)
+ {
+ if (ecode)
+ {
+ LogPrint (eLogError, "SSU2: Can't connect to proxy ", *m_ProxyEndpoint, " ", ecode.message ());
+ m_UDPAssociateSocket.reset (nullptr);
+ ReconnectToProxy ();
+ }
+ else
+ HandshakeWithProxy ();
+ });
+ }
+
+ void SSU2Server::HandshakeWithProxy ()
+ {
+ if (!m_UDPAssociateSocket) return;
+ m_UDPRequestHeader[0] = SOCKS5_VER;
+ m_UDPRequestHeader[1] = 1; // 1 method
+ m_UDPRequestHeader[2] = 0; // no authentication
+ boost::asio::async_write (*m_UDPAssociateSocket, boost::asio::buffer (m_UDPRequestHeader, 3), boost::asio::transfer_all(),
+ [this] (const boost::system::error_code& ecode, std::size_t bytes_transferred)
+ {
+ (void) bytes_transferred;
+ if (ecode)
+ {
+ LogPrint(eLogError, "SSU2: Proxy write error ", ecode.message());
+ m_UDPAssociateSocket.reset (nullptr);
+ ReconnectToProxy ();
+ }
+ else
+ ReadHandshakeWithProxyReply ();
+ });
+ }
+
+ void SSU2Server::ReadHandshakeWithProxyReply ()
+ {
+ if (!m_UDPAssociateSocket) return;
+ boost::asio::async_read (*m_UDPAssociateSocket, boost::asio::buffer (m_UDPRequestHeader, 2), boost::asio::transfer_all(),
+ [this] (const boost::system::error_code& ecode, std::size_t bytes_transferred)
+ {
+ (void) bytes_transferred;
+ if (ecode)
+ {
+ LogPrint(eLogError, "SSU2: Proxy read error ", ecode.message());
+ m_UDPAssociateSocket.reset (nullptr);
+ ReconnectToProxy ();
+ }
+ else
+ {
+ if (m_UDPRequestHeader[0] == SOCKS5_VER && !m_UDPRequestHeader[1])
+ SendUDPAssociateRequest ();
+ else
+ {
+ LogPrint(eLogError, "SSU2: Invalid proxy reply");
+ m_UDPAssociateSocket.reset (nullptr);
+ }
+ }
+ });
+ }
+
+ void SSU2Server::SendUDPAssociateRequest ()
+ {
+ if (!m_UDPAssociateSocket) return;
+ m_UDPRequestHeader[0] = SOCKS5_VER;
+ m_UDPRequestHeader[1] = SOCKS5_CMD_UDP_ASSOCIATE;
+ m_UDPRequestHeader[2] = 0; // RSV
+ m_UDPRequestHeader[3] = SOCKS5_ATYP_IPV4; // TODO: implement ipv6 proxy
+ memset (m_UDPRequestHeader + 4, 0, 6); // address and port all zeros
+ boost::asio::async_write (*m_UDPAssociateSocket, boost::asio::buffer (m_UDPRequestHeader, SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE), boost::asio::transfer_all(),
+ [this] (const boost::system::error_code& ecode, std::size_t bytes_transferred)
+ {
+ (void) bytes_transferred;
+ if (ecode)
+ {
+ LogPrint(eLogError, "SSU2: Proxy write error ", ecode.message());
+ m_UDPAssociateSocket.reset (nullptr);
+ ReconnectToProxy ();
+ }
+ else
+ ReadUDPAssociateReply ();
+ });
+ }
+
+ void SSU2Server::ReadUDPAssociateReply ()
+ {
+ if (!m_UDPAssociateSocket) return;
+ boost::asio::async_read (*m_UDPAssociateSocket, boost::asio::buffer (m_UDPRequestHeader, SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE), boost::asio::transfer_all(),
+ [this] (const boost::system::error_code& ecode, std::size_t bytes_transferred)
+ {
+ (void) bytes_transferred;
+ if (ecode)
+ {
+ LogPrint(eLogError, "SSU2: Proxy read error ", ecode.message());
+ m_UDPAssociateSocket.reset (nullptr);
+ ReconnectToProxy ();
+ }
+ else
+ {
+ if (m_UDPRequestHeader[0] == SOCKS5_VER && !m_UDPRequestHeader[1])
+ {
+ if (m_UDPRequestHeader[3] == SOCKS5_ATYP_IPV4)
+ {
+ boost::asio::ip::address_v4::bytes_type bytes;
+ memcpy (bytes.data (), m_UDPRequestHeader + 4, 4);
+ uint16_t port = bufbe16toh (m_UDPRequestHeader + 8);
+ m_ProxyRelayEndpoint.reset (new boost::asio::ip::udp::endpoint (boost::asio::ip::address_v4 (bytes), port));
+ m_SocketV4.open (boost::asio::ip::udp::v4 ());
+ Receive (m_SocketV4);
+ ReadUDPAssociateSocket ();
+ }
+ else
+ {
+ LogPrint(eLogError, "SSU2: Proxy UDP associate unsupported ATYP ", (int)m_UDPRequestHeader[3]);
+ m_UDPAssociateSocket.reset (nullptr);
+ }
+ }
+ else
+ {
+ LogPrint(eLogError, "SSU2: Proxy UDP associate error ", (int)m_UDPRequestHeader[1]);
+ m_UDPAssociateSocket.reset (nullptr);
+ }
+ }
+ });
+ }
+
+ void SSU2Server::ReadUDPAssociateSocket ()
+ {
+ if (!m_UDPAssociateSocket) return;
+ m_UDPAssociateSocket->async_read_some (boost::asio::buffer (m_UDPRequestHeader, 1),
+ [this] (const boost::system::error_code& ecode, std::size_t bytes_transferred)
+ {
+ (void) bytes_transferred;
+ if (ecode)
+ {
+ LogPrint(eLogWarning, "SSU2: Proxy UDP Associate socket error ", ecode.message());
+ m_UDPAssociateSocket.reset (nullptr);
+ m_ProxyRelayEndpoint.reset (nullptr);
+ m_SocketV4.close ();
+ ConnectToProxy (); // try to reconnect immediately
+ }
+ else
+ ReadUDPAssociateSocket ();
+ });
+ }
+
+ void SSU2Server::ReconnectToProxy ()
+ {
+ LogPrint(eLogInfo, "SSU2: Reconnect to proxy after ", SSU2_PROXY_CONNECT_RETRY_TIMEOUT, " seconds");
+ if (m_ProxyConnectRetryTimer)
+ m_ProxyConnectRetryTimer->cancel ();
+ else
+ m_ProxyConnectRetryTimer.reset (new boost::asio::deadline_timer (m_ReceiveService.GetService ()));
+ m_ProxyConnectRetryTimer->expires_from_now (boost::posix_time::seconds (SSU2_PROXY_CONNECT_RETRY_TIMEOUT));
+ m_ProxyConnectRetryTimer->async_wait (
+ [this](const boost::system::error_code& ecode)
+ {
+ if (ecode != boost::asio::error::operation_aborted)
+ {
+ m_UDPAssociateSocket.reset (nullptr);
+ m_ProxyRelayEndpoint.reset (nullptr);
+ LogPrint(eLogInfo, "SSU2: Reconnecting to proxy");
+ ConnectToProxy ();
+ }
+ });
+ }
+
+ bool SSU2Server::SetProxy (const std::string& address, uint16_t port)
+ {
+ boost::system::error_code ecode;
+ auto addr = boost::asio::ip::address::from_string (address, ecode);
+ if (!ecode && !addr.is_unspecified () && port)
+ {
+ m_IsThroughProxy = true;
+ m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint (addr, port));
+ }
+ else
+ {
+ if (ecode)
+ LogPrint (eLogError, "SSU2: Invalid proxy address ", address, " ", ecode.message());
+ return false;
+ }
+ return true;
+ }
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/SSU2.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022, The PurpleI2P Project
+* Copyright (c) 2022-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -10,6 +10,7 @@
#define SSU2_H__
#include <unordered_map>
+#include <mutex>
#include "util.h"
#include "SSU2Session.h"
@@ -17,15 +18,21 @@
{
namespace transport
{
- const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // in seconds
- const int SSU2_RESEND_CHECK_TIMEOUT = 500; // in milliseconds
+ const int SSU2_TERMINATION_CHECK_TIMEOUT = 25; // in seconds
+ const int SSU2_CLEANUP_INTERVAL = 72; // in seconds
+ const int SSU2_RESEND_CHECK_TIMEOUT = 400; // in milliseconds
+ const int SSU2_RESEND_CHECK_TIMEOUT_VARIANCE = 100; // in milliseconds
+ const int SSU2_RESEND_CHECK_MORE_TIMEOUT = 10; // in milliseconds
+ const size_t SSU2_MAX_RESEND_PACKETS = 128; // packets to resend at the time
const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
const size_t SSU2_MAX_NUM_INTRODUCERS = 3;
const int SSU2_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes
- const int SSU2_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
-
+ const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds
+ const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds
+ const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds
+
class SSU2Server: private i2p::util::RunnableServiceWithWork
{
struct Packet
@@ -54,10 +61,13 @@
void Stop ();
boost::asio::io_service& GetService () { return GetIOService (); };
void SetLocalAddress (const boost::asio::ip::address& localAddress);
+ bool SetProxy (const std::string& address, uint16_t port);
+ bool UsesProxy () const { return m_IsThroughProxy; };
bool IsSupported (const boost::asio::ip::address& addr) const;
uint16_t GetPort (bool v4) const;
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
-
+ void AdjustTimeOffset (int64_t offset);
+
void AddSession (std::shared_ptr<SSU2Session> session);
void RemoveSession (uint64_t connID);
void AddSessionByRouterHash (std::shared_ptr<SSU2Session> session);
@@ -67,7 +77,7 @@
std::shared_ptr<SSU2Session> FindPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) const;
std::shared_ptr<SSU2Session> GetRandomSession (i2p::data::RouterInfo::CompatibleTransports remoteTransports,
const i2p::data::IdentHash& excluded) const;
-
+
void AddRelay (uint32_t tag, std::shared_ptr<SSU2Session> relay);
void RemoveRelay (uint32_t tag);
std::shared_ptr<SSU2Session> FindRelaySession (uint32_t tag);
@@ -80,17 +90,19 @@
bool CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
bool StartPeerTest (std::shared_ptr<const i2p::data::RouterInfo> router, bool v4);
-
+
void UpdateOutgoingToken (const boost::asio::ip::udp::endpoint& ep, uint64_t token, uint32_t exp);
- uint64_t FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep) const;
+ uint64_t FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep);
uint64_t GetIncomingToken (const boost::asio::ip::udp::endpoint& ep);
std::pair<uint64_t, uint32_t> NewIncomingToken (const boost::asio::ip::udp::endpoint& ep);
-
+
void RescheduleIntroducersUpdateTimer ();
void RescheduleIntroducersUpdateTimerV6 ();
i2p::util::MemoryPool<SSU2SentPacket>& GetSentPacketsPool () { return m_SentPacketsPool; };
-
+ i2p::util::MemoryPool<SSU2IncompleteMessage>& GetIncompleteMessagesPool () { return m_IncompleteMessagesPool; };
+ i2p::util::MemoryPool<SSU2IncompleteMessage::Fragment>& GetFragmentsPool () { return m_FragmentsPool; };
+
private:
boost::asio::ip::udp::socket& OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint);
@@ -104,17 +116,31 @@
void ScheduleTermination ();
void HandleTerminationTimer (const boost::system::error_code& ecode);
- void ScheduleResend ();
+ void ScheduleCleanup ();
+ void HandleCleanupTimer (const boost::system::error_code& ecode);
+
+ void ScheduleResend (bool more);
void HandleResendTimer (const boost::system::error_code& ecode);
void ConnectThroughIntroducer (std::shared_ptr<SSU2Session> session);
- std::list<std::shared_ptr<SSU2Session> > FindIntroducers (int maxNumIntroducers,
+ std::list<std::shared_ptr<SSU2Session> > FindIntroducers (int maxNumIntroducers,
bool v4, const std::set<i2p::data::IdentHash>& excluded) const;
void UpdateIntroducers (bool v4);
void ScheduleIntroducersUpdateTimer ();
void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4);
void ScheduleIntroducersUpdateTimerV6 ();
-
+
+ void SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen,
+ const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to);
+ void ProcessNextPacketFromProxy (uint8_t * buf, size_t len);
+ void ConnectToProxy ();
+ void ReconnectToProxy ();
+ void HandshakeWithProxy ();
+ void ReadHandshakeWithProxyReply ();
+ void SendUDPAssociateRequest ();
+ void ReadUDPAssociateReply ();
+ void ReadUDPAssociateSocket (); // handle if closed by peer
+
private:
ReceiveService m_ReceiveService;
@@ -123,17 +149,29 @@
std::unordered_map<uint64_t, std::shared_ptr<SSU2Session> > m_Sessions;
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<SSU2Session> > m_SessionsByRouterHash;
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSU2Session> > m_PendingOutgoingSessions;
+ mutable std::mutex m_PendingOutgoingSessionsMutex;
std::map<boost::asio::ip::udp::endpoint, std::pair<uint64_t, uint32_t> > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds)
std::map<uint32_t, std::shared_ptr<SSU2Session> > m_Relays; // we are introducer, relay tag -> session
std::list<i2p::data::IdentHash> m_Introducers, m_IntroducersV6; // introducers we are connected to
i2p::util::MemoryPoolMt<Packet> m_PacketsPool;
i2p::util::MemoryPool<SSU2SentPacket> m_SentPacketsPool;
- boost::asio::deadline_timer m_TerminationTimer, m_ResendTimer,
+ i2p::util::MemoryPool<SSU2IncompleteMessage> m_IncompleteMessagesPool;
+ i2p::util::MemoryPool<SSU2IncompleteMessage::Fragment> m_FragmentsPool;
+ boost::asio::deadline_timer m_TerminationTimer, m_CleanupTimer, m_ResendTimer,
m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6;
std::shared_ptr<SSU2Session> m_LastSession;
bool m_IsPublished; // if we maintain introducers
bool m_IsSyncClockFromPeers;
-
+ int64_t m_PendingTimeOffset; // during peer test
+
+ // proxy
+ bool m_IsThroughProxy;
+ uint8_t m_UDPRequestHeader[SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE];
+ std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
+ std::unique_ptr<boost::asio::ip::tcp::socket> m_UDPAssociateSocket;
+ std::unique_ptr<boost::asio::ip::udp::endpoint> m_ProxyRelayEndpoint;
+ std::unique_ptr<boost::asio::deadline_timer> m_ProxyConnectRetryTimer;
+
public:
// for HTTP/I2PControl
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/SSU2Session.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022, The PurpleI2P Project
+* Copyright (c) 2022-2024, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -23,7 +23,7 @@
if (msg->len + fragmentSize > msg->maxLen)
{
LogPrint (eLogInfo, "SSU2: I2NP message size ", msg->maxLen, " is not enough");
- auto newMsg = NewI2NPMessage ();
+ auto newMsg = NewI2NPMessage (msg->len + fragmentSize);
*newMsg = *msg;
msg = newMsg;
}
@@ -31,16 +31,61 @@
LogPrint (eLogError, "SSU2: I2NP buffer overflow ", msg->maxLen);
nextFragmentNum++;
}
-
-
+
+ bool SSU2IncompleteMessage::ConcatOutOfSequenceFragments ()
+ {
+ bool isLast = false;
+ while (outOfSequenceFragments)
+ {
+ if (outOfSequenceFragments->fragmentNum == nextFragmentNum)
+ {
+ AttachNextFragment (outOfSequenceFragments->buf, outOfSequenceFragments->len);
+ isLast = outOfSequenceFragments->isLast;
+ if (isLast)
+ outOfSequenceFragments = nullptr;
+ else
+ outOfSequenceFragments = outOfSequenceFragments->next;
+ }
+ else
+ break;
+ }
+ return isLast;
+ }
+
+ void SSU2IncompleteMessage::AddOutOfSequenceFragment (std::shared_ptr<SSU2IncompleteMessage::Fragment> fragment)
+ {
+ if (!fragment || !fragment->fragmentNum) return; // fragment 0 not allowed
+ if (fragment->fragmentNum < nextFragmentNum) return; // already processed
+ if (!outOfSequenceFragments)
+ outOfSequenceFragments = fragment;
+ else
+ {
+ auto frag = outOfSequenceFragments;
+ std::shared_ptr<Fragment> prev;
+ do
+ {
+ if (fragment->fragmentNum < frag->fragmentNum) break; // found
+ if (fragment->fragmentNum == frag->fragmentNum) return; // duplicate
+ prev = frag; frag = frag->next;
+ }
+ while (frag);
+ fragment->next = frag;
+ if (prev)
+ prev->next = fragment;
+ else
+ outOfSequenceFragments = fragment;
+ }
+ lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
+ }
+
SSU2Session::SSU2Session (SSU2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter,
std::shared_ptr<const i2p::data::RouterInfo::Address> addr):
TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT),
m_Server (server), m_Address (addr), m_RemoteTransports (0),
m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown),
- m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false),
- m_WindowSize (SSU2_MIN_WINDOW_SIZE), m_RTT (SSU2_RESEND_INTERVAL),
- m_RTO (SSU2_RESEND_INTERVAL*SSU2_kAPPA), m_RelayTag (0),
+ m_SendPacketNum (0), m_ReceivePacketNum (0), m_LastDatetimeSentPacketNum (0),
+ m_IsDataReceived (false), m_WindowSize (SSU2_MIN_WINDOW_SIZE),
+ m_RTT (SSU2_RESEND_INTERVAL), m_RTO (SSU2_RESEND_INTERVAL*SSU2_kAPPA), m_RelayTag (0),
m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose),
m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size
{
@@ -68,17 +113,19 @@
void SSU2Session::Connect ()
{
if (m_State == eSSU2SessionStateUnknown || m_State == eSSU2SessionStateTokenReceived)
- {
+ {
+ LogPrint(eLogDebug, "SSU2: Connecting to ", GetRemoteEndpoint (),
+ " (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ")");
ScheduleConnectTimer ();
auto token = m_Server.FindOutgoingToken (m_RemoteEndpoint);
if (token)
SendSessionRequest (token);
else
- {
- m_State = eSSU2SessionStateUnknown;
+ {
+ m_State = eSSU2SessionStateUnknown;
SendTokenRequest ();
- }
- }
+ }
+ }
}
void SSU2Session::ScheduleConnectTimer ()
@@ -94,16 +141,19 @@
if (!ecode)
{
// timeout expired
- LogPrint (eLogWarning, "SSU2: Session with ", m_RemoteEndpoint, " was not established after ", SSU2_CONNECT_TIMEOUT, " seconds");
+ if (m_State == eSSU2SessionStateIntroduced) // WaitForIntroducer
+ LogPrint (eLogWarning, "SSU2: Session was not introduced after ", SSU2_CONNECT_TIMEOUT, " seconds");
+ else
+ LogPrint (eLogWarning, "SSU2: Session with ", m_RemoteEndpoint, " was not established after ", SSU2_CONNECT_TIMEOUT, " seconds");
Terminate ();
}
}
-
+
bool SSU2Session::Introduce (std::shared_ptr<SSU2Session> session, uint32_t relayTag)
{
// we are Alice
if (!session || !relayTag) return false;
- // find local adddress to introduce
+ // find local address to introduce
auto localAddress = session->FindLocalAddress ();
if (!localAddress) return false;
// create nonce
@@ -155,48 +205,51 @@
// create new connID
uint64_t oldConnID = GetConnID ();
RAND_bytes ((uint8_t *)&m_DestConnID, 8);
- RAND_bytes ((uint8_t *)&m_SourceConnID, 8);
+ RAND_bytes ((uint8_t *)&m_SourceConnID, 8);
// connect
m_State = eSSU2SessionStateTokenReceived;
m_Server.AddPendingOutgoingSession (shared_from_this ());
m_Server.RemoveSession (oldConnID);
Connect ();
}
- }
-
+ }
+
void SSU2Session::SendPeerTest ()
{
// we are Alice
uint32_t nonce;
RAND_bytes ((uint8_t *)&nonce, 4);
- auto ts = i2p::util::GetSecondsSinceEpoch ();
+ auto ts = i2p::util::GetMillisecondsSinceEpoch ();
// session for message 5
auto session = std::make_shared<SSU2Session> (m_Server);
session->SetState (eSSU2SessionStatePeerTest);
- m_PeerTests.emplace (nonce, std::make_pair (session, ts));
+ m_PeerTests.emplace (nonce, std::make_pair (session, ts/1000));
session->m_SourceConnID = htobe64 (((uint64_t)nonce << 32) | nonce);
session->m_DestConnID = ~session->m_SourceConnID;
m_Server.AddSession (session);
// peer test block
- uint8_t payload[SSU2_MAX_PACKET_SIZE];
- size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, nonce);
- if (payloadSize > 0)
- {
- payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
- SendData (payload, payloadSize);
- }
- }
+ auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
+ packet->payloadSize = CreatePeerTestBlock (packet->payload, m_MaxPayloadSize, nonce);
+ if (packet->payloadSize > 0)
+ {
+ packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
+ uint32_t packetNum = SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED);
+ packet->sendTime = ts;
+ m_SentPackets.emplace (packetNum, packet);
+ LogPrint (eLogDebug, "SSU2: PeerTest msg=1 sent to ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()));
+ }
+ }
void SSU2Session::SendKeepAlive ()
{
if (IsEstablished ())
- {
+ {
uint8_t payload[20];
- size_t payloadSize = CreatePaddingBlock (payload, 20, 5);
+ size_t payloadSize = CreatePaddingBlock (payload, 20, 8);
SendData (payload, payloadSize);
- }
- }
-
+ }
+ }
+
void SSU2Session::Terminate ()
{
if (m_State != eSSU2SessionStateTerminated)
@@ -207,14 +260,27 @@
if (m_RelayTag)
m_Server.RemoveRelay (m_RelayTag);
m_SentHandshakePacket.reset (nullptr);
+ m_SessionConfirmedFragment.reset (nullptr);
+ m_PathChallenge.reset (nullptr);
m_SendQueue.clear ();
+ SetSendQueueSize (0);
m_SentPackets.clear ();
m_IncompleteMessages.clear ();
m_RelaySessions.clear ();
m_PeerTests.clear ();
+ m_ReceivedI2NPMsgIDs.clear ();
m_Server.RemoveSession (m_SourceConnID);
transports.PeerDisconnected (shared_from_this ());
- LogPrint (eLogDebug, "SSU2: Session terminated");
+ auto remoteIdentity = GetRemoteIdentity ();
+ if (remoteIdentity)
+ {
+ LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (),
+ " (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") terminated");
+ }
+ else
+ {
+ LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), " terminated");
+ }
}
}
@@ -226,8 +292,8 @@
SendTermination ();
}
m_State = eSSU2SessionStateClosing;
- }
-
+ }
+
void SSU2Session::Established ()
{
m_State = eSSU2SessionStateEstablished;
@@ -238,11 +304,13 @@
m_ConnectTimer.cancel ();
SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT);
transports.PeerConnected (shared_from_this ());
- if (m_OnEstablished)
- {
+ if (m_OnEstablished)
+ {
m_OnEstablished ();
m_OnEstablished = nullptr;
- }
+ }
+ LogPrint(eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (),
+ " (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") established");
}
void SSU2Session::Done ()
@@ -253,7 +321,7 @@
void SSU2Session::SendLocalRouterInfo (bool update)
{
if (update || !IsOutgoing ())
- {
+ {
auto s = shared_from_this ();
m_Server.GetService ().post ([s]()
{
@@ -265,14 +333,14 @@
if (payloadSize < s->m_MaxPayloadSize)
payloadSize += s->CreatePaddingBlock (payload + payloadSize, s->m_MaxPayloadSize - payloadSize);
s->SendData (payload, payloadSize);
- }
+ }
else
s->SendFragmentedMessage (CreateDatabaseStoreMsg ());
});
- }
+ }
+
+ }
- }
-
void SSU2Session::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
{
m_Server.GetService ().post (std::bind (&SSU2Session::PostI2NPMessages, shared_from_this (), msgs));
@@ -282,20 +350,21 @@
{
if (m_State == eSSU2SessionStateTerminated) return;
for (auto it: msgs)
- m_SendQueue.push_back (it);
+ m_SendQueue.push_back (std::move (it));
SendQueue ();
if (m_SendQueue.size () > 0) // windows is full
- {
+ {
if (m_SendQueue.size () <= SSU2_MAX_OUTGOING_QUEUE_SIZE)
Resend (i2p::util::GetMillisecondsSinceEpoch ());
- else
+ else
{
LogPrint (eLogWarning, "SSU2: Outgoing messages queue size to ",
GetIdentHashBase64(), " exceeds ", SSU2_MAX_OUTGOING_QUEUE_SIZE);
RequestTermination (eSSU2TerminationReasonTimeout);
}
- }
+ }
+ SetSendQueueSize (m_SendQueue.size ());
}
bool SSU2Session::SendQueue ()
@@ -310,6 +379,11 @@
while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize)
{
auto msg = m_SendQueue.front ();
+ if (!msg)
+ {
+ m_SendQueue.pop_front ();
+ continue;
+ }
size_t len = msg->GetNTCP2Length () + 3;
if (len > m_MaxPayloadSize) // message too long
{
@@ -330,12 +404,12 @@
newPacket->payloadSize = ackBlockSize;
// complete current packet
if (packet->payloadSize > ackBlockSize) // more than just ack block
- {
+ {
ackBlockSent = true;
// try to add padding
if (packet->payloadSize + 16 < m_MaxPayloadSize)
packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
- }
+ }
else
{
// reduce ack block
@@ -344,15 +418,15 @@
// keep Ack block and drop some ranges
ackBlockSent = true;
packet->payloadSize = m_MaxPayloadSize - len;
- if (packet->payloadSize & 0x01) packet->payloadSize--; // make it even
+ if (packet->payloadSize & 0x01) packet->payloadSize--; // make it even
htobe16buf (packet->payload + 1, packet->payloadSize - 3); // new block size
- }
+ }
else // drop Ack block completely
- packet->payloadSize = 0;
+ packet->payloadSize = 0;
// msg fits single packet
m_SendQueue.pop_front ();
packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, std::move (msg));
- }
+ }
// send right a way
uint32_t packetNum = SendData (packet->payload, packet->payloadSize);
packet->sendTime = ts;
@@ -362,10 +436,11 @@
};
if (packet->payloadSize > ackBlockSize)
{
+ // last
ackBlockSent = true;
if (packet->payloadSize + 16 < m_MaxPayloadSize)
packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
- uint32_t packetNum = SendData (packet->payload, packet->payloadSize);
+ uint32_t packetNum = SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED);
packet->sendTime = ts;
m_SentPackets.emplace (packetNum, packet);
}
@@ -376,6 +451,7 @@
bool SSU2Session::SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg)
{
+ if (!msg) return false;
size_t lastFragmentSize = (msg->GetNTCP2Length () + 3 - m_MaxPayloadSize) % (m_MaxPayloadSize - 8);
size_t extraSize = m_MaxPayloadSize - lastFragmentSize;
bool ackBlockSent = false;
@@ -384,7 +460,7 @@
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
if (extraSize >= 8)
- {
+ {
packet->payloadSize = CreateAckBlock (packet->payload, extraSize);
ackBlockSent = true;
if (packet->payloadSize + 12 < m_MaxPayloadSize)
@@ -393,10 +469,10 @@
packet->sendTime = ts;
m_SentPackets.emplace (packetNum, packet);
packet = m_Server.GetSentPacketsPool ().AcquireShared ();
- }
- else
+ }
+ else
extraSize -= packet->payloadSize;
- }
+ }
size_t offset = extraSize > 0 ? (rand () % extraSize) : 0;
if (offset + packet->payloadSize >= m_MaxPayloadSize) offset = 0;
auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - offset - packet->payloadSize, msg);
@@ -413,16 +489,21 @@
packet = m_Server.GetSentPacketsPool ().AcquireShared ();
packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, m_MaxPayloadSize - offset, msg, fragmentNum, msgID);
extraSize -= offset;
+ uint8_t flags = 0;
if (msg->offset >= msg->len && packet->payloadSize + 16 < m_MaxPayloadSize) // last fragment
+ {
packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
- uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize);
+ if (fragmentNum > 2) // 3 or more fragments
+ flags |= SSU2_FLAG_IMMEDIATE_ACK_REQUESTED;
+ }
+ uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize, flags);
packet->sendTime = ts;
m_SentPackets.emplace (followonPacketNum, packet);
}
return ackBlockSent;
}
- void SSU2Session::Resend (uint64_t ts)
+ size_t SSU2Session::Resend (uint64_t ts)
{
// resend handshake packet
if (m_SentHandshakePacket && ts >= m_SentHandshakePacket->sendTime + SSU2_HANDSHAKE_RESEND_INTERVAL)
@@ -430,10 +511,10 @@
LogPrint (eLogDebug, "SSU2: Resending ", (int)m_State);
ResendHandshakePacket ();
m_SentHandshakePacket->sendTime = ts;
- return;
- }
+ return 0;
+ }
// resend data packets
- if (m_SentPackets.empty ()) return;
+ if (m_SentPackets.empty ()) return 0;
std::map<uint32_t, std::shared_ptr<SSU2SentPacket> > resentPackets;
for (auto it = m_SentPackets.begin (); it != m_SentPackets.end (); )
if (ts >= it->second->sendTime + it->second->numResends*m_RTO)
@@ -443,9 +524,10 @@
LogPrint (eLogInfo, "SSU2: Packet was not Acked after ", it->second->numResends, " attempts. Terminate session");
m_SentPackets.clear ();
m_SendQueue.clear ();
+ SetSendQueueSize (0);
RequestTermination (eSSU2TerminationReasonTimeout);
- return;
- }
+ return resentPackets.size ();
+ }
else
{
uint32_t packetNum = SendData (it->second->payload, it->second->payloadSize);
@@ -466,22 +548,24 @@
#endif
m_WindowSize >>= 1; // /2
if (m_WindowSize < SSU2_MIN_WINDOW_SIZE) m_WindowSize = SSU2_MIN_WINDOW_SIZE;
+ return resentPackets.size ();
}
+ return 0;
}
void SSU2Session::ResendHandshakePacket ()
{
if (m_SentHandshakePacket)
- {
- m_Server.Send (m_SentHandshakePacket->header.buf, 16, m_SentHandshakePacket->headerX, 48,
+ {
+ m_Server.Send (m_SentHandshakePacket->header.buf, 16, m_SentHandshakePacket->headerX, 48,
m_SentHandshakePacket->payload, m_SentHandshakePacket->payloadSize, m_RemoteEndpoint);
if (m_SessionConfirmedFragment && m_State == eSSU2SessionStateSessionConfirmedSent)
// resend second fragment of SessionConfirmed
- m_Server.Send (m_SessionConfirmedFragment->header.buf, 16,
+ m_Server.Send (m_SessionConfirmedFragment->header.buf, 16,
m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint);
- }
- }
-
+ }
+ }
+
bool SSU2Session::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len)
{
// we are Bob
@@ -500,16 +584,21 @@
break;
case eSSU2PeerTest:
{
- // TODO: remove later
- const uint8_t nonce[12] = {0};
- uint64_t headerX[2];
- i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
+ // TODO: remove later
+ if (len < 32)
+ {
+ LogPrint (eLogWarning, "SSU2: PeerTest message too short ", len);
+ break;
+ }
+ const uint8_t nonce[12] = {0};
+ uint64_t headerX[2];
+ i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
LogPrint (eLogWarning, "SSU2: Unexpected PeerTest message SourceConnID=", connID, " DestConnID=", headerX[0]);
break;
- }
+ }
case eSSU2HolePunch:
LogPrint (eLogDebug, "SSU2: Late HolePunch for ", connID);
- break;
+ break;
default:
{
LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " from ", m_RemoteEndpoint, " of ", len, " bytes");
@@ -526,13 +615,13 @@
m_SentHandshakePacket.reset (new HandshakePacket);
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
m_SentHandshakePacket->sendTime = ts;
-
+
Header& header = m_SentHandshakePacket->header;
- uint8_t * headerX = m_SentHandshakePacket->headerX,
+ uint8_t * headerX = m_SentHandshakePacket->headerX,
* payload = m_SentHandshakePacket->payload;
// fill packet
header.h.connID = m_DestConnID; // dest id
- header.h.packetNum = 0;
+ RAND_bytes (header.buf + 8, 4); // random packet num
header.h.type = eSSU2SessionRequest;
header.h.flags[0] = 2; // ver
header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
@@ -543,7 +632,7 @@
// payload
payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4);
- htobe32buf (payload + 3, ts/1000);
+ htobe32buf (payload + 3, (ts + 500)/1000);
size_t payloadSize = 7;
if (GetRouterStatus () == eRouterStatusFirewalled && m_Address->IsIntroducer ())
{
@@ -551,7 +640,7 @@
payload[payloadSize] = eSSU2BlkRelayTagRequest;
memset (payload + payloadSize + 1, 0, 2); // size = 0
payloadSize += 3;
- }
+ }
payloadSize += CreatePaddingBlock (payload + payloadSize, 40 - payloadSize, 1);
// KDF for session request
m_NoiseState->MixHash ({ {header.buf, 16}, {headerX, 16} }); // h = SHA256(h || header)
@@ -560,7 +649,7 @@
m_EphemeralKeys->Agree (m_Address->s, sharedSecret);
m_NoiseState->MixKey (sharedSecret);
// encrypt
- const uint8_t nonce[12] = {0};
+ const uint8_t nonce[12] = {0}; // always 0
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
payloadSize += 16;
header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24));
@@ -570,20 +659,26 @@
m_SentHandshakePacket->payloadSize = payloadSize;
// send
if (m_State == eSSU2SessionStateTokenReceived || m_Server.AddPendingOutgoingSession (shared_from_this ()))
- {
+ {
m_State = eSSU2SessionStateSessionRequestSent;
+ m_HandshakeInterval = ts;
m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint);
- }
+ }
else
{
- LogPrint (eLogWarning, "SSU2: SessionRequest request to ", m_RemoteEndpoint, " already pending");
+ LogPrint (eLogWarning, "SSU2: SessionRequest request to ", m_RemoteEndpoint, " already pending");
Terminate ();
- }
+ }
}
void SSU2Session::ProcessSessionRequest (Header& header, uint8_t * buf, size_t len)
{
// we are Bob
+ if (len < 88)
+ {
+ LogPrint (eLogWarning, "SSU2: SessionRequest message too short ", len);
+ return;
+ }
const uint8_t nonce[12] = {0};
uint8_t headerX[48];
i2p::crypto::ChaCha20 (buf + 16, 48, i2p::context.GetSSU2IntroKey (), nonce, headerX);
@@ -616,8 +711,13 @@
m_State = eSSU2SessionStateSessionRequestReceived;
HandlePayload (decryptedPayload.data (), decryptedPayload.size ());
- m_Server.AddSession (shared_from_this ());
- SendSessionCreated (headerX + 16);
+ if (m_TerminationReason == eSSU2TerminationReasonNormalClose)
+ {
+ m_Server.AddSession (shared_from_this ());
+ SendSessionCreated (headerX + 16);
+ }
+ else
+ SendRetry ();
}
void SSU2Session::SendSessionCreated (const uint8_t * X)
@@ -627,15 +727,15 @@
m_SentHandshakePacket.reset (new HandshakePacket);
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
m_SentHandshakePacket->sendTime = ts;
-
+
uint8_t kh2[32];
i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessCreateHeader", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessCreateHeader", 32)
// fill packet
Header& header = m_SentHandshakePacket->header;
- uint8_t * headerX = m_SentHandshakePacket->headerX,
+ uint8_t * headerX = m_SentHandshakePacket->headerX,
* payload = m_SentHandshakePacket->payload;
header.h.connID = m_DestConnID; // dest id
- header.h.packetNum = 0;
+ RAND_bytes (header.buf + 8, 4); // random packet num
header.h.type = eSSU2SessionCreated;
header.h.flags[0] = 2; // ver
header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
@@ -647,7 +747,7 @@
size_t maxPayloadSize = m_MaxPayloadSize - 48;
payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4);
- htobe32buf (payload + 3, ts/1000);
+ htobe32buf (payload + 3, (ts + 500)/1000);
size_t payloadSize = 7;
payloadSize += CreateAddressBlock (payload + payloadSize, maxPayloadSize - payloadSize, m_RemoteEndpoint);
if (m_RelayTag)
@@ -659,15 +759,13 @@
}
auto token = m_Server.NewIncomingToken (m_RemoteEndpoint);
if (ts + SSU2_TOKEN_EXPIRATION_THRESHOLD > token.second) // not expired?
- {
+ {
payload[payloadSize] = eSSU2BlkNewToken;
htobe16buf (payload + payloadSize + 1, 12);
htobe32buf (payload + payloadSize + 3, token.second - SSU2_TOKEN_EXPIRATION_THRESHOLD); // expires
memcpy (payload + payloadSize + 7, &token.first, 8); // token
payloadSize += 15;
- }
- if (m_TerminationReason != eSSU2TerminationReasonNormalClose)
- payloadSize += CreateTerminationBlock (payload + payloadSize, maxPayloadSize - payloadSize);
+ }
payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize);
// KDF for SessionCreated
m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header)
@@ -676,7 +774,7 @@
m_EphemeralKeys->Agree (X, sharedSecret);
m_NoiseState->MixKey (sharedSecret);
// encrypt
- const uint8_t nonce[12] = {0};
+ const uint8_t nonce[12] = {0}; // always zero
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
payloadSize += 16;
m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted Noise payload from Session Created)
@@ -686,10 +784,8 @@
m_State = eSSU2SessionStateSessionCreatedSent;
m_SentHandshakePacket->payloadSize = payloadSize;
// send
+ m_HandshakeInterval = ts;
m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint);
- // terminate if errors
- if (m_TerminationReason != eSSU2TerminationReasonNormalClose)
- Terminate ();
}
bool SSU2Session::ProcessSessionCreated (uint8_t * buf, size_t len)
@@ -704,6 +800,12 @@
if (header.h.type != eSSU2SessionCreated)
// this situation is valid, because it might be Retry with different encryption
return false;
+ if (len < 80)
+ {
+ LogPrint (eLogWarning, "SSU2: SessionCreated message too short ", len);
+ return false;
+ }
+ m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
const uint8_t nonce[12] = {0};
uint8_t headerX[48];
i2p::crypto::ChaCha20 (buf + 16, 48, kh2, nonce, headerX);
@@ -720,6 +822,8 @@
m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false))
{
LogPrint (eLogWarning, "SSU2: SessionCreated AEAD verification failed ");
+ if (GetRemoteIdentity ())
+ i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); // assume wrong s key
return false;
}
m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || encrypted payload from SessionCreated) for SessionConfirmed
@@ -740,13 +844,13 @@
// we are Alice
m_SentHandshakePacket.reset (new HandshakePacket);
m_SentHandshakePacket->sendTime = i2p::util::GetMillisecondsSinceEpoch ();
-
+
uint8_t kh2[32];
i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessionConfirmed", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessionConfirmed", 32)
// fill packet
Header& header = m_SentHandshakePacket->header;
header.h.connID = m_DestConnID; // dest id
- header.h.packetNum = 0;
+ header.h.packetNum = 0; // always zero
header.h.type = eSSU2SessionConfirmed;
memset (header.h.flags, 0, 3);
header.h.flags[0] = 1; // frag, total fragments always 1
@@ -761,7 +865,7 @@
payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ());
header.h.flags[0] = 0x02; // frag 0, total fragments 2
// TODO: check if we need more fragments
- }
+ }
if (payloadSize < maxPayloadSize)
payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize);
// KDF for Session Confirmed part 1
@@ -769,7 +873,7 @@
// Encrypt part 1
uint8_t * part1 = m_SentHandshakePacket->headerX;
uint8_t nonce[12];
- CreateNonce (1, nonce);
+ CreateNonce (1, nonce); // always one
i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetSSU2StaticPublicKey (), 32, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, part1, 48, true);
m_NoiseState->MixHash (part1, 48); // h = SHA256(h || ciphertext);
// KDF for Session Confirmed part 2
@@ -777,7 +881,7 @@
i2p::context.GetSSU2StaticKeys ().Agree (Y, sharedSecret);
m_NoiseState->MixKey (sharedSecret);
// Encrypt part2
- memset (nonce, 0, 12);
+ memset (nonce, 0, 12); // always zero
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
payloadSize += 16;
m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || ciphertext);
@@ -789,10 +893,10 @@
payloadSize = m_MaxPayloadSize - 48 - (rand () % 16);
if (m_SentHandshakePacket->payloadSize - payloadSize < 24)
payloadSize -= 24;
- }
+ }
else
header.h.flags[0] = 1;
- }
+ }
// Encrypt header
header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12));
@@ -811,12 +915,12 @@
memset (header.h.flags, 0, 3);
header.h.flags[0] = 0x12; // frag 1, total fragments 2
m_SessionConfirmedFragment->payloadSize = m_SentHandshakePacket->payloadSize - payloadSize;
- memcpy (m_SessionConfirmedFragment->payload, m_SentHandshakePacket->payload + payloadSize, m_SessionConfirmedFragment->payloadSize);
+ memcpy (m_SessionConfirmedFragment->payload, m_SentHandshakePacket->payload + payloadSize, m_SessionConfirmedFragment->payloadSize);
m_SentHandshakePacket->payloadSize = payloadSize;
header.ll[0] ^= CreateHeaderMask (m_Address->i, m_SessionConfirmedFragment->payload + (m_SessionConfirmedFragment->payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (kh2, m_SessionConfirmedFragment->payload + (m_SessionConfirmedFragment->payloadSize - 12));
m_Server.Send (header.buf, 16, m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint);
- }
+ }
}
bool SSU2Session::ProcessSessionConfirmed (uint8_t * buf, size_t len)
@@ -834,21 +938,39 @@
// TODO: queue up
return true;
}
+ // packet num must be always zero
+ if (header.h.packetNum)
+ {
+ LogPrint (eLogError, "SSU2: Non zero packet number in SessionConfirmed");
+ return false;
+ }
// check if fragmented
- if ((header.h.flags[0] & 0x0F) > 1)
+ uint8_t numFragments = header.h.flags[0] & 0x0F;
+ if (numFragments > 1)
{
// fragmented
+ if (numFragments > 2)
+ {
+ LogPrint (eLogError, "SSU2: Too many fragments ", (int)numFragments, " in SessionConfirmed from ", m_RemoteEndpoint);
+ return false;
+ }
+ if (len < 32)
+ {
+ LogPrint (eLogWarning, "SSU2: SessionConfirmed fragment too short ", len);
+ if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr);
+ return false;
+ }
if (!(header.h.flags[0] & 0xF0))
{
// first fragment
if (!m_SessionConfirmedFragment)
- {
+ {
m_SessionConfirmedFragment.reset (new HandshakePacket);
m_SessionConfirmedFragment->header = header;
memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16);
m_SessionConfirmedFragment->payloadSize = len - 16;
return true; // wait for second fragment
- }
+ }
else if (m_SessionConfirmedFragment->isSecondFragment)
{
// we have second fragment
@@ -856,31 +978,42 @@
memmove (m_SessionConfirmedFragment->payload + (len - 16), m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize);
memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16);
m_SessionConfirmedFragment->payloadSize += (len - 16);
+ m_SessionConfirmedFragment->isSecondFragment = false;
buf = m_SessionConfirmedFragment->payload - 16;
len = m_SessionConfirmedFragment->payloadSize + 16;
- }
+ }
else
return true;
}
else
{
// second fragment
- if (!m_SessionConfirmedFragment)
- {
+ if (!m_SessionConfirmedFragment)
+ {
// out of sequence, save it
m_SessionConfirmedFragment.reset (new HandshakePacket);
memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16);
m_SessionConfirmedFragment->payloadSize = len - 16;
m_SessionConfirmedFragment->isSecondFragment = true;
- return true;
- }
+ return true;
+ }
header = m_SessionConfirmedFragment->header;
- memcpy (m_SessionConfirmedFragment->payload + m_SessionConfirmedFragment->payloadSize, buf + 16, len - 16);
- m_SessionConfirmedFragment->payloadSize += (len - 16);
+ if (m_SessionConfirmedFragment->payloadSize + (len - 16) <= SSU2_MAX_PACKET_SIZE*2)
+ {
+ memcpy (m_SessionConfirmedFragment->payload + m_SessionConfirmedFragment->payloadSize, buf + 16, len - 16);
+ m_SessionConfirmedFragment->payloadSize += (len - 16);
+ }
buf = m_SessionConfirmedFragment->payload - 16;
len = m_SessionConfirmedFragment->payloadSize + 16;
}
}
+ if (len < 80)
+ {
+ LogPrint (eLogWarning, "SSU2: SessionConfirmed message too short ", len);
+ if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr);
+ return false;
+ }
+ m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
// KDF for Session Confirmed part 1
m_NoiseState->MixHash (header.buf, 16); // h = SHA256(h || header)
// decrypt part1
@@ -891,6 +1024,7 @@
m_NoiseState->m_CK + 32, nonce, S, 32, false))
{
LogPrint (eLogWarning, "SSU2: SessionConfirmed part 1 AEAD verification failed ");
+ if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr);
return false;
}
m_NoiseState->MixHash (buf + 16, 48); // h = SHA256(h || ciphertext);
@@ -907,9 +1041,11 @@
m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false))
{
LogPrint (eLogWarning, "SSU2: SessionConfirmed part 2 AEAD verification failed ");
+ if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr);
return false;
}
m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || ciphertext);
+ if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr);
// payload
// handle RouterInfo block that must be first
if (decryptedPayload[0] != eSSU2BlkRouterInfo)
@@ -930,10 +1066,29 @@
LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block");
return false;
}
- m_Address = ri->GetSSU2AddressWithStaticKey (S, m_RemoteEndpoint.address ().is_v6 ());
- if (!m_Address)
+ auto ts = i2p::util::GetMillisecondsSinceEpoch();
+ if (ts > ri->GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
+ {
+ LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is too old for ", (ts - ri->GetTimestamp ())/1000LL, " seconds");
+ return false;
+ }
+ if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri->GetTimestamp ()) // 2 minutes
+ {
+ LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is from future for ", (ri->GetTimestamp () - ts)/1000LL, " seconds");
+ return false;
+ }
+ m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address ();
+ if (!m_Address || memcmp (S, m_Address->s, 32))
+ {
+ LogPrint (eLogError, "SSU2: Wrong static key in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
+ return false;
+ }
+ if (m_Address->published && m_RemoteEndpoint.address () != m_Address->host &&
+ (!m_RemoteEndpoint.address ().is_v6 () ||
+ memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), m_Address->host.to_v6 ().to_bytes ().data (), 8))) // temporary address
{
- LogPrint (eLogError, "SSU2: No SSU2 address with static key found in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
+ LogPrint (eLogError, "SSU2: Host mismatch between published address ", m_Address->host,
+ " and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
return false;
}
// update RouterInfo in netdb
@@ -942,7 +1097,7 @@
{
LogPrint (eLogError, "SSU2: Couldn't update RouterInfo from SessionConfirmed in netdb");
return false;
- }
+ }
SetRemoteIdentity (ri->GetRouterIdentity ());
AdjustMaxPayloadSize ();
m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now
@@ -984,7 +1139,7 @@
// payload
payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4);
- htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ());
+ htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
size_t payloadSize = 7;
payloadSize += CreatePaddingBlock (payload + payloadSize, 25 - payloadSize, 1);
// encrypt
@@ -997,13 +1152,13 @@
memset (nonce, 0, 12);
i2p::crypto::ChaCha20 (h + 16, 16, m_Address->i, nonce, h + 16);
// send
- if (m_Server.AddPendingOutgoingSession (shared_from_this ()))
+ if (m_Server.AddPendingOutgoingSession (shared_from_this ()))
m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint);
else
{
- LogPrint (eLogWarning, "SSU2: TokenRequest request to ", m_RemoteEndpoint, " already pending");
+ LogPrint (eLogWarning, "SSU2: TokenRequest request to ", m_RemoteEndpoint, " already pending");
Terminate ();
- }
+ }
}
void SSU2Session::ProcessTokenRequest (Header& header, uint8_t * buf, size_t len)
@@ -1013,7 +1168,7 @@
{
LogPrint (eLogWarning, "SSU2: Incorrect TokenRequest len ", len);
return;
- }
+ }
uint8_t nonce[12] = {0};
uint8_t h[32];
memcpy (h, header.buf, 16);
@@ -1029,6 +1184,7 @@
return;
}
// payload
+ m_State = eSSU2SessionStateTokenRequestReceived;
HandlePayload (payload, len - 48);
SendRetry ();
}
@@ -1037,7 +1193,7 @@
{
// we are Bob
Header header;
- uint8_t h[32], payload[64];
+ uint8_t h[32], payload[72];
// fill packet
header.h.connID = m_DestConnID; // dest id
RAND_bytes (header.buf + 8, 4); // random packet num
@@ -1047,15 +1203,19 @@
header.h.flags[2] = 0; // flag
memcpy (h, header.buf, 16);
memcpy (h + 16, &m_SourceConnID, 8); // source id
- uint64_t token = m_Server.GetIncomingToken (m_RemoteEndpoint);
+ uint64_t token = 0;
+ if (m_TerminationReason == eSSU2TerminationReasonNormalClose)
+ token = m_Server.GetIncomingToken (m_RemoteEndpoint);
memcpy (h + 24, &token, 8); // token
// payload
payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4);
- htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ());
+ htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
size_t payloadSize = 7;
- payloadSize += CreateAddressBlock (payload + payloadSize, 64 - payloadSize, m_RemoteEndpoint);
- payloadSize += CreatePaddingBlock (payload + payloadSize, 64 - payloadSize);
+ payloadSize += CreateAddressBlock (payload + payloadSize, 56 - payloadSize, m_RemoteEndpoint);
+ if (m_TerminationReason != eSSU2TerminationReasonNormalClose)
+ payloadSize += CreateTerminationBlock (payload + payloadSize, 56 - payloadSize);
+ payloadSize += CreatePaddingBlock (payload + payloadSize, 56 - payloadSize);
// encrypt
uint8_t nonce[12];
CreateNonce (be32toh (header.h.packetNum), nonce);
@@ -1081,10 +1241,17 @@
LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2Retry);
return false;
}
+ if (len < 48)
+ {
+ LogPrint (eLogWarning, "SSU2: Retry message too short ", len);
+ return false;
+ }
uint8_t nonce[12] = {0};
uint64_t headerX[2]; // sourceConnID, token
i2p::crypto::ChaCha20 (buf + 16, 16, m_Address->i, nonce, (uint8_t *)headerX);
- m_Server.UpdateOutgoingToken (m_RemoteEndpoint, headerX[1], i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT);
+ uint64_t token = headerX[1];
+ if (token)
+ m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT);
// decrypt and handle payload
uint8_t * payload = buf + 32;
CreateNonce (be32toh (header.h.packetNum), nonce);
@@ -1094,18 +1261,23 @@
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32,
m_Address->i, nonce, payload, len - 48, false))
{
- LogPrint (eLogWarning, "SSU2: Retry AEAD verification failed ");
+ LogPrint (eLogWarning, "SSU2: Retry AEAD verification failed");
return false;
}
- HandlePayload (payload, len - 48);
-
m_State = eSSU2SessionStateTokenReceived;
+ HandlePayload (payload, len - 48);
+ if (!token)
+ {
+ // we should handle payload even for zero token to handle Datetime block and adjust clock in case of clock skew
+ LogPrint (eLogWarning, "SSU2: Retry token is zero");
+ return false;
+ }
InitNoiseXKState1 (*m_NoiseState, m_Address->s); // reset Noise TODO: check state
- SendSessionRequest (headerX[1]);
+ SendSessionRequest (token);
return true;
}
- void SSU2Session::SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep,
+ void SSU2Session::SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep,
const uint8_t * introKey, uint64_t token)
{
// we are Charlie
@@ -1126,10 +1298,10 @@
// payload
payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4);
- htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ());
+ htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
size_t payloadSize = 7;
payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, ep);
- payloadSize += CreateRelayResponseBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize,
+ payloadSize += CreateRelayResponseBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize,
eSSU2RelayResponseCodeAccept, nonce, token, ep.address ().is_v4 ());
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
// encrypt
@@ -1158,6 +1330,11 @@
LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2HolePunch);
return false;
}
+ if (len < 48)
+ {
+ LogPrint (eLogWarning, "SSU2: HolePunch message too short ", len);
+ return false;
+ }
uint8_t nonce[12] = {0};
uint64_t headerX[2]; // sourceConnID, token
i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
@@ -1197,11 +1374,11 @@
// payload
payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4);
- htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ());
+ htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
size_t payloadSize = 7;
if (msg == 6 || msg == 7)
payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, m_RemoteEndpoint);
- payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize,
+ payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize,
msg, eSSU2PeerTestCodeAccept, nullptr, signedData, signedDataLen);
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
// encrypt
@@ -1215,8 +1392,8 @@
i2p::crypto::ChaCha20 (h + 16, 16, introKey, n, h + 16);
// send
m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint);
- }
-
+ }
+
bool SSU2Session::ProcessPeerTest (uint8_t * buf, size_t len)
{
// we are Alice or Charlie
@@ -1229,6 +1406,11 @@
LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2PeerTest);
return false;
}
+ if (len < 48)
+ {
+ LogPrint (eLogWarning, "SSU2: PeerTest message too short ", len);
+ return false;
+ }
uint8_t nonce[12] = {0};
uint64_t headerX[2]; // sourceConnID, token
i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
@@ -1249,7 +1431,7 @@
return true;
}
- uint32_t SSU2Session::SendData (const uint8_t * buf, size_t len)
+ uint32_t SSU2Session::SendData (const uint8_t * buf, size_t len, uint8_t flags)
{
if (len < 8)
{
@@ -1261,6 +1443,7 @@
header.h.packetNum = htobe32 (m_SendPacketNum);
header.h.type = eSSU2Data;
memset (header.h.flags, 0, 3);
+ if (flags) header.h.flags[0] = flags;
uint8_t nonce[12];
CreateNonce (m_SendPacketNum, nonce);
uint8_t payload[SSU2_MAX_PACKET_SIZE];
@@ -1269,12 +1452,11 @@
header.ll[1] ^= CreateHeaderMask (m_KeyDataSend + 32, payload + (len + 4));
m_Server.Send (header.buf, 16, payload, len + 16, m_RemoteEndpoint);
m_SendPacketNum++;
- m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
- m_NumSentBytes += len + 32;
+ UpdateNumSentBytes (len + 32);
return m_SendPacketNum - 1;
}
- void SSU2Session::ProcessData (uint8_t * buf, size_t len)
+ void SSU2Session::ProcessData (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from)
{
Header header;
header.ll[0] = m_SourceConnID;
@@ -1289,6 +1471,17 @@
ResendHandshakePacket (); // assume we receive
return;
}
+ if (from != m_RemoteEndpoint && !i2p::util::net::IsInReservedRange (from.address ()))
+ {
+ LogPrint (eLogInfo, "SSU2: Remote endpoint update ", m_RemoteEndpoint, "->", from);
+ m_RemoteEndpoint = from;
+ SendPathChallenge ();
+ }
+ if (len < 32)
+ {
+ LogPrint (eLogWarning, "SSU2: Data message too short ", len);
+ return;
+ }
uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = len - 32;
uint32_t packetNum = be32toh (header.h.packetNum);
@@ -1300,8 +1493,7 @@
LogPrint (eLogWarning, "SSU2: Data AEAD verification failed ");
return;
}
- m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
- m_NumReceivedBytes += len;
+ UpdateNumReceivedBytes (len);
if (!packetNum || UpdateReceivePacketNum (packetNum))
HandlePayload (payload, payloadSize);
}
@@ -1316,7 +1508,7 @@
auto size = bufbe16toh (buf + offset);
offset += 2;
LogPrint (eLogDebug, "SSU2: Block type ", (int)blk, " of size ", size);
- if (size > len)
+ if (offset + size > len)
{
LogPrint (eLogError, "SSU2: Unexpected block length ", size);
break;
@@ -1336,7 +1528,7 @@
LogPrint (eLogDebug, "SSU2: RouterInfo");
auto ri = ExtractRouterInfo (buf + offset, size);
if (ri)
- i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // TODO: add ri
+ i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // TODO: add ri
break;
}
case eSSU2BlkI2NPMessage:
@@ -1346,7 +1538,7 @@
nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header
memcpy (nextMsg->GetNTCP2Header (), buf + offset, size);
nextMsg->FromNTCP2 (); // SSU2 has the same format as NTCP2
- m_Handler.PutNextMessage (std::move (nextMsg));
+ HandleI2NPMsg (std::move (nextMsg));
m_IsDataReceived = true;
break;
}
@@ -1361,12 +1553,24 @@
m_IsDataReceived = true;
break;
case eSSU2BlkTermination:
- LogPrint (eLogDebug, "SSU2: Termination reason=", (int)buf[11]);
- if (IsEstablished () && buf[11] != eSSU2TerminationReasonTerminationReceived)
- RequestTermination (eSSU2TerminationReasonTerminationReceived);
- else
- Done ();
- break;
+ {
+ if (size >= 9)
+ {
+ uint8_t rsn = buf[offset + 8]; // reason
+ LogPrint (eLogDebug, "SSU2: Termination reason=", (int)rsn);
+ if (IsEstablished () && rsn != eSSU2TerminationReasonTerminationReceived)
+ RequestTermination (eSSU2TerminationReasonTerminationReceived);
+ else if (m_State != eSSU2SessionStateTerminated)
+ {
+ if (m_State == eSSU2SessionStateClosing && rsn == eSSU2TerminationReasonTerminationReceived)
+ m_State = eSSU2SessionStateClosingConfirmed;
+ Done ();
+ }
+ }
+ else
+ LogPrint(eLogWarning, "SSU2: Unexpected termination block size ", size);
+ break;
+ }
case eSSU2BlkRelayRequest:
LogPrint (eLogDebug, "SSU2: RelayRequest");
HandleRelayRequest (buf + offset, size);
@@ -1422,8 +1626,17 @@
SendPathResponse (buf + offset, size);
break;
case eSSU2BlkPathResponse:
+ {
LogPrint (eLogDebug, "SSU2: Path response");
- break;
+ if (m_PathChallenge)
+ {
+ i2p::data::IdentHash hash;
+ SHA256 (buf + offset, size, hash);
+ if (hash == *m_PathChallenge)
+ m_PathChallenge.reset (nullptr);
+ }
+ break;
+ }
case eSSU2BlkFirstPacketNumber:
break;
case eSSU2BlkPadding:
@@ -1442,39 +1655,44 @@
switch (m_State)
{
case eSSU2SessionStateSessionRequestReceived:
+ case eSSU2SessionStateTokenRequestReceived:
+ case eSSU2SessionStateEstablished:
if (std::abs (offset) > SSU2_CLOCK_SKEW)
m_TerminationReason = eSSU2TerminationReasonClockSkew;
break;
- case eSSU2SessionStateSessionCreatedReceived:
- if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetStatus () == eRouterStatusTesting) ||
- (m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusTesting))
+ case eSSU2SessionStateSessionCreatedReceived:
+ case eSSU2SessionStateTokenReceived:
+ if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetTesting ()) ||
+ (m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetTestingV6 ()))
{
if (m_Server.IsSyncClockFromPeers ())
{
if (std::abs (offset) > SSU2_CLOCK_THRESHOLD)
- {
- LogPrint (eLogWarning, "SSU2: Clock adjusted by ", -offset, " seconds");
- i2p::util::AdjustTimeOffset (-offset);
- }
+ {
+ LogPrint (eLogWarning, "SSU2: Time offset ", offset, " from ", m_RemoteEndpoint);
+ m_Server.AdjustTimeOffset (-offset);
+ }
+ else
+ m_Server.AdjustTimeOffset (0);
}
else if (std::abs (offset) > SSU2_CLOCK_SKEW)
{
LogPrint (eLogError, "SSU2: Clock skew detected ", offset, ". Check your clock");
i2p::context.SetError (eRouterErrorClockSkew);
}
- }
- break;
- default: ;
- };
- }
-
+ }
+ break;
+ default: ;
+ };
+ }
+
void SSU2Session::HandleAck (const uint8_t * buf, size_t len)
{
if (m_State == eSSU2SessionStateSessionConfirmedSent)
{
Established ();
return;
- }
+ }
if (m_SentPackets.empty ()) return;
if (len < 5) return;
// acnt
@@ -1484,7 +1702,7 @@
// ranges
len -= 5;
const uint8_t * ranges = buf + 5;
- while (len > 0 && firstPacketNum)
+ while (len > 0 && firstPacketNum && ackThrough - firstPacketNum < SSU2_MAX_NUM_ACK_PACKETS)
{
uint32_t lastPacketNum = firstPacketNum - 1;
if (*ranges > lastPacketNum) break;
@@ -1504,76 +1722,93 @@
if (it == m_SentPackets.end () || it->first > lastPacketNum) return; // not found
auto it1 = it;
int numPackets = 0;
- while (it1 != m_SentPackets.end () && it1->first <= lastPacketNum)
- {
+ while (it1 != m_SentPackets.end () && it1->first <= lastPacketNum)
+ {
if (ts && !it1->second->numResends)
{
if (ts > it1->second->sendTime)
{
auto rtt = ts - it1->second->sendTime;
- m_RTT = (m_RTT*m_SendPacketNum + rtt)/(m_SendPacketNum + 1);
+ m_RTT = std::round ((m_RTT*m_SendPacketNum + rtt)/(m_SendPacketNum + 1.0));
m_RTO = m_RTT*SSU2_kAPPA;
if (m_RTO < SSU2_MIN_RTO) m_RTO = SSU2_MIN_RTO;
if (m_RTO > SSU2_MAX_RTO) m_RTO = SSU2_MAX_RTO;
- }
+ }
ts = 0; // update RTT one time per range
- }
+ }
it1++;
numPackets++;
- }
+ }
m_SentPackets.erase (it, it1);
if (numPackets > 0)
{
m_WindowSize += numPackets;
if (m_WindowSize > SSU2_MAX_WINDOW_SIZE) m_WindowSize = SSU2_MAX_WINDOW_SIZE;
- }
+ }
}
void SSU2Session::HandleAddress (const uint8_t * buf, size_t len)
{
boost::asio::ip::udp::endpoint ep;
if (ExtractEndpoint (buf, len, ep))
- {
+ {
LogPrint (eLogInfo, "SSU2: Our external address is ", ep);
if (!i2p::util::net::IsInReservedRange (ep.address ()))
- {
+ {
i2p::context.UpdateAddress (ep.address ());
// check our port
bool isV4 = ep.address ().is_v4 ();
if (ep.port () != m_Server.GetPort (isV4))
{
+ LogPrint (eLogInfo, "SSU2: Our port ", ep.port (), " received from ", m_RemoteEndpoint, " is different from ", m_Server.GetPort (isV4));
if (isV4)
{
- if (i2p::context.GetStatus () == eRouterStatusTesting)
+ if (i2p::context.GetTesting ())
i2p::context.SetError (eRouterErrorSymmetricNAT);
- }
+ else if (m_State == eSSU2SessionStatePeerTest)
+ i2p::context.SetError (eRouterErrorFullConeNAT);
+ }
else
{
- if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
+ if (i2p::context.GetTestingV6 ())
i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT);
- }
- }
+ else if (m_State == eSSU2SessionStatePeerTest)
+ i2p::context.SetErrorV6 (eRouterErrorFullConeNAT);
+ }
+ }
else
{
if (isV4)
{
- if (i2p::context.GetStatus () == eRouterStatusError && i2p::context.GetError () == eRouterErrorSymmetricNAT)
- i2p::context.SetStatus (eRouterStatusTesting);
- }
+ if (i2p::context.GetError () == eRouterErrorSymmetricNAT)
+ {
+ if (m_State == eSSU2SessionStatePeerTest)
+ i2p::context.SetStatus (eRouterStatusOK);
+ i2p::context.SetError (eRouterErrorNone);
+ }
+ else if (i2p::context.GetError () == eRouterErrorFullConeNAT)
+ i2p::context.SetError (eRouterErrorNone);
+ }
else
{
- if (i2p::context.GetStatusV6 () == eRouterStatusError && i2p::context.GetErrorV6 () == eRouterErrorSymmetricNAT)
- i2p::context.SetStatusV6 (eRouterStatusTesting);
- }
- }
- }
- }
- }
-
+ if (i2p::context.GetErrorV6 () == eRouterErrorSymmetricNAT)
+ {
+ if (m_State == eSSU2SessionStatePeerTest)
+ i2p::context.SetStatusV6 (eRouterStatusOK);
+ i2p::context.SetErrorV6 (eRouterErrorNone);
+ }
+ else if (i2p::context.GetErrorV6 () == eRouterErrorFullConeNAT)
+ i2p::context.SetErrorV6 (eRouterErrorNone);
+ }
+ }
+ }
+ }
+ }
+
void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len)
{
+ auto msg = (buf[0] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPShortMessage ();
uint32_t msgID; memcpy (&msgID, buf + 1, 4);
- auto msg = NewI2NPShortMessage ();
// same format as I2NP message block
msg->len = msg->offset + len + 7;
memcpy (msg->GetNTCP2Header (), buf, len);
@@ -1587,17 +1822,17 @@
}
else
{
- m = std::make_shared<SSU2IncompleteMessage>();
+ m = m_Server.GetIncompleteMessagesPool ().AcquireShared ();
m_IncompleteMessages.emplace (msgID, m);
}
m->msg = msg;
m->nextFragmentNum = 1;
m->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
- if (found && ConcatOutOfSequenceFragments (m))
+ if (found && m->ConcatOutOfSequenceFragments ())
{
// we have all follow-on fragments already
m->msg->FromNTCP2 ();
- m_Handler.PutNextMessage (std::move (m->msg));
+ HandleI2NPMsg (std::move (m->msg));
m_IncompleteMessages.erase (it);
}
}
@@ -1606,12 +1841,18 @@
{
if (len < 5) return;
uint8_t fragmentNum = buf[0] >> 1;
+ if (!fragmentNum || fragmentNum >= SSU2_MAX_NUM_FRAGMENTS)
+ {
+ LogPrint (eLogWarning, "SSU2: Invalid follow-on fragment num ", fragmentNum);
+ return;
+ }
bool isLast = buf[0] & 0x01;
uint32_t msgID; memcpy (&msgID, buf + 1, 4);
auto it = m_IncompleteMessages.find (msgID);
if (it != m_IncompleteMessages.end ())
{
- if (it->second->nextFragmentNum == fragmentNum && fragmentNum < SSU2_MAX_NUM_FRAGMENTS &&
+ if (fragmentNum < it->second->nextFragmentNum) return; // duplicate
+ if (it->second->nextFragmentNum == fragmentNum && fragmentNum < SSU2_MAX_NUM_FRAGMENTS &&
it->second->msg)
{
// in sequence
@@ -1619,14 +1860,14 @@
if (isLast)
{
it->second->msg->FromNTCP2 ();
- m_Handler.PutNextMessage (std::move (it->second->msg));
+ HandleI2NPMsg (std::move (it->second->msg));
m_IncompleteMessages.erase (it);
}
else
{
- if (ConcatOutOfSequenceFragments (it->second))
+ if (it->second->ConcatOutOfSequenceFragments ())
{
- m_Handler.PutNextMessage (std::move (it->second->msg));
+ HandleI2NPMsg (std::move (it->second->msg));
m_IncompleteMessages.erase (it);
}
else
@@ -1638,38 +1879,17 @@
else
{
// follow-on fragment before first fragment
- auto msg = std::make_shared<SSU2IncompleteMessage> ();
+ auto msg = m_Server.GetIncompleteMessagesPool ().AcquireShared ();
msg->nextFragmentNum = 0;
it = m_IncompleteMessages.emplace (msgID, msg).first;
}
// insert out of sequence fragment
- if (fragmentNum >= SSU2_MAX_NUM_FRAGMENTS)
- {
- LogPrint (eLogWarning, "SSU2: Fragment number ", fragmentNum, " exceeds ", SSU2_MAX_NUM_FRAGMENTS);
- return;
- }
- auto fragment = std::make_shared<SSU2IncompleteMessage::Fragment> ();
+ auto fragment = m_Server.GetFragmentsPool ().AcquireShared ();
memcpy (fragment->buf, buf + 5, len -5);
fragment->len = len - 5;
+ fragment->fragmentNum = fragmentNum;
fragment->isLast = isLast;
- it->second->outOfSequenceFragments.emplace (fragmentNum, fragment);
- it->second->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
- }
-
- bool SSU2Session::ConcatOutOfSequenceFragments (std::shared_ptr<SSU2IncompleteMessage> m)
- {
- if (!m) return false;
- bool isLast = false;
- for (auto it = m->outOfSequenceFragments.begin (); it != m->outOfSequenceFragments.end ();)
- if (it->first == m->nextFragmentNum)
- {
- m->AttachNextFragment (it->second->buf, it->second->len);
- isLast = it->second->isLast;
- it = m->outOfSequenceFragments.erase (it);
- }
- else
- break;
- return isLast;
+ it->second->AddOutOfSequenceFragment (fragment);
}
void SSU2Session::HandleRelayRequest (const uint8_t * buf, size_t len)
@@ -1682,21 +1902,20 @@
LogPrint (eLogWarning, "SSU2: RelayRequest session with relay tag ", relayTag, " not found");
// send relay response back to Alice
uint8_t payload[SSU2_MAX_PACKET_SIZE];
- size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize,
+ size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize,
eSSU2RelayResponseCodeBobRelayTagNotFound, bufbe32toh (buf + 1), 0, false);
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
SendData (payload, payloadSize);
- return;
+ return;
}
session->m_RelaySessions.emplace (bufbe32toh (buf + 1), // nonce
std::make_pair (shared_from_this (), i2p::util::GetSecondsSinceEpoch ()) );
// send relay intro to Charlie
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); // Alice's RI
- if (r)
- i2p::data::netdb.PopulateRouterInfoBuffer (r);
- else
- LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found");
+ if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr;
+ if (!r) LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found");
+
uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0;
if (!payloadSize && r)
@@ -1707,7 +1926,7 @@
session->SendData (payload, payloadSize);
}
- void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len)
+ void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len, int attempts)
{
// we are Charlie
SSU2RelayResponseCode code = eSSU2RelayResponseCodeAccept;
@@ -1715,7 +1934,7 @@
bool isV4 = false;
auto r = i2p::data::netdb.FindRouter (buf + 1); // Alice
if (r)
- {
+ {
SignedData s;
s.Insert ((const uint8_t *)"RelayRequestData", 16); // prologue
s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
@@ -1737,49 +1956,62 @@
token = m_Server.GetIncomingToken (ep);
isV4 = ep.address ().is_v4 ();
SendHolePunch (bufbe32toh (buf + 33), ep, addr->i, token);
- }
+ }
else
- {
+ {
LogPrint (eLogWarning, "SSU2: RelayIntro unsupported address");
code = eSSU2RelayResponseCodeCharlieUnsupportedAddress;
- }
- }
+ }
+ }
else
{
LogPrint (eLogWarning, "SSU2: RelayIntro unknown address");
- code = eSSU2RelayResponseCodeCharlieAliceIsUnknown;
- }
+ code = eSSU2RelayResponseCodeCharlieAliceIsUnknown;
+ }
}
else
{
LogPrint (eLogWarning, "SSU2: RelayIntro can't extract endpoint");
- code = eSSU2RelayResponseCodeCharlieAliceIsUnknown;
- }
+ code = eSSU2RelayResponseCodeCharlieAliceIsUnknown;
+ }
}
else
{
LogPrint (eLogWarning, "SSU2: RelayIntro signature verification failed");
code = eSSU2RelayResponseCodeCharlieSignatureFailure;
}
- }
+ }
+ else if (!attempts)
+ {
+ // RouterInfo might come in the next packet, try again
+ auto vec = std::make_shared<std::vector<uint8_t> >(len);
+ memcpy (vec->data (), buf, len);
+ auto s = shared_from_this ();
+ m_Server.GetService ().post ([s, vec, attempts]()
+ {
+ LogPrint (eLogDebug, "SSU2: RelayIntro attempt ", attempts + 1);
+ s->HandleRelayIntro (vec->data (), vec->size (), attempts + 1);
+ });
+ return;
+ }
else
{
- LogPrint (eLogError, "SSU2: RelayIntro unknown router to introduce");
+ LogPrint (eLogWarning, "SSU2: RelayIntro unknown router to introduce");
code = eSSU2RelayResponseCodeCharlieAliceIsUnknown;
- }
+ }
// send relay response to Bob
uint8_t payload[SSU2_MAX_PACKET_SIZE];
- size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize,
+ size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize,
code, bufbe32toh (buf + 33), token, isV4);
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
SendData (payload, payloadSize);
}
void SSU2Session::HandleRelayResponse (const uint8_t * buf, size_t len)
- {
+ {
uint32_t nonce = bufbe32toh (buf + 2);
- if (m_State == eSSU2SessionStateIntroduced)
- {
+ if (m_State == eSSU2SessionStateIntroduced)
+ {
// HolePunch from Charlie
// TODO: verify address and signature
// verify nonce
@@ -1788,17 +2020,17 @@
if (len >= 8)
{
// new token
- uint64_t token;
+ uint64_t token;
memcpy (&token, buf + len - 8, 8);
m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT);
- }
- return;
- }
- auto it = m_RelaySessions.find (nonce);
+ }
+ return;
+ }
+ auto it = m_RelaySessions.find (nonce);
if (it != m_RelaySessions.end ())
{
if (it->second.first && it->second.first->IsEstablished ())
- {
+ {
// we are Bob, message from Charlie
uint8_t payload[SSU2_MAX_PACKET_SIZE];
payload[0] = eSSU2BlkRelayResponse;
@@ -1806,8 +2038,8 @@
memcpy (payload + 3, buf, len); // forward to Alice as is
size_t payloadSize = len + 3;
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
- it->second.first->SendData (payload, payloadSize);
- }
+ it->second.first->SendData (payload, payloadSize);
+ }
else
{
// we are Alice, message from Bob
@@ -1822,12 +2054,12 @@
if (s.Verify (it->second.first->GetRemoteIdentity (), buf + 12 + csz))
{
if (it->second.first->m_State == eSSU2SessionStateIntroduced) // HolePunch not received yet
- {
+ {
// update Charlie's endpoint
if (ExtractEndpoint (buf + 12, csz, it->second.first->m_RemoteEndpoint))
- {
+ {
// update token
- uint64_t token;
+ uint64_t token;
memcpy (&token, buf + len - 8, 8);
m_Server.UpdateOutgoingToken (it->second.first->m_RemoteEndpoint,
token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT);
@@ -1836,19 +2068,19 @@
}
else
LogPrint (eLogWarning, "SSU2: RelayResponse can't extract endpoint");
- }
+ }
}
else
- {
+ {
LogPrint (eLogWarning, "SSU2: RelayResponse signature verification failed");
it->second.first->Done ();
- }
+ }
}
else
- {
+ {
LogPrint (eLogInfo, "SSU2: RelayResponse status code=", (int)buf[1]);
it->second.first->Done ();
- }
+ }
}
m_RelaySessions.erase (it);
}
@@ -1861,46 +2093,51 @@
if (len < 3) return;
uint8_t msg = buf[0];
size_t offset = 3; // points to signed data
- if (msg == 2 || msg == 4) offset += 32; // hash is presented for msg 2 and 4 only
- if (len < offset + 5) return;
- uint32_t nonce = bufbe32toh (buf + offset + 1);
+ if (msg == 2 || msg == 4) offset += 32; // hash is presented for msg 2 and 4 only
+ if (len < offset + 5) return;
+ auto ts = i2p::util::GetMillisecondsSinceEpoch ();
+ uint32_t nonce = bufbe32toh (buf + offset + 1);
switch (msg) // msg
{
case 1: // Bob from Alice
- {
+ {
auto session = m_Server.GetRandomSession ((buf[12] == 6) ? i2p::data::RouterInfo::eSSU2V4 : i2p::data::RouterInfo::eSSU2V6,
GetRemoteIdentity ()->GetIdentHash ());
if (session) // session with Charlie
{
session->m_PeerTests.emplace (nonce, std::make_pair (shared_from_this (), i2p::util::GetSecondsSinceEpoch ()));
- uint8_t payload[SSU2_MAX_PACKET_SIZE];
+ auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
// Alice's RouterInfo
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ());
- if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r);
- size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0;
- if (!payloadSize && r)
+ if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr;
+ packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0;
+ if (!packet->payloadSize && r)
session->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
- if (payloadSize + len + 48 > m_MaxPayloadSize)
+ if (packet->payloadSize + len + 48 > m_MaxPayloadSize)
{
// doesn't fit one message, send RouterInfo in separate message
- session->SendData (payload, payloadSize);
- payloadSize = 0;
- }
+ uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED);
+ packet->sendTime = ts;
+ session->m_SentPackets.emplace (packetNum, packet);
+ packet = m_Server.GetSentPacketsPool ().AcquireShared (); // new packet
+ }
// PeerTest to Charlie
- payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, 2,
+ packet->payloadSize += CreatePeerTestBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, 2,
eSSU2PeerTestCodeAccept, GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset);
- payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
- session->SendData (payload, payloadSize);
+ packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
+ uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED);
+ packet->sendTime = ts;
+ session->m_SentPackets.emplace (packetNum, packet);
}
else
{
// Charlie not found, send error back to Alice
uint8_t payload[SSU2_MAX_PACKET_SIZE], zeroHash[32] = {0};
- size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 4,
+ size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 4,
eSSU2PeerTestCodeBobNoCharlieAvailable, zeroHash, buf + offset, len - offset);
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
SendData (payload, payloadSize);
- }
+ }
break;
}
case 2: // Charlie from Bob
@@ -1913,7 +2150,7 @@
s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue
s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
s.Insert (buf + 3, 32); // ahash
- s.Insert (newSignedData.data (), asz + 10); // ver, nonce, ts, asz, Alice's endpoint
+ s.Insert (newSignedData.data (), asz + 10); // ver, nonce, ts, asz, Alice's endpoint
s.Sign (i2p::context.GetPrivateKeys (), newSignedData.data () + 10 + asz);
// send response (msg 3) back and msg 5 if accepted
SSU2PeerTestCode code = eSSU2PeerTestCodeAccept;
@@ -1922,39 +2159,39 @@
{
size_t signatureLen = r->GetIdentity ()->GetSignatureLen ();
if (len >= offset + asz + 10 + signatureLen)
- {
+ {
s.Reset ();
s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue
s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
s.Insert (buf + offset, asz + 10); // signed data
if (s.Verify (r->GetIdentity (), buf + offset + asz + 10))
- {
+ {
if (!m_Server.FindSession (r->GetIdentity ()->GetIdentHash ()))
- {
+ {
boost::asio::ip::udp::endpoint ep;
std::shared_ptr<const i2p::data::RouterInfo::Address> addr;
if (ExtractEndpoint (buf + offset + 10, asz, ep))
addr = r->GetSSU2Address (ep.address ().is_v4 ());
if (addr && m_Server.IsSupported (ep.address ()))
- {
+ {
// send msg 5 to Alice
auto session = std::make_shared<SSU2Session> (m_Server, r, addr);
- session->SetState (eSSU2SessionStatePeerTest);
+ session->SetState (eSSU2SessionStatePeerTest);
session->m_RemoteEndpoint = ep; // might be different
session->m_DestConnID = htobe64 (((uint64_t)nonce << 32) | nonce);
session->m_SourceConnID = ~session->m_DestConnID;
m_Server.AddSession (session);
session->SendPeerTest (5, newSignedData.data (), newSignedData.size (), addr->i);
- }
+ }
else
code = eSSU2PeerTestCodeCharlieUnsupportedAddress;
}
else
code = eSSU2PeerTestCodeCharlieAliceIsAlreadyConnected;
}
- else
- code = eSSU2PeerTestCodeCharlieSignatureFailure;
- }
+ else
+ code = eSSU2PeerTestCodeCharlieSignatureFailure;
+ }
else // maformed message
code = eSSU2PeerTestCodeCharlieReasonUnspecified;
}
@@ -1962,12 +2199,12 @@
code = eSSU2PeerTestCodeCharlieAliceIsUnknown;
// send msg 3 back to Bob
uint8_t payload[SSU2_MAX_PACKET_SIZE];
- size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 3,
+ size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 3,
code, nullptr, newSignedData.data (), newSignedData.size ());
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
SendData (payload, payloadSize);
break;
- }
+ }
case 3: // Bob from Charlie
{
auto it = m_PeerTests.find (nonce);
@@ -1976,7 +2213,7 @@
uint8_t payload[SSU2_MAX_PACKET_SIZE];
// Charlie's RouterInfo
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ());
- if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r);
+ if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr;
size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0;
if (!payloadSize && r)
it->second.first->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
@@ -1987,7 +2224,7 @@
payloadSize = 0;
}
// PeerTest to Alice
- payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize, 4,
+ payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize, 4,
(SSU2PeerTestCode)buf[1], GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset);
if (payloadSize < m_MaxPayloadSize)
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
@@ -1999,88 +2236,100 @@
break;
}
case 4: // Alice from Bob
- {
+ {
auto it = m_PeerTests.find (nonce);
if (it != m_PeerTests.end ())
{
if (buf[1] == eSSU2PeerTestCodeAccept)
- {
+ {
if (GetRouterStatus () == eRouterStatusUnknown)
- SetRouterStatus (eRouterStatusTesting);
+ SetTestingState (true);
auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie
if (r && it->second.first)
- {
+ {
uint8_t asz = buf[offset + 9];
SignedData s;
s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue
s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
s.Insert (i2p::context.GetIdentity ()->GetIdentHash (), 32); // ahash
- s.Insert (buf + offset, asz + 10); // ver, nonce, ts, asz, Alice's endpoint
+ s.Insert (buf + offset, asz + 10); // ver, nonce, ts, asz, Alice's endpoint
if (s.Verify (r->GetIdentity (), buf + offset + asz + 10))
{
it->second.first->SetRemoteIdentity (r->GetIdentity ());
auto addr = r->GetSSU2Address (m_Address->IsV4 ());
if (addr)
- {
+ {
it->second.first->m_Address = addr;
if (it->second.first->m_State == eSSU2SessionStatePeerTestReceived)
{
- // msg 5 already received. send msg 6
+ // msg 5 already received. send msg 6
SetRouterStatus (eRouterStatusOK);
it->second.first->m_State = eSSU2SessionStatePeerTest;
it->second.first->SendPeerTest (6, buf + offset, len - offset, addr->i);
}
else
{
- if (GetRouterStatus () == eRouterStatusTesting)
- {
- SetRouterStatus (eRouterStatusFirewalled);
- if (m_Address->IsV4 ())
- m_Server.RescheduleIntroducersUpdateTimer ();
- else
- m_Server.RescheduleIntroducersUpdateTimerV6 ();
- }
- }
+ if (GetTestingState ())
+ {
+ SetTestingState (false);
+ if (GetRouterStatus () != eRouterStatusFirewalled)
+ {
+ SetRouterStatus (eRouterStatusFirewalled);
+ if (m_Address->IsV4 ())
+ m_Server.RescheduleIntroducersUpdateTimer ();
+ else
+ m_Server.RescheduleIntroducersUpdateTimerV6 ();
+ }
+ }
+ }
+ LogPrint (eLogDebug, "SSU2: Peer test 4 received from ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()),
+ " with information about ", i2p::data::GetIdentHashAbbreviation (i2p::data::IdentHash (buf + 3)));
}
else
{
LogPrint (eLogWarning, "SSU2: Peer test 4 address not found");
it->second.first->Done ();
- }
+ }
}
else
- {
+ {
LogPrint (eLogWarning, "SSU2: Peer test 4 signature verification failed");
it->second.first->Done ();
- }
- }
+ }
+ }
+ else
+ {
+ LogPrint (eLogWarning, "SSU2: Peer test 4 router not found");
+ if (it->second.first)
+ it->second.first->Done ();
+ }
}
else
{
LogPrint (eLogInfo, "SSU2: Peer test 4 error code ", (int)buf[1], " from ",
i2p::data::GetIdentHashAbbreviation (buf[1] < 64 ? GetRemoteIdentity ()->GetIdentHash () : i2p::data::IdentHash (buf + 3)));
- if (GetRouterStatus () == eRouterStatusTesting)
+ if (GetTestingState ())
SetRouterStatus (eRouterStatusUnknown);
it->second.first->Done ();
- }
+ }
m_PeerTests.erase (it);
- }
+ }
else
LogPrint (eLogWarning, "SSU2: Unknown peer test 4 nonce ", nonce);
break;
- }
+ }
case 5: // Alice from Charlie 1
if (htobe64 (((uint64_t)nonce << 32) | nonce) == m_SourceConnID)
{
if (m_Address)
- {
+ {
SetRouterStatus (eRouterStatusOK);
SendPeerTest (6, buf + offset, len - offset, m_Address->i);
- }
+ }
else
// we received msg 5 before msg 4
m_State = eSSU2SessionStatePeerTestReceived;
- }
+ }
else
LogPrint (eLogWarning, "SSU2: Peer test 5 nonce mismatch ", nonce, " connID=", m_SourceConnID);
break;
@@ -2092,15 +2341,31 @@
m_Server.RemoveSession (~htobe64 (((uint64_t)nonce << 32) | nonce));
break;
case 7: // Alice from Charlie 2
- m_Server.RemoveSession (htobe64 (((uint64_t)nonce << 32) | nonce));
if (m_Address->IsV6 ())
i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2
+ m_Server.RemoveSession (htobe64 (((uint64_t)nonce << 32) | nonce));
break;
default:
LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", buf[0]);
}
}
+ void SSU2Session::HandleI2NPMsg (std::shared_ptr<I2NPMessage>&& msg)
+ {
+ if (!msg) return;
+ uint32_t msgID = msg->GetMsgID ();
+ if (!msg->IsExpired ())
+ {
+ // m_LastActivityTimestamp is updated in ProcessData before
+ if (m_ReceivedI2NPMsgIDs.emplace (msgID, (uint32_t)GetLastActivityTimestamp ()).second)
+ m_Handler.PutNextMessage (std::move (msg));
+ else
+ LogPrint (eLogDebug, "SSU2: Message ", msgID, " already received");
+ }
+ else
+ LogPrint (eLogDebug, "SSU2: Message ", msgID, " expired");
+ }
+
bool SSU2Session::ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep)
{
if (size < 2) return false;
@@ -2154,48 +2419,74 @@
if (m_Address)
return i2p::context.GetRouterInfo ().GetSSU2Address (m_Address->IsV4 ());
return nullptr;
- }
+ }
void SSU2Session::AdjustMaxPayloadSize ()
{
auto addr = FindLocalAddress ();
- if (addr && addr->ssu)
- {
+ if (addr && addr->ssu)
+ {
int mtu = addr->ssu->mtu;
if (!mtu && addr->IsV4 ()) mtu = SSU2_MAX_PACKET_SIZE;
- if (m_Address && m_Address->ssu && (!mtu || m_Address->ssu->mtu < mtu))
+ if (m_Address && m_Address->ssu && (!mtu || m_Address->ssu->mtu < mtu))
mtu = m_Address->ssu->mtu;
if (mtu)
- {
+ {
+ if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE;
m_MaxPayloadSize = mtu - (addr->IsV6 () ? IPV6_HEADER_SIZE: IPV4_HEADER_SIZE) - UDP_HEADER_SIZE - 32;
LogPrint (eLogDebug, "SSU2: Session MTU=", mtu, ", max payload size=", m_MaxPayloadSize);
- }
- }
- }
-
+ }
+ }
+ }
+
RouterStatus SSU2Session::GetRouterStatus () const
{
if (m_Address)
{
- if (m_Address->IsV4 ())
+ if (m_Address->IsV4 ())
return i2p::context.GetStatus ();
- if (m_Address->IsV6 ())
+ if (m_Address->IsV6 ())
return i2p::context.GetStatusV6 ();
- }
+ }
return eRouterStatusUnknown;
- }
-
+ }
+
void SSU2Session::SetRouterStatus (RouterStatus status) const
{
if (m_Address)
- {
+ {
if (m_Address->IsV4 ())
- i2p::context.SetStatusSSU2 (status);
+ i2p::context.SetStatus (status);
else if (m_Address->IsV6 ())
- i2p::context.SetStatusV6SSU2 (status);
- }
- }
-
+ i2p::context.SetStatusV6 (status);
+ }
+ }
+
+ bool SSU2Session::GetTestingState () const
+ {
+ if (m_Address)
+ {
+ if (m_Address->IsV4 ())
+ return i2p::context.GetTesting ();
+ if (m_Address->IsV6 ())
+ return i2p::context.GetTestingV6 ();
+ }
+ return false;
+ }
+
+ void SSU2Session::SetTestingState (bool testing) const
+ {
+ if (m_Address)
+ {
+ if (m_Address->IsV4 ())
+ i2p::context.SetTesting (testing);
+ else if (m_Address->IsV6 ())
+ i2p::context.SetTestingV6 (testing);
+ }
+ if (!testing)
+ m_Server.AdjustTimeOffset (0); // reset time offset when testing is over
+ }
+
size_t SSU2Session::CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep)
{
if (len < 9) return 0;
@@ -2242,53 +2533,60 @@
if (ackThrough)
{
if (m_OutOfSequencePackets.empty ())
- acnt = std::min ((int)ackThrough, 255); // no gaps
+ acnt = std::min ((int)ackThrough, SSU2_MAX_NUM_ACNT); // no gaps
else
{
auto it = m_OutOfSequencePackets.rbegin (); it++; // prev packet num
while (it != m_OutOfSequencePackets.rend () && *it == ackThrough - acnt - 1)
{
acnt++;
- it++;
+ if (acnt >= SSU2_MAX_NUM_ACK_PACKETS)
+ break;
+ else
+ it++;
}
// ranges
uint32_t lastNum = ackThrough - acnt;
- if (acnt > 255)
+ if (acnt > SSU2_MAX_NUM_ACNT)
{
- auto d = std::div (acnt - 255, 255);
- acnt = 255;
- if (d.quot > maxNumRanges)
- {
+ auto d = std::div (acnt - SSU2_MAX_NUM_ACNT, SSU2_MAX_NUM_ACNT);
+ acnt = SSU2_MAX_NUM_ACNT;
+ if (d.quot > maxNumRanges)
+ {
d.quot = maxNumRanges;
d.rem = 0;
- }
- // Acks only ragnes for acnt
+ }
+ // Acks only ranges for acnt
for (int i = 0; i < d.quot; i++)
{
- buf[8 + numRanges*2] = 0; buf[8 + numRanges*2 + 1] = 255; // NACKs 0, Acks 255
+ buf[8 + numRanges*2] = 0; buf[8 + numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // NACKs 0, Acks 255
numRanges++;
}
if (d.rem > 0)
{
buf[8 + numRanges*2] = 0; buf[8 + numRanges*2 + 1] = d.rem;
numRanges++;
- }
- }
- while (it != m_OutOfSequencePackets.rend () && numRanges < maxNumRanges)
+ }
+ }
+ int numPackets = acnt + numRanges*SSU2_MAX_NUM_ACNT;
+ while (it != m_OutOfSequencePackets.rend () &&
+ numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS)
{
- if (lastNum - (*it) > 255)
- {
+ if (lastNum - (*it) > SSU2_MAX_NUM_ACNT)
+ {
// NACKs only ranges
- if (lastNum > (*it) + 255*(maxNumRanges - numRanges)) break; // too many NACKs
- while (lastNum - (*it) > 255)
+ if (lastNum > (*it) + SSU2_MAX_NUM_ACNT*(maxNumRanges - numRanges)) break; // too many NACKs
+ while (lastNum - (*it) > SSU2_MAX_NUM_ACNT)
{
- buf[8 + numRanges*2] = 255; buf[8 + numRanges*2 + 1] = 0; // NACKs 255, Acks 0
- lastNum -= 255;
+ buf[8 + numRanges*2] = SSU2_MAX_NUM_ACNT; buf[8 + numRanges*2 + 1] = 0; // NACKs 255, Acks 0
+ lastNum -= SSU2_MAX_NUM_ACNT;
numRanges++;
+ numPackets += SSU2_MAX_NUM_ACNT;
}
- }
+ }
// NACKs and Acks ranges
buf[8 + numRanges*2] = lastNum - (*it) - 1; // NACKs
+ numPackets += buf[8 + numRanges*2];
lastNum = *it; it++;
int numAcks = 1;
while (it != m_OutOfSequencePackets.rend () && lastNum > 0 && *it == lastNum - 1)
@@ -2296,31 +2594,34 @@
numAcks++; lastNum--;
it++;
}
- while (numAcks > 255)
+ while (numAcks > SSU2_MAX_NUM_ACNT)
{
// Acks only ranges
- buf[8 + numRanges*2 + 1] = 255; // Acks 255
- numAcks -= 255;
+ buf[8 + numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // Acks 255
+ numAcks -= SSU2_MAX_NUM_ACNT;
numRanges++;
- buf[8 + numRanges*2] = 0; // NACKs 0
- if (numRanges >= maxNumRanges) break;
- }
- if (numAcks > 255) numAcks = 255;
+ numPackets += SSU2_MAX_NUM_ACNT;
+ buf[8 + numRanges*2] = 0; // NACKs 0
+ if (numRanges >= maxNumRanges || numPackets >= SSU2_MAX_NUM_ACK_PACKETS) break;
+ }
+ if (numAcks > SSU2_MAX_NUM_ACNT) numAcks = SSU2_MAX_NUM_ACNT;
buf[8 + numRanges*2 + 1] = (uint8_t)numAcks; // Acks
- numRanges++;
+ numPackets += numAcks;
+ numRanges++;
}
- if (numRanges < maxNumRanges && it == m_OutOfSequencePackets.rend ())
+ if (it == m_OutOfSequencePackets.rend () &&
+ numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS)
{
- // add range between out-of-seqence and received
+ // add range between out-of-sequence and received
int nacks = *m_OutOfSequencePackets.begin () - m_ReceivePacketNum - 1;
if (nacks > 0)
{
- if (nacks > 255) nacks = 255;
+ if (nacks > SSU2_MAX_NUM_ACNT) nacks = SSU2_MAX_NUM_ACNT;
buf[8 + numRanges*2] = nacks;
- buf[8 + numRanges*2 + 1] = std::min ((int)m_ReceivePacketNum + 1, 255);
+ buf[8 + numRanges*2 + 1] = std::min ((int)m_ReceivePacketNum + 1, SSU2_MAX_NUM_ACNT);
numRanges++;
- }
- }
+ }
+ }
}
}
buf[7] = (uint8_t)acnt; // acnt
@@ -2330,18 +2631,13 @@
size_t SSU2Session::CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize)
{
- if (len < minSize) return 0;
- uint8_t paddingSize = rand () & 0x0F; // 0 - 15
- if (paddingSize > len) paddingSize = len;
- else if (paddingSize < minSize) paddingSize = minSize;
- if (paddingSize)
- {
- buf[0] = eSSU2BlkPadding;
- htobe16buf (buf + 1, paddingSize);
- memset (buf + 3, 0, paddingSize);
- }
- else
- return 0;
+ if (len < 3 || len < minSize) return 0;
+ size_t paddingSize = rand () & 0x0F; // 0 - 15
+ if (paddingSize + 3 > len) paddingSize = len - 3;
+ else if (paddingSize + 3 < minSize) paddingSize = minSize - 3;
+ buf[0] = eSSU2BlkPadding;
+ htobe16buf (buf + 1, paddingSize);
+ memset (buf + 3, 0, paddingSize);
return paddingSize + 3;
}
@@ -2405,7 +2701,7 @@
return payloadSize + 3;
}
- size_t SSU2Session::CreateRelayResponseBlock (uint8_t * buf, size_t len,
+ size_t SSU2Session::CreateRelayResponseBlock (uint8_t * buf, size_t len,
SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4)
{
buf[0] = eSSU2BlkRelayResponse;
@@ -2416,20 +2712,20 @@
buf[13] = 2; // ver
size_t csz = 0;
if (code == eSSU2RelayResponseCodeAccept)
- {
+ {
auto addr = i2p::context.GetRouterInfo ().GetSSU2Address (v4);
if (!addr)
{
LogPrint (eLogError, "SSU2: Can't find local address for RelayResponse");
return 0;
- }
+ }
csz = CreateEndpoint (buf + 15, len - 15, boost::asio::ip::udp::endpoint (addr->host, addr->port));
- if (!csz)
- {
+ if (!csz)
+ {
LogPrint (eLogError, "SSU2: Can't create local endpoint for RelayResponse");
return 0;
- }
- }
+ }
+ }
buf[14] = csz; // csz
// signature
size_t signatureLen = i2p::context.GetIdentity ()->GetSignatureLen ();
@@ -2437,7 +2733,7 @@
{
LogPrint (eLogError, "SSU2: Buffer for RelayResponse signature is too small ", len);
return 0;
- }
+ }
SignedData s;
s.Insert ((const uint8_t *)"RelayAgreementOK", 16); // prologue
if (code == eSSU2RelayResponseCodeAccept || code >= 64) // Charlie
@@ -2453,14 +2749,14 @@
{
LogPrint (eLogError, "SSU2: Buffer for RelayResponse token is too small ", len);
return 0;
- }
+ }
memcpy (buf + 3 + payloadSize, &token, 8);
payloadSize += 8;
- }
+ }
htobe16buf (buf + 1, payloadSize); // size
return payloadSize + 3;
}
-
+
size_t SSU2Session::CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code,
const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen)
{
@@ -2474,23 +2770,23 @@
buf[5] = 0; //flag
size_t offset = 6;
if (routerHash)
- {
+ {
memcpy (buf + offset, routerHash, 32); // router hash
offset += 32;
- }
+ }
memcpy (buf + offset, signedData, signedDataLen);
return payloadSize + 3;
}
size_t SSU2Session::CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce)
{
- auto localAddress = FindLocalAddress ();
+ auto localAddress = FindLocalAddress ();
if (!localAddress || !localAddress->port || localAddress->host.is_unspecified () ||
- localAddress->host.is_v4 () != m_RemoteEndpoint.address ().is_v4 ())
+ localAddress->host.is_v4 () != m_RemoteEndpoint.address ().is_v4 ())
{
LogPrint (eLogWarning, "SSU2: Can't find local address for peer test");
return 0;
- }
+ }
// signed data
auto ts = i2p::util::GetSecondsSinceEpoch ();
uint8_t signedData[96];
@@ -2503,21 +2799,21 @@
SignedData s;
s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue
s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
- s.Insert (signedData, 10 + asz); // ver, nonce, ts, asz, Alice's endpoint
+ s.Insert (signedData, 10 + asz); // ver, nonce, ts, asz, Alice's endpoint
s.Sign (i2p::context.GetPrivateKeys (), signedData + 10 + asz);
- return CreatePeerTestBlock (buf, len, 1, eSSU2PeerTestCodeAccept, nullptr,
+ return CreatePeerTestBlock (buf, len, 1, eSSU2PeerTestCodeAccept, nullptr,
signedData, 10 + asz + i2p::context.GetIdentity ()->GetSignatureLen ());
- }
+ }
size_t SSU2Session::CreateTerminationBlock (uint8_t * buf, size_t len)
- {
+ {
buf[0] = eSSU2BlkTermination;
htobe16buf (buf + 1, 9);
htobe64buf (buf + 3, m_ReceivePacketNum);
buf[11] = (uint8_t)m_TerminationReason;
return 12;
}
-
+
std::shared_ptr<const i2p::data::RouterInfo> SSU2Session::ExtractRouterInfo (const uint8_t * buf, size_t size)
{
if (size < 2) return nullptr;
@@ -2549,15 +2845,25 @@
if (packetNum <= m_ReceivePacketNum) return false; // duplicate
if (packetNum == m_ReceivePacketNum + 1)
{
- for (auto it = m_OutOfSequencePackets.begin (); it != m_OutOfSequencePackets.end ();)
+ if (!m_OutOfSequencePackets.empty ())
{
+ auto it = m_OutOfSequencePackets.begin ();
if (*it == packetNum + 1)
{
- packetNum++;
- it = m_OutOfSequencePackets.erase (it);
+ // first out of sequence packet is in sequence now
+ packetNum++; it++;
+ while (it != m_OutOfSequencePackets.end ())
+ {
+ if (*it == packetNum + 1)
+ {
+ packetNum++;
+ it++;
+ }
+ else // next out of sequence
+ break;
+ }
+ m_OutOfSequencePackets.erase (m_OutOfSequencePackets.begin (), it);
}
- else
- break;
}
m_ReceivePacketNum = packetNum;
}
@@ -2569,7 +2875,16 @@
void SSU2Session::SendQuickAck ()
{
uint8_t payload[SSU2_MAX_PACKET_SIZE];
- size_t payloadSize = CreateAckBlock (payload, m_MaxPayloadSize);
+ size_t payloadSize = 0;
+ if (m_SendPacketNum > m_LastDatetimeSentPacketNum + SSU2_SEND_DATETIME_NUM_PACKETS)
+ {
+ payload[0] = eSSU2BlkDateTime;
+ htobe16buf (payload + 1, 4);
+ htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
+ payloadSize += 7;
+ m_LastDatetimeSentPacketNum = m_SendPacketNum;
+ }
+ payloadSize += CreateAckBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
SendData (payload, payloadSize);
}
@@ -2584,18 +2899,40 @@
void SSU2Session::SendPathResponse (const uint8_t * data, size_t len)
{
- if (len < 8 || len > m_MaxPayloadSize - 3)
+ if (len > m_MaxPayloadSize - 3)
{
LogPrint (eLogWarning, "SSU2: Incorrect data size for path response ", len);
return;
- }
+ }
uint8_t payload[SSU2_MAX_PACKET_SIZE];
payload[0] = eSSU2BlkPathResponse;
htobe16buf (payload + 1, len);
memcpy (payload + 3, data, len);
- SendData (payload, len + 3);
- }
-
+ size_t payloadSize = len + 3;
+ if (payloadSize < m_MaxPayloadSize)
+ payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, payloadSize < 8 ? 8 : 0);
+ SendData (payload, payloadSize);
+ }
+
+ void SSU2Session::SendPathChallenge ()
+ {
+ uint8_t payload[SSU2_MAX_PACKET_SIZE];
+ payload[0] = eSSU2BlkPathChallenge;
+ size_t len = rand () % (m_MaxPayloadSize - 3);
+ htobe16buf (payload + 1, len);
+ if (len > 0)
+ {
+ RAND_bytes (payload + 3, len);
+ i2p::data::IdentHash * hash = new i2p::data::IdentHash ();
+ SHA256 (payload + 3, len, *hash);
+ m_PathChallenge.reset (hash);
+ }
+ len += 3;
+ if (len < m_MaxPayloadSize)
+ len += CreatePaddingBlock (payload + len, m_MaxPayloadSize - len, len < 8 ? 8 : 0);
+ SendData (payload, len);
+ }
+
void SSU2Session::CleanUp (uint64_t ts)
{
for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();)
@@ -2608,10 +2945,26 @@
else
++it;
}
+ if (m_ReceivedI2NPMsgIDs.size () > SSU2_MAX_NUM_RECEIVED_I2NP_MSGIDS || ts > GetLastActivityTimestamp () + SSU2_DECAY_INTERVAL)
+ // decay
+ m_ReceivedI2NPMsgIDs.clear ();
+ else
+ {
+ // delete old received msgIDs
+ for (auto it = m_ReceivedI2NPMsgIDs.begin (); it != m_ReceivedI2NPMsgIDs.end ();)
+ {
+ if (ts > it->second + SSU2_RECEIVED_I2NP_MSGIDS_CLEANUP_TIMEOUT)
+ it = m_ReceivedI2NPMsgIDs.erase (it);
+ else
+ ++it;
+ }
+ }
if (!m_OutOfSequencePackets.empty ())
- {
- if (m_OutOfSequencePackets.size () > 2*SSU2_MAX_NUM_ACK_RANGES ||
- *m_OutOfSequencePackets.rbegin () > m_ReceivePacketNum + 255*8)
+ {
+ int ranges = 0;
+ while (ranges < 8 && !m_OutOfSequencePackets.empty () &&
+ (m_OutOfSequencePackets.size () > 2*SSU2_MAX_NUM_ACK_RANGES ||
+ *m_OutOfSequencePackets.rbegin () > m_ReceivePacketNum + SSU2_MAX_NUM_ACK_PACKETS))
{
uint32_t packet = *m_OutOfSequencePackets.begin ();
if (packet > m_ReceivePacketNum + 1)
@@ -2620,9 +2973,13 @@
packet--;
m_ReceivePacketNum = packet - 1;
UpdateReceivePacketNum (packet);
- }
+ ranges++;
+ }
else
- LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received ", m_ReceivePacketNum);
+ {
+ LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received ", m_ReceivePacketNum);
+ break;
+ }
}
if (m_OutOfSequencePackets.size () > 255*4)
{
@@ -2630,8 +2987,8 @@
m_ReceivePacketNum = *m_OutOfSequencePackets.rbegin ();
m_OutOfSequencePackets.clear ();
}
- }
-
+ }
+
for (auto it = m_RelaySessions.begin (); it != m_RelaySessions.end ();)
{
if (ts > it->second.second + SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT)
@@ -2652,11 +3009,15 @@
else
++it;
}
+ if (m_PathChallenge)
+ RequestTermination (eSSU2TerminationReasonNormalClose);
}
void SSU2Session::FlushData ()
{
bool sent = SendQueue (); // if we have something to send
+ if (sent)
+ SetSendQueueSize (m_SendQueue.size ());
if (m_IsDataReceived)
{
if (!sent) SendQuickAck ();
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/SSU2Session.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022, The PurpleI2P Project
+* Copyright (c) 2022-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -35,18 +35,27 @@
const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 seconds
const size_t SSU2_MAX_PACKET_SIZE = 1500;
const size_t SSU2_MIN_PACKET_SIZE = 1280;
- const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1000; // in millseconds
+ const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1000; // in milliseconds
const int SSU2_RESEND_INTERVAL = 300; // in milliseconds
const int SSU2_MAX_NUM_RESENDS = 5;
const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
+ const int SSU2_MAX_NUM_RECEIVED_I2NP_MSGIDS = 5000; // how many msgID we store for duplicates check
+ const int SSU2_RECEIVED_I2NP_MSGIDS_CLEANUP_TIMEOUT = 10; // in seconds
+ const int SSU2_DECAY_INTERVAL = 20; // in seconds
const size_t SSU2_MIN_WINDOW_SIZE = 16; // in packets
const size_t SSU2_MAX_WINDOW_SIZE = 256; // in packets
const size_t SSU2_MIN_RTO = 100; // in milliseconds
const size_t SSU2_MAX_RTO = 2500; // in milliseconds
const float SSU2_kAPPA = 1.8;
const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 500; // in messages
+ const int SSU2_MAX_NUM_ACNT = 255; // acnt, acks or nacks
+ const int SSU2_MAX_NUM_ACK_PACKETS = 511; // ackthrough + acnt + 1 range
const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send
const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64;
+ const int SSU2_SEND_DATETIME_NUM_PACKETS = 256;
+
+ // flags
+ const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01;
enum SSU2MessageType
{
@@ -97,11 +106,13 @@
eSSU2SessionStateSessionConfirmedSent,
eSSU2SessionStateEstablished,
eSSU2SessionStateClosing,
+ eSSU2SessionStateClosingConfirmed,
eSSU2SessionStateTerminated,
eSSU2SessionStateFailed,
eSSU2SessionStateIntroduced,
eSSU2SessionStatePeerTest,
- eSSU2SessionStatePeerTestReceived // 5 before 4
+ eSSU2SessionStatePeerTestReceived, // 5 before 4
+ eSSU2SessionStateTokenRequestReceived
};
enum SSU2PeerTestCode
@@ -119,7 +130,7 @@
eSSU2PeerTestCodeCharlieAliceIsBanned = 69,
eSSU2PeerTestCodeCharlieAliceIsUnknown = 70,
eSSU2PeerTestCodeUnspecified = 128
- };
+ };
enum SSU2RelayResponseCode
{
@@ -128,7 +139,7 @@
eSSU2RelayResponseCodeCharlieUnsupportedAddress = 65,
eSSU2RelayResponseCodeCharlieSignatureFailure = 67,
eSSU2RelayResponseCodeCharlieAliceIsUnknown = 70
- };
+ };
enum SSU2TerminationReason
{
@@ -155,23 +166,27 @@
eSSU2TerminationReasonIncompatibleVersion = 20,
eSSU2TerminationReasonWrongNetID = 21,
eSSU2TerminationReasonReplacedByNewSession = 22
- };
-
+ };
+
struct SSU2IncompleteMessage
{
struct Fragment
{
uint8_t buf[SSU2_MAX_PACKET_SIZE];
size_t len;
+ int fragmentNum;
bool isLast;
+ std::shared_ptr<Fragment> next;
};
std::shared_ptr<I2NPMessage> msg;
int nextFragmentNum;
uint32_t lastFragmentInsertTime; // in seconds
- std::map<int, std::shared_ptr<Fragment> > outOfSequenceFragments;
+ std::shared_ptr<Fragment> outOfSequenceFragments; // #1 and more
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
+ bool ConcatOutOfSequenceFragments (); // true if message complete
+ void AddOutOfSequenceFragment (std::shared_ptr<Fragment> fragment);
};
struct SSU2SentPacket
@@ -181,7 +196,7 @@
uint64_t sendTime; // in milliseconds
int numResends = 0;
};
-
+
// RouterInfo flags
const uint8_t SSU2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
const uint8_t SSU2_ROUTER_INFO_FLAG_GZIP = 0x02;
@@ -239,8 +254,8 @@
void SendLocalRouterInfo (bool update) override;
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
uint32_t GetRelayTag () const override { return m_RelayTag; };
- void Resend (uint64_t ts);
- bool IsEstablished () const { return m_State == eSSU2SessionStateEstablished; };
+ size_t Resend (uint64_t ts); // return number or resent packets
+ bool IsEstablished () const override { return m_State == eSSU2SessionStateEstablished; };
uint64_t GetConnID () const { return m_SourceConnID; };
SSU2SessionState GetState () const { return m_State; };
void SetState (SSU2SessionState state) { m_State = state; };
@@ -251,7 +266,7 @@
bool ProcessRetry (uint8_t * buf, size_t len);
bool ProcessHolePunch (uint8_t * buf, size_t len);
bool ProcessPeerTest (uint8_t * buf, size_t len);
- void ProcessData (uint8_t * buf, size_t len);
+ void ProcessData (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
private:
@@ -264,7 +279,7 @@
bool SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg);
void ResendHandshakePacket ();
void ConnectAfterIntroduction ();
-
+
void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len);
void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len);
@@ -274,13 +289,14 @@
void KDFDataPhase (uint8_t * keydata_ab, uint8_t * keydata_ba);
void SendTokenRequest ();
void SendRetry ();
- uint32_t SendData (const uint8_t * buf, size_t len); // returns packet num
+ uint32_t SendData (const uint8_t * buf, size_t len, uint8_t flags = 0); // returns packet num
void SendQuickAck ();
void SendTermination ();
void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey, uint64_t token);
- void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message
+ void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message
void SendPathResponse (const uint8_t * data, size_t len);
-
+ void SendPathChallenge ();
+
void HandlePayload (const uint8_t * buf, size_t len);
void HandleDateTime (const uint8_t * buf, size_t len);
void HandleAck (const uint8_t * buf, size_t len);
@@ -292,16 +308,18 @@
void AdjustMaxPayloadSize ();
RouterStatus GetRouterStatus () const;
void SetRouterStatus (RouterStatus status) const;
+ bool GetTestingState () const;
+ void SetTestingState(bool testing) const;
std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo (const uint8_t * buf, size_t size);
void CreateNonce (uint64_t seqn, uint8_t * nonce);
bool UpdateReceivePacketNum (uint32_t packetNum); // for Ack, returns false if duplicate
void HandleFirstFragment (const uint8_t * buf, size_t len);
void HandleFollowOnFragment (const uint8_t * buf, size_t len);
- bool ConcatOutOfSequenceFragments (std::shared_ptr<SSU2IncompleteMessage> m); // true if message complete
void HandleRelayRequest (const uint8_t * buf, size_t len);
- void HandleRelayIntro (const uint8_t * buf, size_t len);
+ void HandleRelayIntro (const uint8_t * buf, size_t len, int attempts = 0);
void HandleRelayResponse (const uint8_t * buf, size_t len);
void HandlePeerTest (const uint8_t * buf, size_t len);
+ void HandleI2NPMsg (std::shared_ptr<I2NPMessage>&& msg);
size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r);
@@ -311,7 +329,7 @@
size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg);
size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg, uint8_t& fragmentNum, uint32_t msgID);
size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen);
- size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4);
+ size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4);
size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen);
size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice
size_t CreateTerminationBlock (uint8_t * buf, size_t len);
@@ -329,10 +347,10 @@
uint64_t m_DestConnID, m_SourceConnID;
SSU2SessionState m_State;
uint8_t m_KeyDataSend[64], m_KeyDataReceive[64];
- uint32_t m_SendPacketNum, m_ReceivePacketNum;
+ uint32_t m_SendPacketNum, m_ReceivePacketNum, m_LastDatetimeSentPacketNum;
std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num
std::map<uint32_t, std::shared_ptr<SSU2SentPacket> > m_SentPackets; // packetNum -> packet
- std::map<uint32_t, std::shared_ptr<SSU2IncompleteMessage> > m_IncompleteMessages; // I2NP
+ std::unordered_map<uint32_t, std::shared_ptr<SSU2IncompleteMessage> > m_IncompleteMessages; // msgID -> I2NP
std::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::map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_PeerTests; // same as for relay sessions
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
@@ -344,6 +362,8 @@
boost::asio::deadline_timer m_ConnectTimer;
SSU2TerminationReason m_TerminationReason;
size_t m_MaxPayloadSize;
+ std::unique_ptr<i2p::data::IdentHash> m_PathChallenge;
+ std::unordered_map<uint32_t, uint32_t> m_ReceivedI2NPMsgIDs; // msgID -> timestamp in seconds
};
inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce)
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Signature.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -15,26 +15,35 @@
namespace crypto
{
#if OPENSSL_EDDSA
- EDDSA25519Verifier::EDDSA25519Verifier ()
+ EDDSA25519Verifier::EDDSA25519Verifier ():
+ m_Pkey (nullptr)
{
- m_MDCtx = EVP_MD_CTX_create ();
}
EDDSA25519Verifier::~EDDSA25519Verifier ()
{
- EVP_MD_CTX_destroy (m_MDCtx);
+ EVP_PKEY_free (m_Pkey);
}
void EDDSA25519Verifier::SetPublicKey (const uint8_t * signingKey)
{
- EVP_PKEY * pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ED25519, NULL, signingKey, 32);
- EVP_DigestVerifyInit (m_MDCtx, NULL, NULL, NULL, pkey);
- EVP_PKEY_free (pkey);
+ if (m_Pkey) EVP_PKEY_free (m_Pkey);
+ m_Pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ED25519, NULL, signingKey, 32);
}
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
- return EVP_DigestVerify (m_MDCtx, signature, 64, buf, len);
+ if (m_Pkey)
+ {
+ EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
+ EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, m_Pkey);
+ auto ret = EVP_DigestVerify (ctx, signature, 64, buf, len);
+ EVP_MD_CTX_destroy (ctx);
+ return ret;
+ }
+ else
+ LogPrint (eLogError, "EdDSA verification key is not set");
+ return false;
}
#else
@@ -99,41 +108,45 @@
#if OPENSSL_EDDSA
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey):
- m_MDCtx (nullptr), m_Fallback (nullptr)
+ m_Pkey (nullptr), m_Fallback (nullptr)
{
- EVP_PKEY * pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_ED25519, NULL, signingPrivateKey, 32);
+ m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_ED25519, NULL, signingPrivateKey, 32);
uint8_t publicKey[EDDSA25519_PUBLIC_KEY_LENGTH];
size_t len = EDDSA25519_PUBLIC_KEY_LENGTH;
- EVP_PKEY_get_raw_public_key (pkey, publicKey, &len);
+ EVP_PKEY_get_raw_public_key (m_Pkey, publicKey, &len);
if (signingPublicKey && memcmp (publicKey, signingPublicKey, EDDSA25519_PUBLIC_KEY_LENGTH))
{
LogPrint (eLogWarning, "EdDSA public key mismatch. Fallback");
m_Fallback = new EDDSA25519SignerCompat (signingPrivateKey, signingPublicKey);
+ EVP_PKEY_free (m_Pkey);
+ m_Pkey = nullptr;
}
- else
- {
- m_MDCtx = EVP_MD_CTX_create ();
- EVP_DigestSignInit (m_MDCtx, NULL, NULL, NULL, pkey);
- }
- EVP_PKEY_free (pkey);
}
EDDSA25519Signer::~EDDSA25519Signer ()
{
if (m_Fallback) delete m_Fallback;
- EVP_MD_CTX_destroy (m_MDCtx);
+ if (m_Pkey) EVP_PKEY_free (m_Pkey);
}
void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const
{
- if (m_Fallback) return m_Fallback->Sign (buf, len, signature);
- else
+ if (m_Fallback)
+ return m_Fallback->Sign (buf, len, signature);
+ else if (m_Pkey)
{
+
+ EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
size_t l = 64;
uint8_t sig[64]; // temporary buffer for signature. openssl issue #7232
- EVP_DigestSign (m_MDCtx, sig, &l, buf, len);
+ EVP_DigestSignInit (ctx, NULL, NULL, NULL, m_Pkey);
+ if (!EVP_DigestSign (ctx, sig, &l, buf, len))
+ LogPrint (eLogError, "EdDSA signing failed");
memcpy (signature, sig, 64);
+ EVP_MD_CTX_destroy (ctx);
}
+ else
+ LogPrint (eLogError, "EdDSA signing key is not set");
}
#endif
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Signature.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -304,7 +304,7 @@
private:
#if OPENSSL_EDDSA
- EVP_MD_CTX * m_MDCtx;
+ EVP_PKEY * m_Pkey;
#else
EDDSAPoint m_PublicKey;
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
@@ -341,7 +341,7 @@
private:
- EVP_MD_CTX * m_MDCtx;
+ EVP_PKEY * m_Pkey;
EDDSA25519SignerCompat * m_Fallback;
};
#else
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Streaming.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -19,11 +19,6 @@
{
namespace stream
{
- void SendBufferQueue::Add (const uint8_t * buf, size_t len, SendHandler handler)
- {
- Add (std::make_shared<SendBuffer>(buf, len, handler));
- }
-
void SendBufferQueue::Add (std::shared_ptr<SendBuffer> buf)
{
if (buf)
@@ -51,8 +46,8 @@
{
// partially
rem = len - offset;
- memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), len - offset);
- nextBuffer->offset += (len - offset);
+ memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), rem);
+ nextBuffer->offset += rem;
offset = len; // break
}
}
@@ -115,10 +110,7 @@
void Stream::CleanUp ()
{
- {
- std::unique_lock<std::mutex> l(m_SendBufferMutex);
- m_SendBuffer.CleanUp ();
- }
+ m_SendBuffer.CleanUp ();
while (!m_ReceiveQueue.empty ())
{
auto packet = m_ReceiveQueue.front ();
@@ -139,14 +131,22 @@
{
m_NumReceivedBytes += packet->GetLength ();
if (!m_SendStreamID)
+ {
m_SendStreamID = packet->GetReceiveStreamID ();
+ if (!m_RemoteIdentity && packet->GetNACKCount () == 8 && // first incoming packet
+ memcmp (packet->GetNACKs (), m_LocalDestination.GetOwner ()->GetIdentHash (), 32))
+ {
+ LogPrint (eLogWarning, "Streaming: Destination mismatch for ", m_LocalDestination.GetOwner ()->GetIdentHash ().ToBase32 ());
+ m_LocalDestination.DeletePacket (packet);
+ return;
+ }
+ }
if (!packet->IsNoAck ()) // ack received
ProcessAck (packet);
int32_t receivedSeqn = packet->GetSeqn ();
- bool isSyn = packet->IsSYN ();
- if (!receivedSeqn && !isSyn)
+ if (!receivedSeqn && !packet->GetFlags ())
{
// plain ack
LogPrint (eLogDebug, "Streaming: Plain ACK received");
@@ -188,7 +188,7 @@
shared_from_this (), std::placeholders::_1));
}
}
- else if (isSyn)
+ else if (packet->IsSYN ())
// we have to send SYN back to incoming connection
SendBuffer (); // also sets m_IsOpen
}
@@ -384,7 +384,7 @@
memset (p.buf, 0, 22); // minimal header all zeroes
memcpy (p.buf + 4, packet->buf, 4); // but receiveStreamID is the sendStreamID from the ping
htobe16buf (p.buf + 18, PACKET_FLAG_ECHO); // and echo flag
- ssize_t payloadLen = packet->len - (packet->GetPayload () - packet->buf);
+ auto payloadLen = int(packet->len) - (packet->GetPayload () - packet->buf);
if (payloadLen > 0)
memcpy (p.buf + 22, packet->GetPayload (), payloadLen);
else
@@ -435,7 +435,7 @@
LogPrint(eLogError, "Streaming: Packet ", seqn, "sent from the future, sendTime=", sentPacket->sendTime);
rtt = 1;
}
- m_RTT = (m_RTT*seqn + rtt)/(seqn + 1);
+ m_RTT = std::round ((m_RTT*seqn + rtt)/(seqn + 1.0));
m_RTO = m_RTT*1.5; // TODO: implement it better
LogPrint (eLogDebug, "Streaming: Packet ", seqn, " acknowledged rtt=", rtt, " sentTime=", sentPacket->sendTime);
m_SentPackets.erase (it++);
@@ -474,6 +474,48 @@
Close (); // check is all outgoing messages have been sent and we can send close
}
+ size_t Stream::Receive (uint8_t * buf, size_t len, int timeout)
+ {
+ if (!len) return 0;
+ size_t ret = 0;
+ volatile bool done = false;
+ std::condition_variable newDataReceived;
+ std::mutex newDataReceivedMutex;
+ AsyncReceive (boost::asio::buffer (buf, len),
+ [&ret, &done, &newDataReceived, &newDataReceivedMutex](const boost::system::error_code& ecode, std::size_t bytes_transferred)
+ {
+ if (ecode == boost::asio::error::timed_out)
+ ret = 0;
+ else
+ ret = bytes_transferred;
+ std::unique_lock<std::mutex> l(newDataReceivedMutex);
+ newDataReceived.notify_all ();
+ done = true;
+ },
+ timeout);
+ if (!done)
+ { std::unique_lock<std::mutex> l(newDataReceivedMutex);
+ if (!done && newDataReceived.wait_for (l, std::chrono::seconds (timeout)) == std::cv_status::timeout)
+ ret = 0;
+ }
+ if (!done)
+ {
+ // make sure that AsycReceive complete
+ auto s = shared_from_this();
+ m_Service.post ([s]()
+ {
+ s->m_ReceiveTimer.cancel ();
+ });
+ int i = 0;
+ while (!done && i < 100) // 1 sec
+ {
+ std::this_thread::sleep_for (std::chrono::milliseconds(10));
+ i++;
+ }
+ }
+ return ret;
+ }
+
size_t Stream::Send (const uint8_t * buf, size_t len)
{
AsyncSend (buf, len, nullptr);
@@ -482,14 +524,18 @@
void Stream::AsyncSend (const uint8_t * buf, size_t len, SendHandler handler)
{
+ std::shared_ptr<i2p::stream::SendBuffer> buffer;
if (len > 0 && buf)
- {
- std::unique_lock<std::mutex> l(m_SendBufferMutex);
- m_SendBuffer.Add (buf, len, handler);
- }
+ buffer = std::make_shared<i2p::stream::SendBuffer>(buf, len, handler);
else if (handler)
handler(boost::system::error_code ());
- m_Service.post (std::bind (&Stream::SendBuffer, shared_from_this ()));
+ auto s = shared_from_this ();
+ m_Service.post ([s, buffer]()
+ {
+ if (buffer)
+ s->m_SendBuffer.Add (buffer);
+ s->SendBuffer ();
+ });
}
void Stream::SendBuffer ()
@@ -499,80 +545,88 @@
bool isNoAck = m_LastReceivedSequenceNumber < 0; // first packet
std::vector<Packet *> packets;
+ while ((m_Status == eStreamStatusNew) || (IsEstablished () && !m_SendBuffer.IsEmpty () && numMsgs > 0))
{
- std::unique_lock<std::mutex> l(m_SendBufferMutex);
- while ((m_Status == eStreamStatusNew) || (IsEstablished () && !m_SendBuffer.IsEmpty () && numMsgs > 0))
+ Packet * p = m_LocalDestination.NewPacket ();
+ uint8_t * packet = p->GetBuffer ();
+ // TODO: implement setters
+ size_t size = 0;
+ htobe32buf (packet + size, m_SendStreamID);
+ size += 4; // sendStreamID
+ htobe32buf (packet + size, m_RecvStreamID);
+ size += 4; // receiveStreamID
+ htobe32buf (packet + size, m_SequenceNumber++);
+ size += 4; // sequenceNum
+ if (isNoAck)
+ htobuf32 (packet + size, 0);
+ else
+ htobe32buf (packet + size, m_LastReceivedSequenceNumber);
+ size += 4; // ack Through
+ if (m_Status == eStreamStatusNew && !m_SendStreamID && m_RemoteIdentity)
{
- Packet * p = m_LocalDestination.NewPacket ();
- uint8_t * packet = p->GetBuffer ();
- // TODO: implement setters
- size_t size = 0;
- htobe32buf (packet + size, m_SendStreamID);
- size += 4; // sendStreamID
- htobe32buf (packet + size, m_RecvStreamID);
- size += 4; // receiveStreamID
- htobe32buf (packet + size, m_SequenceNumber++);
- size += 4; // sequenceNum
- if (isNoAck)
- htobuf32 (packet + size, 0);
- else
- htobe32buf (packet + size, m_LastReceivedSequenceNumber);
- size += 4; // ack Through
+ // first SYN packet
+ packet[size] = 8;
+ size++; // NACK count
+ memcpy (packet + size, m_RemoteIdentity->GetIdentHash (), 32);
+ size += 32;
+ }
+ else
+ {
packet[size] = 0;
size++; // NACK count
- packet[size] = m_RTO/1000;
- size++; // resend delay
- if (m_Status == eStreamStatusNew)
- {
- // initial packet
- m_Status = eStreamStatusOpen;
- if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());;
- if (m_RemoteLeaseSet)
- {
- m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true);
- m_MTU = m_RoutingSession->IsRatchets () ? STREAMING_MTU_RATCHETS : STREAMING_MTU;
- }
- uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED |
- PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED;
- if (isNoAck) flags |= PACKET_FLAG_NO_ACK;
- bool isOfflineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().IsOfflineSignature ();
- if (isOfflineSignature) flags |= PACKET_FLAG_OFFLINE_SIGNATURE;
- htobe16buf (packet + size, flags);
- size += 2; // flags
- size_t identityLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetFullLen ();
- size_t signatureLen = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetSignatureLen ();
- uint8_t * optionsSize = packet + size; // set options size later
- size += 2; // options size
- m_LocalDestination.GetOwner ()->GetIdentity ()->ToBuffer (packet + size, identityLen);
- size += identityLen; // from
- htobe16buf (packet + size, m_MTU);
- size += 2; // max packet size
- if (isOfflineSignature)
- {
- const auto& offlineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetOfflineSignature ();
- memcpy (packet + size, offlineSignature.data (), offlineSignature.size ());
- size += offlineSignature.size (); // offline signature
- }
- uint8_t * signature = packet + size; // set it later
- memset (signature, 0, signatureLen); // zeroes for now
- size += signatureLen; // signature
- htobe16buf (optionsSize, packet + size - 2 - optionsSize); // actual options size
- size += m_SendBuffer.Get (packet + size, m_MTU); // payload
- m_LocalDestination.GetOwner ()->Sign (packet, size, signature);
- }
- else
- {
- // follow on packet
- htobuf16 (packet + size, 0);
- size += 2; // flags
- htobuf16 (packet + size, 0); // no options
- size += 2; // options size
- size += m_SendBuffer.Get(packet + size, m_MTU); // payload
- }
- p->len = size;
- packets.push_back (p);
- numMsgs--;
+ }
+ packet[size] = m_RTO/1000;
+ size++; // resend delay
+ if (m_Status == eStreamStatusNew)
+ {
+ // initial packet
+ m_Status = eStreamStatusOpen;
+ if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());;
+ if (m_RemoteLeaseSet)
+ {
+ m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true);
+ m_MTU = m_RoutingSession->IsRatchets () ? STREAMING_MTU_RATCHETS : STREAMING_MTU;
+ }
+ uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED |
+ PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED;
+ if (isNoAck) flags |= PACKET_FLAG_NO_ACK;
+ bool isOfflineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().IsOfflineSignature ();
+ if (isOfflineSignature) flags |= PACKET_FLAG_OFFLINE_SIGNATURE;
+ htobe16buf (packet + size, flags);
+ size += 2; // flags
+ size_t identityLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetFullLen ();
+ size_t signatureLen = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetSignatureLen ();
+ uint8_t * optionsSize = packet + size; // set options size later
+ size += 2; // options size
+ m_LocalDestination.GetOwner ()->GetIdentity ()->ToBuffer (packet + size, identityLen);
+ size += identityLen; // from
+ htobe16buf (packet + size, m_MTU);
+ size += 2; // max packet size
+ if (isOfflineSignature)
+ {
+ const auto& offlineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetOfflineSignature ();
+ memcpy (packet + size, offlineSignature.data (), offlineSignature.size ());
+ size += offlineSignature.size (); // offline signature
+ }
+ uint8_t * signature = packet + size; // set it later
+ memset (signature, 0, signatureLen); // zeroes for now
+ size += signatureLen; // signature
+ htobe16buf (optionsSize, packet + size - 2 - optionsSize); // actual options size
+ size += m_SendBuffer.Get (packet + size, m_MTU); // payload
+ m_LocalDestination.GetOwner ()->Sign (packet, size, signature);
}
+ else
+ {
+ // follow on packet
+ htobuf16 (packet + size, 0);
+ size += 2; // flags
+ htobuf16 (packet + size, 0); // no options
+ size += 2; // options size
+ size += m_SendBuffer.Get(packet + size, m_MTU); // payload
+ }
+ p->len = size;
+ packets.push_back (p);
+ numMsgs--;
}
if (packets.size () > 0)
{
@@ -729,7 +783,7 @@
Terminate ();
break;
default:
- LogPrint (eLogWarning, "Streaming: Unexpected stream status ", (int)m_Status, "sSID=", m_SendStreamID);
+ LogPrint (eLogWarning, "Streaming: Unexpected stream status=", (int)m_Status, " for sSID=", m_SendStreamID);
};
}
@@ -855,7 +909,7 @@
for (const auto& it: packets)
{
auto msg = m_RoutingSession->WrapSingleMessage (m_LocalDestination.CreateDataMessage (
- it->GetBuffer (), it->GetLength (), m_Port, !m_RoutingSession->IsRatchets ()));
+ it->GetBuffer (), it->GetLength (), m_Port, !m_RoutingSession->IsRatchets (), it->IsSYN ()));
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
i2p::tunnel::eDeliveryTypeTunnel,
@@ -864,7 +918,7 @@
});
m_NumSentBytes += it->GetLength ();
}
- m_CurrentOutboundTunnel->SendTunnelDataMsg (msgs);
+ m_CurrentOutboundTunnel->SendTunnelDataMsgs (msgs);
}
else
{
@@ -1085,8 +1139,6 @@
m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip),
m_PendingIncomingTimer (m_Owner->GetService ())
{
- if (m_Gzip)
- m_Deflator.reset (new i2p::data::GzipDeflator);
}
StreamingDestination::~StreamingDestination ()
@@ -1341,6 +1393,26 @@
acceptor (stream);
}
+ std::shared_ptr<Stream> StreamingDestination::AcceptStream (int timeout)
+ {
+ std::shared_ptr<i2p::stream::Stream> stream;
+ std::condition_variable streamAccept;
+ std::mutex streamAcceptMutex;
+ std::unique_lock<std::mutex> l(streamAcceptMutex);
+ AcceptOnce (
+ [&streamAccept, &streamAcceptMutex, &stream](std::shared_ptr<i2p::stream::Stream> s)
+ {
+ stream = s;
+ std::unique_lock<std::mutex> l(streamAcceptMutex);
+ streamAccept.notify_all ();
+ });
+ if (timeout)
+ streamAccept.wait_for (l, std::chrono::seconds (timeout));
+ else
+ streamAccept.wait (l);
+ return stream;
+ }
+
void StreamingDestination::HandlePendingIncomingTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
@@ -1365,16 +1437,16 @@
}
std::shared_ptr<I2NPMessage> StreamingDestination::CreateDataMessage (
- const uint8_t * payload, size_t len, uint16_t toPort, bool checksum)
+ const uint8_t * payload, size_t len, uint16_t toPort, bool checksum, bool gzip)
{
size_t size;
- auto msg = m_I2NPMsgsPool.AcquireShared ();
+ auto msg = (len <= STREAMING_MTU_RATCHETS) ? m_I2NPMsgsPool.AcquireShared () : NewI2NPMessage ();
uint8_t * buf = msg->GetPayload ();
buf += 4; // reserve for lengthlength
msg->len += 4;
- if (m_Gzip && m_Deflator)
- size = m_Deflator->Deflate (payload, len, buf, msg->maxLen - msg->len);
+ if (m_Gzip || gzip)
+ size = m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len);
else
size = i2p::data::GzipNoCompression (payload, len, buf, msg->maxLen - msg->len);
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Streaming.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -80,6 +80,7 @@
uint32_t GetAckThrough () const { return bufbe32toh (buf + 12); };
uint8_t GetNACKCount () const { return buf[16]; };
uint32_t GetNACK (int i) const { return bufbe32toh (buf + 17 + 4 * i); };
+ const uint8_t * GetNACKs () const { return buf + 17; };
const uint8_t * GetOption () const { return buf + 17 + GetNACKCount ()*4 + 3; }; // 3 = resendDelay + flags
uint16_t GetFlags () const { return bufbe16toh (GetOption () - 2); };
uint16_t GetOptionSize () const { return bufbe16toh (GetOption ()); };
@@ -134,7 +135,6 @@
SendBufferQueue (): m_Size (0) {};
~SendBufferQueue () { CleanUp (); };
- void Add (const uint8_t * buf, size_t len, SendHandler handler);
void Add (std::shared_ptr<SendBuffer> buf);
size_t Get (uint8_t * buf, size_t len);
size_t GetSize () const { return m_Size; };
@@ -185,6 +185,7 @@
template<typename Buffer, typename ReceiveHandler>
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); };
+ size_t Receive (uint8_t * buf, size_t len, int timeout);
void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); };
@@ -249,7 +250,6 @@
size_t m_NumSentBytes, m_NumReceivedBytes;
uint16_t m_Port;
- std::mutex m_SendBufferMutex;
SendBufferQueue m_SendBuffer;
int m_WindowSize, m_RTT, m_RTO, m_AckDelay;
uint64_t m_LastWindowSizeIncreaseTime;
@@ -278,13 +278,14 @@
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
void AcceptOnce (const Acceptor& acceptor);
void AcceptOnceAcceptor (std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev);
+ std::shared_ptr<Stream> AcceptStream (int timeout = 0); // sync
std::shared_ptr<i2p::client::ClientDestination> GetOwner () const { return m_Owner; };
void SetOwner (std::shared_ptr<i2p::client::ClientDestination> owner) { m_Owner = owner; };
uint16_t GetLocalPort () const { return m_LocalPort; };
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
- std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort, bool checksum = true);
+ std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort, bool checksum = true, bool gzip = false);
Packet * NewPacket () { return m_PacketsPool.Acquire(); }
void DeletePacket (Packet * p) { return m_PacketsPool.Release(p); }
@@ -310,12 +311,12 @@
std::unordered_map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN
i2p::util::MemoryPool<Packet> m_PacketsPool;
- i2p::util::MemoryPool<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> > m_I2NPMsgsPool;
+ i2p::util::MemoryPool<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> > m_I2NPMsgsPool;
public:
i2p::data::GzipInflator m_Inflator;
- std::unique_ptr<i2p::data::GzipDeflator> m_Deflator;
+ i2p::data::GzipDeflator m_Deflator;
// for HTTP only
const decltype(m_Streams)& GetStreams () const { return m_Streams; };
@@ -336,11 +337,10 @@
int t = (timeout > MAX_RECEIVE_TIMEOUT) ? MAX_RECEIVE_TIMEOUT : timeout;
s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(t));
int left = timeout - t;
- auto self = s->shared_from_this();
- self->m_ReceiveTimer.async_wait (
- [self, buffer, handler, left](const boost::system::error_code & ec)
+ s->m_ReceiveTimer.async_wait (
+ [s, buffer, handler, left](const boost::system::error_code & ec)
{
- self->HandleReceiveTimer(ec, buffer, handler, left);
+ s->HandleReceiveTimer(ec, buffer, handler, left);
});
}
});
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Tag.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -80,6 +80,13 @@
return i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz);
}
+ uint8_t GetBit (int i) const
+ {
+ int pos = i >> 3; // /8
+ if (pos >= (int)sz) return 0;
+ return m_Buf[pos] & (0x80 >> (i & 0x07));
+ }
+
private:
union // 8 bytes aligned
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Timestamp.h
^
|
@@ -25,7 +25,7 @@
uint32_t GetHoursSinceEpoch ();
void GetCurrentDate (char * date); // returns date as YYYYMMDD string, 9 bytes
- void GetDateString (uint64_t timestamp, char * date); // timestap is seconds since epoch, returns date as YYYYMMDD string, 9 bytes
+ void GetDateString (uint64_t timestamp, char * date); // timestamp is seconds since epoch, returns date as YYYYMMDD string, 9 bytes
void AdjustTimeOffset (int64_t offset); // in seconds from current
class NTPTimeSync
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/TransitTunnel.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -20,16 +20,21 @@
namespace tunnel
{
TransitTunnel::TransitTunnel (uint32_t receiveTunnelID,
- const uint8_t * nextIdent, uint32_t nextTunnelID,
- const uint8_t * layerKey,const uint8_t * ivKey):
- TunnelBase (receiveTunnelID, nextTunnelID, nextIdent)
+ const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID,
+ const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey):
+ TunnelBase (receiveTunnelID, nextTunnelID, nextIdent),
+ m_LayerKey (layerKey), m_IVKey (ivKey)
{
- m_Encryption.SetKeys (layerKey, ivKey);
}
void TransitTunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
{
- m_Encryption.Encrypt (in->GetPayload () + 4, out->GetPayload () + 4);
+ if (!m_Encryption)
+ {
+ m_Encryption.reset (new i2p::crypto::TunnelEncryption);
+ m_Encryption->SetKeys (m_LayerKey, m_IVKey);
+ }
+ m_Encryption->Encrypt (in->GetPayload () + 4, out->GetPayload () + 4);
i2p::transport::transports.UpdateTotalTransitTransmittedBytes (TUNNEL_DATA_MSG_SIZE);
}
@@ -94,8 +99,8 @@
}
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
- const uint8_t * nextIdent, uint32_t nextTunnelID,
- const uint8_t * layerKey,const uint8_t * ivKey,
+ const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID,
+ const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey,
bool isGateway, bool isEndpoint)
{
if (isEndpoint)
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/TransitTunnel.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -28,18 +28,19 @@
public:
TransitTunnel (uint32_t receiveTunnelID,
- const uint8_t * nextIdent, uint32_t nextTunnelID,
- const uint8_t * layerKey,const uint8_t * ivKey);
+ const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID,
+ const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey);
virtual size_t GetNumTransmittedBytes () const { return 0; };
// implements TunnelBase
- void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
- void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg);
- void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
+ void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
+ void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
+ void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) override;
private:
- i2p::crypto::TunnelEncryption m_Encryption;
+ i2p::crypto::AESKey m_LayerKey, m_IVKey;
+ std::unique_ptr<i2p::crypto::TunnelEncryption> m_Encryption;
};
class TransitTunnelParticipant: public TransitTunnel
@@ -47,15 +48,15 @@
public:
TransitTunnelParticipant (uint32_t receiveTunnelID,
- const uint8_t * nextIdent, uint32_t nextTunnelID,
- const uint8_t * layerKey,const uint8_t * ivKey):
+ const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID,
+ const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey):
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
layerKey, ivKey), m_NumTransmittedBytes (0) {};
~TransitTunnelParticipant ();
- size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; };
- void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg);
- void FlushTunnelDataMsgs ();
+ size_t GetNumTransmittedBytes () const override { return m_NumTransmittedBytes; };
+ void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
+ void FlushTunnelDataMsgs () override;
private:
@@ -68,14 +69,14 @@
public:
TransitTunnelGateway (uint32_t receiveTunnelID,
- const uint8_t * nextIdent, uint32_t nextTunnelID,
- const uint8_t * layerKey,const uint8_t * ivKey):
+ const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID,
+ const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey):
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
layerKey, ivKey), m_Gateway(this) {};
- void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
- void FlushTunnelDataMsgs ();
- size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); };
+ void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
+ void FlushTunnelDataMsgs () override;
+ size_t GetNumTransmittedBytes () const override { return m_Gateway.GetNumSentBytes (); };
private:
@@ -88,15 +89,15 @@
public:
TransitTunnelEndpoint (uint32_t receiveTunnelID,
- const uint8_t * nextIdent, uint32_t nextTunnelID,
- const uint8_t * layerKey,const uint8_t * ivKey):
+ const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID,
+ const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey):
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey),
m_Endpoint (false) {}; // transit endpoint is always outbound
- void Cleanup () { m_Endpoint.Cleanup (); }
+ void Cleanup () override { m_Endpoint.Cleanup (); }
- void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg);
- size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }
+ void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
+ size_t GetNumTransmittedBytes () const override { return m_Endpoint.GetNumReceivedBytes (); }
private:
@@ -104,8 +105,8 @@
};
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
- const uint8_t * nextIdent, uint32_t nextTunnelID,
- const uint8_t * layerKey,const uint8_t * ivKey,
+ const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID,
+ const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey,
bool isGateway, bool isEndpoint);
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/TransportSession.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -27,7 +27,7 @@
const size_t IPV4_HEADER_SIZE = 20;
const size_t IPV6_HEADER_SIZE = 40;
const size_t UDP_HEADER_SIZE = 8;
-
+
class SignedData
{
public:
@@ -42,7 +42,7 @@
{
m_Stream.str("");
}
-
+
void Insert (const uint8_t * buf, size_t len)
{
m_Stream.write ((char *)buf, len);
@@ -68,18 +68,24 @@
std::stringstream m_Stream;
};
-
+
+ const int64_t TRANSPORT_SESSION_SLOWNESS_THRESHOLD = 500; // in milliseconds
+ const int64_t TRANSPORT_SESSION_MAX_HANDSHAKE_INTERVAL = 10000; // in milliseconds
+ const uint64_t TRANSPORT_SESSION_BANDWIDTH_UPDATE_MIN_INTERVAL = 5; // in seconds
class TransportSession
{
public:
TransportSession (std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout):
- m_NumSentBytes (0), m_NumReceivedBytes (0), m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout),
- m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ())
+ m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout), m_HandshakeInterval (0),
+ m_SendQueueSize (0), m_NumSentBytes (0), m_NumReceivedBytes (0),
+ m_LastBandWidthUpdateNumSentBytes (0), m_LastBandWidthUpdateNumReceivedBytes (0),
+ m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ()),
+ m_LastBandwidthUpdateTimestamp (m_LastActivityTimestamp), m_InBandwidth (0), m_OutBandwidth (0)
{
if (router)
m_RemoteIdentity = router->GetRouterIdentity ();
- m_CreationTime = m_LastActivityTimestamp;
+ m_CreationTime = m_LastActivityTimestamp;
}
virtual ~TransportSession () {};
@@ -99,31 +105,97 @@
}
size_t GetNumSentBytes () const { return m_NumSentBytes; };
+ void UpdateNumSentBytes (size_t len)
+ {
+ m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
+ m_NumSentBytes += len;
+ UpdateBandwidth ();
+ }
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
+ void UpdateNumReceivedBytes (size_t len)
+ {
+ m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
+ m_NumReceivedBytes += len;
+ UpdateBandwidth ();
+ }
+ size_t GetSendQueueSize () const { return m_SendQueueSize; };
+ void SetSendQueueSize (size_t s) { m_SendQueueSize = s; };
bool IsOutgoing () const { return m_IsOutgoing; };
-
+ bool IsSlow () const { return m_HandshakeInterval > TRANSPORT_SESSION_SLOWNESS_THRESHOLD &&
+ m_HandshakeInterval < TRANSPORT_SESSION_MAX_HANDSHAKE_INTERVAL; };
+ bool IsBandwidthExceeded (bool isHighBandwidth) const
+ {
+ auto limit = isHighBandwidth ? i2p::data::HIGH_BANDWIDTH_LIMIT*1024 : i2p::data::LOW_BANDWIDTH_LIMIT*1024; // convert to bytes
+ return std::max (m_InBandwidth, m_OutBandwidth) > limit;
+ }
+
int GetTerminationTimeout () const { return m_TerminationTimeout; };
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
bool IsTerminationTimeoutExpired (uint64_t ts) const
- { return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); };
+ {
+ return ts >= m_LastActivityTimestamp + GetTerminationTimeout () ||
+ ts + GetTerminationTimeout () < m_LastActivityTimestamp;
+ };
uint32_t GetCreationTime () const { return m_CreationTime; };
void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers
+
+ uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
+ void SetLastActivityTimestamp (uint64_t ts) { m_LastActivityTimestamp = ts; };
virtual uint32_t GetRelayTag () const { return 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:
+
+ void UpdateBandwidth ()
+ {
+ int64_t interval = m_LastActivityTimestamp - m_LastBandwidthUpdateTimestamp;
+ if (interval < 0 || interval > 60*10) // 10 minutes
+ {
+ // clock was adjusted, copy new values
+ m_LastBandWidthUpdateNumSentBytes = m_NumSentBytes;
+ m_LastBandWidthUpdateNumReceivedBytes = m_NumReceivedBytes;
+ m_LastBandwidthUpdateTimestamp = m_LastActivityTimestamp;
+ return;
+ }
+ if ((uint64_t)interval > TRANSPORT_SESSION_BANDWIDTH_UPDATE_MIN_INTERVAL)
+ {
+ m_OutBandwidth = (m_NumSentBytes - m_LastBandWidthUpdateNumSentBytes)/interval;
+ m_LastBandWidthUpdateNumSentBytes = m_NumSentBytes;
+ m_InBandwidth = (m_NumReceivedBytes - m_LastBandWidthUpdateNumReceivedBytes)/interval;
+ m_LastBandWidthUpdateNumReceivedBytes = m_NumReceivedBytes;
+ m_LastBandwidthUpdateTimestamp = m_LastActivityTimestamp;
+ }
+ }
+
protected:
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
mutable std::mutex m_RemoteIdentityMutex;
- size_t m_NumSentBytes, m_NumReceivedBytes;
bool m_IsOutgoing;
int m_TerminationTimeout;
- uint64_t m_LastActivityTimestamp;
uint32_t m_CreationTime; // seconds since epoch
+ int64_t m_HandshakeInterval; // in milliseconds between SessionRequest->SessionCreated or SessionCreated->SessionConfirmed
+
+ private:
+
+ size_t m_SendQueueSize, m_NumSentBytes, m_NumReceivedBytes,
+ m_LastBandWidthUpdateNumSentBytes, m_LastBandWidthUpdateNumReceivedBytes;
+ uint64_t m_LastActivityTimestamp, m_LastBandwidthUpdateTimestamp;
+ uint32_t m_InBandwidth, m_OutBandwidth;
};
+
+ // SOCKS5 proxy
+ const uint8_t SOCKS5_VER = 0x05;
+ const uint8_t SOCKS5_CMD_CONNECT = 0x01;
+ const uint8_t SOCKS5_CMD_UDP_ASSOCIATE = 0x03;
+ const uint8_t SOCKS5_ATYP_IPV4 = 0x01;
+ const uint8_t SOCKS5_ATYP_IPV6 = 0x04;
+ const size_t SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE = 10;
+ const size_t SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE = 22;
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Transports.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -136,12 +136,14 @@
Transports::Transports ():
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_SSUServer (nullptr), m_SSU2Server (nullptr), m_NTCP2Server (nullptr),
+ m_UpdateBandwidthTimer (nullptr), m_SSU2Server (nullptr), m_NTCP2Server (nullptr),
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_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0),
- m_LastTransitBandwidthUpdateBytes (0), m_LastBandwidthUpdateTime (0)
+ m_TotalSentBytes (0), m_TotalReceivedBytes (0), m_TotalTransitTransmittedBytes (0),
+ m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth (0),
+ m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), m_LastTransitBandwidthUpdateBytes (0),
+ m_InBandwidth15s (0), m_OutBandwidth15s (0), m_TransitBandwidth15s (0),
+ m_LastInBandwidth15sUpdateBytes (0), m_LastOutBandwidth15sUpdateBytes (0), m_LastTransitBandwidth15sUpdateBytes (0),
+ m_LastBandwidth15sUpdateTime (0)
{
}
@@ -152,12 +154,13 @@
{
delete m_PeerCleanupTimer; m_PeerCleanupTimer = nullptr;
delete m_PeerTestTimer; m_PeerTestTimer = nullptr;
+ delete m_UpdateBandwidthTimer; m_UpdateBandwidthTimer = nullptr;
delete m_Work; m_Work = nullptr;
delete m_Service; m_Service = nullptr;
}
}
- void Transports::Start (bool enableNTCP2, bool enableSSU, bool enableSSU2)
+ void Transports::Start (bool enableNTCP2, bool enableSSU2)
{
if (!m_Service)
{
@@ -165,8 +168,11 @@
m_Work = new boost::asio::io_service::work (*m_Service);
m_PeerCleanupTimer = new boost::asio::deadline_timer (*m_Service);
m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service);
+ m_UpdateBandwidthTimer = new boost::asio::deadline_timer (*m_Service);
}
+ bool ipv4; i2p::config::GetOption("ipv4", ipv4);
+ bool ipv6; i2p::config::GetOption("ipv6", ipv6);
i2p::config::GetOption("nat", m_IsNAT);
m_X25519KeysPairSupplier.Start ();
m_IsRunning = true;
@@ -190,38 +196,43 @@
m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port, proxyurl.user, proxyurl.pass);
i2p::context.SetStatus (eRouterStatusProxy);
+ if (ipv6)
+ i2p::context.SetStatusV6 (eRouterStatusProxy);
}
else
- LogPrint(eLogError, "Transports: Unsupported NTCP2 proxy URL ", ntcp2proxy);
+ LogPrint(eLogCritical, "Transports: Unsupported NTCP2 proxy URL ", ntcp2proxy);
}
else
- LogPrint(eLogError, "Transports: Invalid NTCP2 proxy URL ", ntcp2proxy);
+ LogPrint(eLogCritical, "Transports: Invalid NTCP2 proxy URL ", ntcp2proxy);
}
else
m_NTCP2Server = new NTCP2Server ();
}
- // create SSU server
- int ssuPort = 0;
- if (enableSSU)
- {
- auto& addresses = context.GetRouterInfo ().GetAddresses ();
- for (const auto& address: addresses)
- {
- if (!address) continue;
- if (address->transportStyle == RouterInfo::eTransportSSU)
- {
- ssuPort = address->port;
- m_SSUServer = new SSUServer (address->port);
- break;
+ // create SSU2 server
+ if (enableSSU2)
+ {
+ m_SSU2Server = new SSU2Server ();
+ std::string ssu2proxy; i2p::config::GetOption("ssu2.proxy", ssu2proxy);
+ if (!ssu2proxy.empty())
+ {
+ if (proxyurl.parse (ssu2proxy) && proxyurl.schema == "socks")
+ {
+ if (m_SSU2Server->SetProxy (proxyurl.host, proxyurl.port))
+ {
+ i2p::context.SetStatus (eRouterStatusProxy);
+ if (ipv6)
+ i2p::context.SetStatusV6 (eRouterStatusProxy);
+ }
+ else
+ LogPrint(eLogCritical, "Transports: Can't set SSU2 proxy ", ssu2proxy);
}
+ else
+ LogPrint(eLogCritical, "Transports: Invalid SSU2 proxy URL ", ssu2proxy);
}
}
- // create SSU2 server
- if (enableSSU2) m_SSU2Server = new SSU2Server ();
// bind to interfaces
- bool ipv4; i2p::config::GetOption("ipv4", ipv4);
if (ipv4)
{
std::string address; i2p::config::GetOption("address4", address);
@@ -232,13 +243,22 @@
if (!ec)
{
if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr);
- if (m_SSUServer) m_SSUServer->SetLocalAddress (addr);
if (m_SSU2Server) m_SSU2Server->SetLocalAddress (addr);
}
}
+
+ if (enableSSU2)
+ {
+ uint16_t mtu; i2p::config::GetOption ("ssu2.mtu4", mtu);
+ if (mtu)
+ {
+ if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE;
+ if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE;
+ i2p::context.SetMTU (mtu, true);
+ }
+ }
}
- bool ipv6; i2p::config::GetOption("ipv6", ipv6);
if (ipv6)
{
std::string address; i2p::config::GetOption("address6", address);
@@ -249,10 +269,20 @@
if (!ec)
{
if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr);
- if (m_SSUServer) m_SSUServer->SetLocalAddress (addr);
if (m_SSU2Server) m_SSU2Server->SetLocalAddress (addr);
}
}
+
+ if (enableSSU2)
+ {
+ uint16_t mtu; i2p::config::GetOption ("ssu2.mtu6", mtu);
+ if (mtu)
+ {
+ if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE;
+ if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE;
+ i2p::context.SetMTU (mtu, false);
+ }
+ }
}
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
@@ -271,26 +301,14 @@
// start servers
if (m_NTCP2Server) m_NTCP2Server->Start ();
if (m_SSU2Server) m_SSU2Server->Start ();
- if (m_SSUServer)
- {
- LogPrint (eLogInfo, "Transports: Start listening UDP port ", ssuPort);
- try
- {
- m_SSUServer->Start ();
- }
- catch (std::exception& ex )
- {
- LogPrint(eLogError, "Transports: Failed to bind to UDP port", ssuPort);
- m_SSUServer->Stop ();
- delete m_SSUServer;
- m_SSUServer = nullptr;
- }
- }
- if (m_SSUServer || m_SSU2Server) DetectExternalIP ();
+ if (m_SSU2Server) DetectExternalIP ();
- m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
+ m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5 * SESSION_CREATION_TIMEOUT));
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
+ m_UpdateBandwidthTimer->expires_from_now (boost::posix_time::seconds(1));
+ m_UpdateBandwidthTimer->async_wait (std::bind (&Transports::HandleUpdateBandwidthTimer, this, std::placeholders::_1));
+
if (m_IsNAT)
{
m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
@@ -303,12 +321,6 @@
if (m_PeerCleanupTimer) m_PeerCleanupTimer->cancel ();
if (m_PeerTestTimer) m_PeerTestTimer->cancel ();
m_Peers.clear ();
- if (m_SSUServer)
- {
- m_SSUServer->Stop ();
- delete m_SSUServer;
- m_SSUServer = nullptr;
- }
if (m_SSU2Server)
{
@@ -352,29 +364,44 @@
}
}
- void Transports::UpdateBandwidth ()
+ void Transports::HandleUpdateBandwidthTimer (const boost::system::error_code& ecode)
{
- uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
- if (m_LastBandwidthUpdateTime > 0)
+ if (ecode != boost::asio::error::operation_aborted)
{
- auto delta = ts - m_LastBandwidthUpdateTime;
- if (delta > 0)
+ uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
+
+ // updated every second
+ m_InBandwidth = m_TotalReceivedBytes - m_LastInBandwidthUpdateBytes;
+ m_OutBandwidth = m_TotalSentBytes - m_LastOutBandwidthUpdateBytes;
+ m_TransitBandwidth = m_TotalTransitTransmittedBytes - m_LastTransitBandwidthUpdateBytes;
+
+ m_LastInBandwidthUpdateBytes = m_TotalReceivedBytes;
+ m_LastOutBandwidthUpdateBytes = m_TotalSentBytes;
+ m_LastTransitBandwidthUpdateBytes = m_TotalTransitTransmittedBytes;
+
+ // updated every 15 seconds
+ auto delta = ts - m_LastBandwidth15sUpdateTime;
+ if (delta > 15 * 1000)
{
- m_InBandwidth = (m_TotalReceivedBytes - m_LastInBandwidthUpdateBytes)*1000/delta; // per second
- m_OutBandwidth = (m_TotalSentBytes - m_LastOutBandwidthUpdateBytes)*1000/delta; // per second
- m_TransitBandwidth = (m_TotalTransitTransmittedBytes - m_LastTransitBandwidthUpdateBytes)*1000/delta;
+ m_InBandwidth15s = (m_TotalReceivedBytes - m_LastInBandwidth15sUpdateBytes) * 1000 / delta;
+ m_OutBandwidth15s = (m_TotalSentBytes - m_LastOutBandwidth15sUpdateBytes) * 1000 / delta;
+ m_TransitBandwidth15s = (m_TotalTransitTransmittedBytes - m_LastTransitBandwidth15sUpdateBytes) * 1000 / delta;
+
+ m_LastBandwidth15sUpdateTime = ts;
+ m_LastInBandwidth15sUpdateBytes = m_TotalReceivedBytes;
+ m_LastOutBandwidth15sUpdateBytes = m_TotalSentBytes;
+ m_LastTransitBandwidth15sUpdateBytes = m_TotalTransitTransmittedBytes;
}
+
+ m_UpdateBandwidthTimer->expires_from_now (boost::posix_time::seconds(1));
+ m_UpdateBandwidthTimer->async_wait (std::bind (&Transports::HandleUpdateBandwidthTimer, this, std::placeholders::_1));
}
- m_LastBandwidthUpdateTime = ts;
- m_LastInBandwidthUpdateBytes = m_TotalReceivedBytes;
- m_LastOutBandwidthUpdateBytes = m_TotalSentBytes;
- m_LastTransitBandwidthUpdateBytes = m_TotalTransitTransmittedBytes;
}
bool Transports::IsBandwidthExceeded () const
{
auto limit = i2p::context.GetBandwidthLimit() * 1024; // convert to bytes
- auto bw = std::max (m_InBandwidth, m_OutBandwidth);
+ auto bw = std::max (m_InBandwidth15s, m_OutBandwidth15s);
return bw > limit;
}
@@ -417,8 +444,7 @@
{
auto ts = i2p::util::GetSecondsSinceEpoch ();
std::unique_lock<std::mutex> l(m_PeersMutex);
- it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},
- ts, ts + PEER_ROUTER_INFO_UPDATE_INTERVAL, {} })).first;
+ it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, {r, ts})).first;
}
connected = ConnectToPeer (ident, it->second);
}
@@ -432,8 +458,20 @@
it->second.sessions.front ()->SendI2NPMessages (msgs);
else
{
- if (it->second.delayedMessages.size () < MAX_NUM_DELAYED_MESSAGES)
+ auto sz = it->second.delayedMessages.size ();
+ if (sz < MAX_NUM_DELAYED_MESSAGES)
{
+ if (sz < CHECK_PROFILE_NUM_DELAYED_MESSAGES && sz + msgs.size () >= CHECK_PROFILE_NUM_DELAYED_MESSAGES)
+ {
+ auto profile = i2p::data::GetRouterProfile (ident);
+ if (profile && profile->IsUnreachable ())
+ {
+ LogPrint (eLogWarning, "Transports: Peer profile for ", ident.ToBase64 (), " reports unreachable. Dropped");
+ std::unique_lock<std::mutex> l(m_PeersMutex);
+ m_Peers.erase (it);
+ return;
+ }
+ }
for (auto& it1: msgs)
it->second.delayedMessages.push_back (it1);
}
@@ -450,131 +488,71 @@
bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer)
{
if (!peer.router) // reconnect
- peer.router = netdb.FindRouter (ident); // try to get new one from netdb
+ peer.SetRouter (netdb.FindRouter (ident)); // try to get new one from netdb
if (peer.router) // we have RI already
{
- if (peer.numAttempts < 2) // NTCP2, 0 - ipv6, 1 - ipv4
+ if (peer.priority.empty ())
+ SetPriority (peer);
+ while (peer.numAttempts < (int)peer.priority.size ())
{
- if (m_NTCP2Server) // we support NTCP2
+ auto tr = peer.priority[peer.numAttempts];
+ peer.numAttempts++;
+ switch (tr)
{
- std::shared_ptr<const RouterInfo::Address> address;
- if (!peer.numAttempts) // NTCP2 ipv6
+ case i2p::data::RouterInfo::eNTCP2V4:
+ case i2p::data::RouterInfo::eNTCP2V6:
{
- if (context.GetRouterInfo ().IsNTCP2V6 () && peer.router->IsReachableBy (RouterInfo::eNTCP2V6))
+ if (!m_NTCP2Server) continue;
+ std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eNTCP2V6) ?
+ peer.router->GetPublishedNTCP2V6Address () : peer.router->GetPublishedNTCP2V4Address ();
+ if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
+ address = nullptr;
+ if (address)
{
- address = peer.router->GetPublishedNTCP2V6Address ();
- if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
- address = nullptr;
+ auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
+ if( m_NTCP2Server->UsingProxy())
+ m_NTCP2Server->ConnectWithProxy(s);
+ else
+ m_NTCP2Server->Connect (s);
+ return true;
}
- peer.numAttempts++;
+ break;
}
- if (!address && peer.numAttempts == 1) // NTCP2 ipv4
+ case i2p::data::RouterInfo::eSSU2V4:
+ case i2p::data::RouterInfo::eSSU2V6:
{
- if (context.GetRouterInfo ().IsNTCP2 (true) && peer.router->IsReachableBy (RouterInfo::eNTCP2V4))
+ if (!m_SSU2Server) continue;
+ std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eSSU2V6) ?
+ peer.router->GetSSU2V6Address () : peer.router->GetSSU2V4Address ();
+ if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
+ address = nullptr;
+ if (address && address->IsReachableSSU ())
{
- address = peer.router->GetPublishedNTCP2V4Address ();
- if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
- address = nullptr;
+ if (m_SSU2Server->CreateSession (peer.router, address))
+ return true;
}
- peer.numAttempts++;
+ break;
}
- if (address)
+ case i2p::data::RouterInfo::eNTCP2V6Mesh:
{
- auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
- if( m_NTCP2Server->UsingProxy())
- m_NTCP2Server->ConnectWithProxy(s);
- else
- m_NTCP2Server->Connect (s);
- return true;
- }
- }
- else
- peer.numAttempts = 2; // switch to SSU
- }
- if (peer.numAttempts == 2 || peer.numAttempts == 3) // SSU2, 2 - ipv6, 3 - ipv4
- {
- if (m_SSU2Server)
- {
- std::shared_ptr<const RouterInfo::Address> address;
- if (peer.numAttempts == 2) // SSU2 ipv6
- {
- if (context.GetRouterInfo ().IsSSU2V6 () && peer.router->IsReachableBy (RouterInfo::eSSU2V6))
+ if (!m_NTCP2Server) continue;
+ auto address = peer.router->GetYggdrasilAddress ();
+ if (address)
{
- address = peer.router->GetSSU2V6Address ();
- if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
- address = nullptr;
- }
- peer.numAttempts++;
- }
- if (!address && peer.numAttempts == 3) // SSU2 ipv4
- {
- if (context.GetRouterInfo ().IsSSU2V4 () && peer.router->IsReachableBy (RouterInfo::eSSU2V4))
- {
- address = peer.router->GetSSU2V4Address ();
- if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
- address = nullptr;
- }
- peer.numAttempts++;
- }
- if (address && address->IsReachableSSU ())
- {
- if (m_SSU2Server->CreateSession (peer.router, address))
+ auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
+ m_NTCP2Server->Connect (s);
return true;
- }
- }
- else
- peer.numAttempts += 2; // switch to mesh
- }
- if (peer.numAttempts == 4) // Mesh
- {
- peer.numAttempts++;
- if (m_NTCP2Server && context.GetRouterInfo ().IsMesh () && peer.router->IsMesh ())
- {
- auto address = peer.router->GetYggdrasilAddress ();
- if (address)
- {
- auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
- m_NTCP2Server->Connect (s);
- return true;
- }
- }
- }
- if (peer.numAttempts == 5 || peer.numAttempts == 6) // SSU, 5 - ipv6, 6 - ipv4
- {
- if (m_SSUServer)
- {
- std::shared_ptr<const RouterInfo::Address> address;
- if (peer.numAttempts == 5) // SSU ipv6
- {
- if (context.GetRouterInfo ().IsSSUV6 () && peer.router->IsReachableBy (RouterInfo::eSSUV6))
- {
- address = peer.router->GetSSUV6Address ();
- if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
- address = nullptr;
- }
- peer.numAttempts++;
- }
- if (!address && peer.numAttempts == 6) // SSU ipv4
- {
- if (context.GetRouterInfo ().IsSSU (true) && peer.router->IsReachableBy (RouterInfo::eSSUV4))
- {
- address = peer.router->GetSSUAddress (true);
- if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
- address = nullptr;
}
- peer.numAttempts++;
- }
- if (address && address->IsReachableSSU ())
- {
- if (m_SSUServer->CreateSession (peer.router, address))
- return true;
+ break;
}
+ default:
+ LogPrint (eLogError, "Transports: Unknown transport ", (int)tr);
}
- else
- peer.numAttempts += 2;
}
- LogPrint (eLogInfo, "Transports: No compatble NTCP2 or SSU addresses available");
- i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed
+
+ LogPrint (eLogInfo, "Transports: No compatible addresses available");
+ if (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::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (ident);
@@ -589,6 +567,37 @@
return true;
}
+ void Transports::SetPriority (Peer& peer) const
+ {
+ static const std::vector<i2p::data::RouterInfo::SupportedTransports>
+ ntcp2Priority =
+ {
+ i2p::data::RouterInfo::eNTCP2V6,
+ i2p::data::RouterInfo::eNTCP2V4,
+ i2p::data::RouterInfo::eSSU2V6,
+ i2p::data::RouterInfo::eSSU2V4,
+ i2p::data::RouterInfo::eNTCP2V6Mesh
+ },
+ ssu2Priority =
+ {
+ i2p::data::RouterInfo::eSSU2V6,
+ i2p::data::RouterInfo::eSSU2V4,
+ i2p::data::RouterInfo::eNTCP2V6,
+ i2p::data::RouterInfo::eNTCP2V4,
+ i2p::data::RouterInfo::eNTCP2V6Mesh
+ };
+ if (!peer.router) return;
+ auto compatibleTransports = context.GetRouterInfo ().GetCompatibleTransports (false) &
+ peer.router->GetCompatibleTransports (true);
+ peer.numAttempts = 0;
+ peer.priority.clear ();
+ bool ssu2 = peer.router->GetProfile ()->IsReal () ? (rand () & 1) : false; // try NTCP2 if router is not confirmed real
+ const auto& priority = ssu2 ? ssu2Priority : ntcp2Priority;
+ for (auto transport: priority)
+ if (transport & compatibleTransports)
+ peer.priority.push_back (transport);
+ }
+
void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
{
m_Service->post (std::bind (&Transports::HandleRequestComplete, this, r, ident));
@@ -602,7 +611,7 @@
if (r)
{
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect");
- it->second.router = r;
+ it->second.SetRouter (r);
ConnectToPeer (ident, it->second);
}
else
@@ -622,7 +631,7 @@
i2p::context.SetStatus (eRouterStatusOK);
return;
}
- if (m_SSUServer || m_SSU2Server)
+ if (m_SSU2Server)
PeerTest ();
else
LogPrint (eLogWarning, "Transports: Can't detect external IP. SSU or SSU2 is not available");
@@ -630,101 +639,82 @@
void Transports::PeerTest (bool ipv4, bool ipv6)
{
- if (RoutesRestricted() || (!m_SSUServer && !m_SSU2Server)) return;
+ if (RoutesRestricted() || !m_SSU2Server || m_SSU2Server->UsesProxy ()) return;
if (ipv4 && i2p::context.SupportsV4 ())
{
LogPrint (eLogInfo, "Transports: Started peer test IPv4");
std::set<i2p::data::IdentHash> excluded;
excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
- if (m_SSUServer)
- {
- bool statusChanged = false;
- for (int i = 0; i < 5; i++)
- {
- auto router = i2p::data::netdb.GetRandomPeerTestRouter (true, excluded); // v4
- if (router)
- {
- auto addr = router->GetSSUAddress (true); // ipv4
- if (addr && !i2p::util::net::IsInReservedRange(addr->host))
- {
- if (!statusChanged)
- {
- statusChanged = true;
- i2p::context.SetStatus (eRouterStatusTesting); // first time only
- }
- m_SSUServer->CreateSession (router, addr, true); // peer test v4
- }
- excluded.insert (router->GetIdentHash ());
- }
- }
- if (!statusChanged)
- LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv4");
- }
- // SSU2
- if (m_SSU2Server)
+ int testDelay = 0;
+ for (int i = 0; i < 5; i++)
{
- excluded.clear ();
- excluded.insert (i2p::context.GetIdentHash ());
- for (int i = 0; i < 3; i++)
+ auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4
+ if (router)
{
- auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4
- if (router)
- {
- if (i2p::context.GetStatus () != eRouterStatusTesting)
- i2p::context.SetStatusSSU2 (eRouterStatusTesting);
+ if (!i2p::context.GetTesting ())
+ {
+ i2p::context.SetTesting (true);
+ // send first peer test immediately
m_SSU2Server->StartPeerTest (router, true);
- excluded.insert (router->GetIdentHash ());
- }
+ }
+ else
+ {
+ testDelay += PEER_TEST_DELAY_INTERVAL + rand() % PEER_TEST_DELAY_INTERVAL_VARIANCE;
+ if (m_Service)
+ {
+ auto delayTimer = std::make_shared<boost::asio::deadline_timer>(*m_Service);
+ delayTimer->expires_from_now (boost::posix_time::milliseconds (testDelay));
+ delayTimer->async_wait (
+ [this, router, delayTimer](const boost::system::error_code& ecode)
+ {
+ if (ecode != boost::asio::error::operation_aborted)
+ m_SSU2Server->StartPeerTest (router, true);
+ });
+ }
+ }
+ excluded.insert (router->GetIdentHash ());
}
}
+ if (excluded.size () <= 1)
+ LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv4");
}
if (ipv6 && i2p::context.SupportsV6 ())
{
LogPrint (eLogInfo, "Transports: Started peer test IPv6");
std::set<i2p::data::IdentHash> excluded;
excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
- if (m_SSUServer)
+ int testDelay = 0;
+ for (int i = 0; i < 5; i++)
{
- bool statusChanged = false;
- for (int i = 0; i < 5; i++)
+ auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6
+ if (router)
{
- auto router = i2p::data::netdb.GetRandomPeerTestRouter (false, excluded); // v6
- if (router)
- {
- auto addr = router->GetSSUV6Address ();
- if (addr && !i2p::util::net::IsInReservedRange(addr->host))
- {
- if (!statusChanged)
- {
- statusChanged = true;
- i2p::context.SetStatusV6 (eRouterStatusTesting); // first time only
- }
- m_SSUServer->CreateSession (router, addr, true); // peer test v6
- }
- excluded.insert (router->GetIdentHash ());
- }
- }
- if (!statusChanged)
- LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6");
- }
-
- // SSU2
- if (m_SSU2Server)
- {
- excluded.clear ();
- excluded.insert (i2p::context.GetIdentHash ());
- for (int i = 0; i < 3; i++)
- {
- auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6
- if (router)
- {
- if (i2p::context.GetStatusV6 () != eRouterStatusTesting)
- i2p::context.SetStatusV6SSU2 (eRouterStatusTesting);
+ if (!i2p::context.GetTestingV6 ())
+ {
+ i2p::context.SetTestingV6 (true);
+ // send first peer test immediately
m_SSU2Server->StartPeerTest (router, false);
- excluded.insert (router->GetIdentHash ());
+ }
+ else
+ {
+ testDelay += PEER_TEST_DELAY_INTERVAL + rand() % PEER_TEST_DELAY_INTERVAL_VARIANCE;
+ if (m_Service)
+ {
+ auto delayTimer = std::make_shared<boost::asio::deadline_timer>(*m_Service);
+ delayTimer->expires_from_now (boost::posix_time::milliseconds (testDelay));
+ delayTimer->async_wait (
+ [this, router, delayTimer](const boost::system::error_code& ecode)
+ {
+ if (ecode != boost::asio::error::operation_aborted)
+ m_SSU2Server->StartPeerTest (router, false);
+ });
+ }
}
+ excluded.insert (router->GetIdentHash ());
}
}
+ if (excluded.size () <= 1)
+ LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6");
}
}
@@ -748,6 +738,25 @@
auto it = m_Peers.find (ident);
if (it != m_Peers.end ())
{
+ if (it->second.numAttempts > 1)
+ {
+ // exclude failed transports
+ i2p::data::RouterInfo::CompatibleTransports transports = 0;
+ int numExcluded = it->second.numAttempts - 1;
+ if (numExcluded > (int)it->second.priority.size ()) numExcluded = it->second.priority.size ();
+ for (int i = 0; i < numExcluded; i++)
+ transports |= it->second.priority[i];
+ i2p::data::netdb.ExcludeReachableTransports (ident, transports);
+ }
+ if (it->second.router && it->second.numAttempts)
+ {
+ auto transport = it->second.priority[it->second.numAttempts-1];
+ if (transport == i2p::data::RouterInfo::eNTCP2V4 ||
+ transport == i2p::data::RouterInfo::eNTCP2V6 || transport == i2p::data::RouterInfo::eNTCP2V6Mesh)
+ it->second.router->GetProfile ()->Connected (); // outgoing NTCP2 connection if always real
+ i2p::data::netdb.SetUnreachable (ident, false); // clear unreachable
+ }
+ it->second.numAttempts = 0;
it->second.router = nullptr; // we don't need RouterInfo after successive connect
bool sendDatabaseStore = true;
if (it->second.delayedMessages.size () > 0)
@@ -766,7 +775,7 @@
session->SendI2NPMessages (it->second.delayedMessages);
it->second.delayedMessages.clear ();
}
- else // incoming connection
+ else // incoming connection or peer test
{
if(RoutesRestricted() && ! IsRestrictedPeer(ident)) {
// not trusted
@@ -774,11 +783,15 @@
session->Done();
return;
}
- session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore
+ if (!session->IsOutgoing ()) // incoming
+ 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 ();
std::unique_lock<std::mutex> l(m_PeersMutex);
- m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session },
- ts, ts + PEER_ROUTER_INFO_UPDATE_INTERVAL, {} }));
+ auto it = m_Peers.insert (std::make_pair (ident, Peer{ r, ts })).first;
+ it->second.sessions.push_back (session);
+ it->second.router = nullptr;
}
});
}
@@ -827,14 +840,20 @@
auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = m_Peers.begin (); it != m_Peers.end (); )
{
- if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT)
+ it->second.sessions.remove_if (
+ [](std::shared_ptr<TransportSession> session)->bool
+ {
+ return !session || !session->IsEstablished ();
+ });
+ if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT)
{
LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
- auto profile = i2p::data::GetRouterProfile(it->first);
- if (profile)
- {
- profile->TunnelNonReplied();
- }
+ /* if (!it->second.router)
+ {
+ // if router for ident not found mark it unreachable
+ auto profile = i2p::data::GetRouterProfile (it->first);
+ if (profile) profile->Unreachable ();
+ } */
std::unique_lock<std::mutex> l(m_PeersMutex);
it = m_Peers.erase (it);
}
@@ -845,19 +864,22 @@
auto session = it->second.sessions.front ();
if (session)
session->SendLocalRouterInfo (true);
- it->second.nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL +
+ it->second.nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL +
rand () % PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE;
}
++it;
}
}
- UpdateBandwidth (); // TODO: use separate timer(s) for it
- bool ipv4Testing = i2p::context.GetStatus () == eRouterStatusTesting;
- bool ipv6Testing = i2p::context.GetStatusV6 () == eRouterStatusTesting;
- // if still testing, repeat peer test
+ bool ipv4Testing = i2p::context.GetTesting ();
+ if (!ipv4Testing)
+ ipv4Testing = i2p::context.GetRouterInfo ().IsSSU2V4 () && (i2p::context.GetStatus() == eRouterStatusUnknown);
+ bool ipv6Testing = i2p::context.GetTestingV6 ();
+ if (!ipv6Testing)
+ ipv6Testing = i2p::context.GetRouterInfo ().IsSSU2V6 () && (i2p::context.GetStatusV6() == eRouterStatusUnknown);
+ // if still testing or unknown, repeat peer test
if (ipv4Testing || ipv6Testing)
PeerTest (ipv4Testing, ipv6Testing);
- m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(3*SESSION_CREATION_TIMEOUT));
+ m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(3 * SESSION_CREATION_TIMEOUT));
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
}
}
@@ -872,18 +894,104 @@
}
}
- std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer () const
+ template<typename Filter>
+ std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (Filter filter) const
{
- if (m_Peers.empty ()) return nullptr;
+ if (m_Peers.empty()) return nullptr;
+ bool found = false;
i2p::data::IdentHash ident;
{
+ uint16_t inds[3];
+ RAND_bytes ((uint8_t *)inds, sizeof (inds));
std::unique_lock<std::mutex> l(m_PeersMutex);
+ auto count = m_Peers.size ();
+ if(count == 0) return nullptr;
+ inds[0] %= count;
auto it = m_Peers.begin ();
- std::advance (it, rand () % m_Peers.size ());
- if (it == m_Peers.end () || it->second.router) return nullptr; // not connected
- ident = it->first;
+ std::advance (it, inds[0]);
+ // try random peer
+ if (it != m_Peers.end () && filter (it->second))
+ {
+ ident = it->first;
+ found = true;
+ }
+ else
+ {
+ // try some peers around
+ auto it1 = m_Peers.begin ();
+ if (inds[0])
+ {
+ // before
+ inds[1] %= inds[0];
+ std::advance (it1, (inds[1] + inds[0])/2);
+ }
+ else
+ it1 = it;
+ auto it2 = it;
+ if (inds[0] < m_Peers.size () - 1)
+ {
+ // after
+ inds[2] %= (m_Peers.size () - 1 - inds[0]); inds[2] /= 2;
+ std::advance (it2, inds[2]);
+ }
+ // it1 - from, it2 - to
+ it = it1;
+ while (it != it2 && it != m_Peers.end ())
+ {
+ if (filter (it->second))
+ {
+ ident = it->first;
+ found = true;
+ break;
+ }
+ it++;
+ }
+ if (!found)
+ {
+ // still not found, try from the beginning
+ it = m_Peers.begin ();
+ while (it != it1 && it != m_Peers.end ())
+ {
+ if (filter (it->second))
+ {
+ ident = it->first;
+ found = true;
+ break;
+ }
+ it++;
+ }
+ if (!found)
+ {
+ // still not found, try to the beginning
+ it = it2;
+ while (it != m_Peers.end ())
+ {
+ if (filter (it->second))
+ {
+ ident = it->first;
+ found = true;
+ break;
+ }
+ it++;
+ }
+ }
+ }
+ }
}
- return i2p::data::netdb.FindRouter (ident);
+ return found ? i2p::data::netdb.FindRouter (ident) : nullptr;
+ }
+
+ std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (bool isHighBandwidth) const
+ {
+ return GetRandomPeer (
+ [isHighBandwidth](const Peer& peer)->bool
+ {
+ // connected, not overloaded and not slow
+ return !peer.router && !peer.sessions.empty () && peer.isReachable &&
+ peer.sessions.front ()->GetSendQueueSize () <= PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE &&
+ !peer.sessions.front ()->IsSlow () && !peer.sessions.front ()->IsBandwidthExceeded (peer.isHighBandwidth) &&
+ (!isHighBandwidth || peer.isHighBandwidth);
+ });
}
void Transports::RestrictRoutesToFamilies(const std::set<std::string>& families)
@@ -975,5 +1083,119 @@
i2p::context.SetError (eRouterErrorOffline);
}
}
+
+ void InitAddressFromIface ()
+ {
+ bool ipv6; i2p::config::GetOption("ipv6", ipv6);
+ bool ipv4; i2p::config::GetOption("ipv4", ipv4);
+
+ // ifname -> address
+ std::string ifname; i2p::config::GetOption("ifname", ifname);
+ if (ipv4 && i2p::config::IsDefault ("address4"))
+ {
+ std::string ifname4; i2p::config::GetOption("ifname4", ifname4);
+ if (!ifname4.empty ())
+ i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname4, false).to_string ()); // v4
+ else if (!ifname.empty ())
+ i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname, false).to_string ()); // v4
+ }
+ if (ipv6 && i2p::config::IsDefault ("address6"))
+ {
+ std::string ifname6; i2p::config::GetOption("ifname6", ifname6);
+ if (!ifname6.empty ())
+ i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname6, true).to_string ()); // v6
+ else if (!ifname.empty ())
+ i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname, true).to_string ()); // v6
+ }
+ }
+
+ void InitTransports ()
+ {
+ bool ipv6; i2p::config::GetOption("ipv6", ipv6);
+ bool ipv4; i2p::config::GetOption("ipv4", ipv4);
+ bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
+ uint16_t port; i2p::config::GetOption("port", port);
+
+ boost::asio::ip::address_v6 yggaddr;
+ if (ygg)
+ {
+ std::string yggaddress; i2p::config::GetOption ("meshnets.yggaddress", yggaddress);
+ if (!yggaddress.empty ())
+ {
+ yggaddr = boost::asio::ip::address_v6::from_string (yggaddress);
+ if (yggaddr.is_unspecified () || !i2p::util::net::IsYggdrasilAddress (yggaddr) ||
+ !i2p::util::net::IsLocalAddress (yggaddr))
+ {
+ LogPrint(eLogWarning, "Transports: Can't find Yggdrasil address ", yggaddress);
+ ygg = false;
+ }
+ }
+ else
+ {
+ yggaddr = i2p::util::net::GetYggdrasilAddress ();
+ if (yggaddr.is_unspecified ())
+ {
+ LogPrint(eLogWarning, "Transports: Yggdrasil is not running. Disabled");
+ ygg = false;
+ }
+ }
+ }
+
+ if (!i2p::config::IsDefault("port"))
+ {
+ LogPrint(eLogInfo, "Transports: Accepting incoming connections at port ", port);
+ i2p::context.UpdatePort (port);
+ }
+ i2p::context.SetSupportsV6 (ipv6);
+ i2p::context.SetSupportsV4 (ipv4);
+ i2p::context.SetSupportsMesh (ygg, yggaddr);
+
+ bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
+ if (ntcp2)
+ {
+ bool published; i2p::config::GetOption("ntcp2.published", published);
+ if (published)
+ {
+ std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy);
+ if (!ntcp2proxy.empty ()) published = false;
+ }
+ if (published)
+ {
+ uint16_t ntcp2port; i2p::config::GetOption("ntcp2.port", ntcp2port);
+ if (!ntcp2port) ntcp2port = port; // use standard port
+ i2p::context.PublishNTCP2Address (ntcp2port, true, ipv4, ipv6, false); // publish
+ if (ipv6)
+ {
+ std::string ipv6Addr; i2p::config::GetOption("ntcp2.addressv6", ipv6Addr);
+ auto addr = boost::asio::ip::address_v6::from_string (ipv6Addr);
+ if (!addr.is_unspecified () && addr != boost::asio::ip::address_v6::any ())
+ i2p::context.UpdateNTCP2V6Address (addr); // set ipv6 address if configured
+ }
+ }
+ else
+ i2p::context.PublishNTCP2Address (port, false, ipv4, ipv6, false); // unpublish
+ }
+ if (ygg)
+ {
+ i2p::context.PublishNTCP2Address (port, true, false, false, true);
+ i2p::context.UpdateNTCP2V6Address (yggaddr);
+ if (!ipv4 && !ipv6)
+ i2p::context.SetStatus (eRouterStatusMesh);
+ }
+ bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
+ if (ssu2 && i2p::config::IsDefault ("ssu2.enabled") && !ipv4 && !ipv6)
+ ssu2 = false; // don't enable ssu2 for yggdrasil only router
+ if (ssu2)
+ {
+ uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port);
+ if (!ssu2port && port) ssu2port = port;
+ bool published; i2p::config::GetOption("ssu2.published", published);
+ if (published)
+ i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish
+ else
+ i2p::context.PublishSSU2Address (ssu2port, false, ipv4, ipv6); // unpublish
+ }
+
+ }
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Transports.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -21,7 +21,6 @@
#include <atomic>
#include <boost/asio.hpp>
#include "TransportSession.h"
-#include "SSU.h"
#include "SSU2.h"
#include "NTCP2.h"
#include "RouterInfo.h"
@@ -62,8 +61,9 @@
};
typedef EphemeralKeysSupplier<i2p::crypto::X25519Keys> X25519KeysPairSupplier;
- const int PEER_ROUTER_INFO_UPDATE_INTERVAL = 31*60; // in seconds
- const int PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE = 7*60; // in seconds
+ const int PEER_ROUTER_INFO_UPDATE_INTERVAL = 31*60; // in seconds
+ const int PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE = 7*60; // in seconds
+ const size_t PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE = 25;
struct Peer
{
int numAttempts;
@@ -71,17 +71,44 @@
std::list<std::shared_ptr<TransportSession> > sessions;
uint64_t creationTime, nextRouterInfoUpdateTime;
std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
+ std::vector<i2p::data::RouterInfo::SupportedTransports> priority;
+ bool isHighBandwidth, isReachable;
+
+ Peer (std::shared_ptr<const i2p::data::RouterInfo> r, uint64_t ts):
+ numAttempts (0), router (r), creationTime (ts),
+ nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL),
+ isHighBandwidth (false), isReachable (false)
+ {
+ if (router)
+ {
+ isHighBandwidth = router->IsHighBandwidth ();
+ isReachable = (bool)router->GetCompatibleTransports (true);
+ }
+ }
void Done ()
{
for (auto& it: sessions)
it->Done ();
}
+
+ void SetRouter (std::shared_ptr<const i2p::data::RouterInfo> r)
+ {
+ router = r;
+ if (router)
+ {
+ isHighBandwidth = router->IsHighBandwidth ();
+ isReachable = (bool)router->GetCompatibleTransports (true);
+ }
+ }
};
const uint64_t SESSION_CREATION_TIMEOUT = 15; // in seconds
const int PEER_TEST_INTERVAL = 71; // in minutes
+ const int PEER_TEST_DELAY_INTERVAL = 20; // in milliseconds
+ 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
class Transports
{
public:
@@ -89,10 +116,9 @@
Transports ();
~Transports ();
- void Start (bool enableNTCP2=true, bool enableSSU=true, bool enableSSU2=false);
+ void Start (bool enableNTCP2=true, bool enableSSU2=true);
void Stop ();
- bool IsBoundSSU() const { return m_SSUServer != nullptr; }
bool IsBoundSSU2() const { return m_SSU2Server != nullptr; }
bool IsBoundNTCP2() const { return m_NTCP2Server != nullptr; }
@@ -119,10 +145,13 @@
uint32_t GetInBandwidth () const { return m_InBandwidth; };
uint32_t GetOutBandwidth () const { return m_OutBandwidth; };
uint32_t GetTransitBandwidth () const { return m_TransitBandwidth; };
+ uint32_t GetInBandwidth15s () const { return m_InBandwidth15s; };
+ uint32_t GetOutBandwidth15s () const { return m_OutBandwidth15s; };
+ uint32_t GetTransitBandwidth15s () const { return m_TransitBandwidth15s; };
bool IsBandwidthExceeded () const;
bool IsTransitBandwidthExceeded () const;
size_t GetNumPeers () const { return m_Peers.size (); };
- std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer () const;
+ std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer (bool isHighBandwidth) const;
/** get a trusted first hop for restricted routes */
std::shared_ptr<const i2p::data::RouterInfo> GetRestrictedPeer() const;
@@ -147,12 +176,16 @@
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident);
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
+ void SetPriority (Peer& peer) const;
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
void HandlePeerTestTimer (const boost::system::error_code& ecode);
+ void HandleUpdateBandwidthTimer (const boost::system::error_code& ecode);
- void UpdateBandwidth ();
void DetectExternalIP ();
+ template<typename Filter>
+ std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer (Filter filter) const;
+
private:
volatile bool m_IsOnline;
@@ -160,9 +193,8 @@
std::thread * m_Thread;
boost::asio::io_service * m_Service;
boost::asio::io_service::work * m_Work;
- boost::asio::deadline_timer * m_PeerCleanupTimer, * m_PeerTestTimer;
+ boost::asio::deadline_timer * m_PeerCleanupTimer, * m_PeerTestTimer, * m_UpdateBandwidthTimer;
- SSUServer * m_SSUServer;
SSU2Server * m_SSU2Server;
NTCP2Server * m_NTCP2Server;
mutable std::mutex m_PeersMutex;
@@ -171,9 +203,15 @@
X25519KeysPairSupplier m_X25519KeysPairSupplier;
std::atomic<uint64_t> m_TotalSentBytes, m_TotalReceivedBytes, m_TotalTransitTransmittedBytes;
- uint32_t m_InBandwidth, m_OutBandwidth, m_TransitBandwidth; // bytes per second
+
+ // Bandwidth per second
+ uint32_t m_InBandwidth, m_OutBandwidth, m_TransitBandwidth;
uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes, m_LastTransitBandwidthUpdateBytes;
- uint64_t m_LastBandwidthUpdateTime;
+
+ // Bandwidth every 15 seconds
+ uint32_t m_InBandwidth15s, m_OutBandwidth15s, m_TransitBandwidth15s;
+ uint64_t m_LastInBandwidth15sUpdateBytes, m_LastOutBandwidth15sUpdateBytes, m_LastTransitBandwidth15sUpdateBytes;
+ uint64_t m_LastBandwidth15sUpdateTime;
/** which router families to trust for first hops */
std::vector<i2p::data::FamilyID> m_TrustedFamilies;
@@ -188,13 +226,15 @@
public:
// for HTTP only
- const SSUServer * GetSSUServer () const { return m_SSUServer; };
const NTCP2Server * GetNTCP2Server () const { return m_NTCP2Server; };
const SSU2Server * GetSSU2Server () const { return m_SSU2Server; };
const decltype(m_Peers)& GetPeers () const { return m_Peers; };
};
extern Transports transports;
+
+ void InitAddressFromIface ();
+ void InitTransports ();
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Tunnel.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -103,7 +103,7 @@
if (msg1) msg = msg1;
}
}
- outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg);
+ outboundTunnel->SendTunnelDataMsgTo (GetNextIdentHash (), 0, msg);
}
else
{
@@ -266,7 +266,7 @@
}
}
- void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg)
+ void OutboundTunnel::SendTunnelDataMsgTo (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg)
{
TunnelMessageBlock block;
if (gwHash)
@@ -284,10 +284,10 @@
block.deliveryType = eDeliveryTypeLocal;
block.data = msg;
- SendTunnelDataMsg ({block});
+ SendTunnelDataMsgs ({block});
}
- void OutboundTunnel::SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs)
+ void OutboundTunnel::SendTunnelDataMsgs (const std::vector<TunnelMessageBlock>& msgs)
{
std::unique_lock<std::mutex> l(m_SendMutex);
for (auto& it : msgs)
@@ -306,7 +306,7 @@
{
}
- void ZeroHopsOutboundTunnel::SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs)
+ void ZeroHopsOutboundTunnel::SendTunnelDataMsgs (const std::vector<TunnelMessageBlock>& msgs)
{
for (auto& msg : msgs)
{
@@ -331,13 +331,15 @@
Tunnels tunnels;
- Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr),
- m_NumSuccesiveTunnelCreations (0), m_NumFailedTunnelCreations (0)
+ Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr), m_MaxNumTransitTunnels (DEFAULT_MAX_NUM_TRANSIT_TUNNELS),
+ m_TotalNumSuccesiveTunnelCreations (0), m_TotalNumFailedTunnelCreations (0), // for normal average
+ m_TunnelCreationSuccessRate (TCSR_START_VALUE), m_TunnelCreationAttemptsNum(0)
{
}
Tunnels::~Tunnels ()
{
+ DeleteTunnelPool(m_ExploratoryPool);
}
std::shared_ptr<TunnelBase> Tunnels::GetTunnel (uint32_t tunnelID)
@@ -433,12 +435,16 @@
}
}
- void Tunnels::AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel)
+ bool Tunnels::AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel)
{
if (m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second)
m_TransitTunnels.push_back (tunnel);
else
+ {
LogPrint (eLogError, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " already exists");
+ return false;
+ }
+ return true;
}
void Tunnels::Start ()
@@ -472,6 +478,7 @@
auto msg = m_Queue.GetNextWithTimeout (1000); // 1 sec
if (msg)
{
+ int numMsgs = 0;
uint32_t prevTunnelID = 0, tunnelID = 0;
std::shared_ptr<TunnelBase> prevTunnel;
do
@@ -509,17 +516,18 @@
case eI2NPShortTunnelBuildReply:
case eI2NPTunnelBuild:
case eI2NPTunnelBuildReply:
- HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
+ HandleTunnelBuildI2NPMessage (msg);
break;
default:
LogPrint (eLogWarning, "Tunnel: Unexpected message type ", (int) typeID);
}
- msg = m_Queue.Get ();
+ msg = (numMsgs <= MAX_TUNNEL_MSGS_BATCH_SIZE) ? m_Queue.Get () : nullptr;
if (msg)
{
prevTunnelID = tunnelID;
prevTunnel = tunnel;
+ numMsgs++;
}
else if (tunnel)
tunnel->FlushTunnelDataMsgs ();
@@ -530,17 +538,20 @@
if (i2p::transport::transports.IsOnline())
{
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
- if (ts - lastTs >= 15) // manage tunnels every 15 seconds
+ if (ts - lastTs >= TUNNEL_MANAGE_INTERVAL || // manage tunnels every 15 seconds
+ ts + TUNNEL_MANAGE_INTERVAL < lastTs)
{
- ManageTunnels ();
+ ManageTunnels (ts);
lastTs = ts;
}
- if (ts - lastPoolsTs >= 5) // manage pools every 5 seconds
+ if (ts - lastPoolsTs >= TUNNEL_POOLS_MANAGE_INTERVAL || // manage pools every 5 seconds
+ ts + TUNNEL_POOLS_MANAGE_INTERVAL < lastPoolsTs)
{
ManageTunnelPools (ts);
lastPoolsTs = ts;
}
- if (ts - lastMemoryPoolTs >= 120) // manage memory pool every 2 minutes
+ if (ts - lastMemoryPoolTs >= TUNNEL_MEMORY_POOL_MANAGE_INTERVAL ||
+ ts + TUNNEL_MEMORY_POOL_MANAGE_INTERVAL < lastMemoryPoolTs) // manage memory pool every 2 minutes
{
m_I2NPTunnelEndpointMessagesMemoryPool.CleanUpMt ();
m_I2NPTunnelMessagesMemoryPool.CleanUpMt ();
@@ -575,39 +586,46 @@
auto typeID = msg->GetTypeID ();
LogPrint (eLogDebug, "Tunnel: Gateway of ", (int) len, " bytes for tunnel ", tunnel->GetTunnelID (), ", msg type ", (int)typeID);
- if (IsRouterInfoMsg (msg) || typeID == eI2NPDatabaseSearchReply)
- // transit DatabaseStore my contain new/updated RI
- // or DatabaseSearchReply with new routers
+ if (typeID == eI2NPDatabaseSearchReply)
+ // DatabaseSearchReply with new routers
i2p::data::netdb.PostI2NPMsg (CopyI2NPMessage (msg));
+ else if (IsRouterInfoMsg (msg))
+ {
+ // transit DatabaseStore might contain new/updated RI
+ auto m = CopyI2NPMessage (msg);
+ if (bufbe32toh (m->GetPayload () + DATABASE_STORE_REPLY_TOKEN_OFFSET))
+ memset (m->GetPayload () + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0xFF, 4); // fake replyToken meaning no reply
+ i2p::data::netdb.PostI2NPMsg (m);
+ }
tunnel->SendTunnelDataMsg (msg);
}
- void Tunnels::ManageTunnels ()
+ void Tunnels::ManageTunnels (uint64_t ts)
{
- ManagePendingTunnels ();
- ManageInboundTunnels ();
- ManageOutboundTunnels ();
- ManageTransitTunnels ();
+ ManagePendingTunnels (ts);
+ ManageInboundTunnels (ts);
+ ManageOutboundTunnels (ts);
+ ManageTransitTunnels (ts);
}
- void Tunnels::ManagePendingTunnels ()
+ void Tunnels::ManagePendingTunnels (uint64_t ts)
{
- ManagePendingTunnels (m_PendingInboundTunnels);
- ManagePendingTunnels (m_PendingOutboundTunnels);
+ ManagePendingTunnels (m_PendingInboundTunnels, ts);
+ ManagePendingTunnels (m_PendingOutboundTunnels, ts);
}
template<class PendingTunnels>
- void Tunnels::ManagePendingTunnels (PendingTunnels& pendingTunnels)
+ void Tunnels::ManagePendingTunnels (PendingTunnels& pendingTunnels, uint64_t ts)
{
// check pending tunnel. delete failed or timeout
- uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = pendingTunnels.begin (); it != pendingTunnels.end ();)
{
auto tunnel = it->second;
switch (tunnel->GetState ())
{
case eTunnelStatePending:
- if (ts > tunnel->GetCreationTime () + TUNNEL_CREATION_TIMEOUT)
+ if (ts > tunnel->GetCreationTime () + TUNNEL_CREATION_TIMEOUT ||
+ ts + TUNNEL_CREATION_TIMEOUT < tunnel->GetCreationTime ())
{
LogPrint (eLogDebug, "Tunnel: Pending build request ", it->first, " timeout, deleted");
// update stats
@@ -628,7 +646,7 @@
}
// delete
it = pendingTunnels.erase (it);
- m_NumFailedTunnelCreations++;
+ FailedTunnelCreation();
}
else
++it;
@@ -636,7 +654,7 @@
case eTunnelStateBuildFailed:
LogPrint (eLogDebug, "Tunnel: Pending build request ", it->first, " failed, deleted");
it = pendingTunnels.erase (it);
- m_NumFailedTunnelCreations++;
+ FailedTunnelCreation();
break;
case eTunnelStateBuildReplyReceived:
// intermediate state, will be either established of build failed
@@ -645,56 +663,53 @@
default:
// success
it = pendingTunnels.erase (it);
- m_NumSuccesiveTunnelCreations++;
+ SuccesiveTunnelCreation();
}
}
}
- void Tunnels::ManageOutboundTunnels ()
+ void Tunnels::ManageOutboundTunnels (uint64_t ts)
{
- uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
+ for (auto it = m_OutboundTunnels.begin (); it != m_OutboundTunnels.end ();)
{
- for (auto it = m_OutboundTunnels.begin (); it != m_OutboundTunnels.end ();)
+ auto tunnel = *it;
+ if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
- auto tunnel = *it;
- if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
- {
- LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired");
- auto pool = tunnel->GetTunnelPool ();
- if (pool)
- pool->TunnelExpired (tunnel);
- // we don't have outbound tunnels in m_Tunnels
- it = m_OutboundTunnels.erase (it);
- }
- else
+ LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired");
+ auto pool = tunnel->GetTunnelPool ();
+ if (pool)
+ pool->TunnelExpired (tunnel);
+ // we don't have outbound tunnels in m_Tunnels
+ it = m_OutboundTunnels.erase (it);
+ }
+ else
+ {
+ if (tunnel->IsEstablished ())
{
- if (tunnel->IsEstablished ())
+ if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
- if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
+ auto pool = tunnel->GetTunnelPool ();
+ // let it die if the tunnel pool has been reconfigured and this is old
+ if (pool && tunnel->GetNumHops() == pool->GetNumOutboundHops())
{
- auto pool = tunnel->GetTunnelPool ();
- // let it die if the tunnel pool has been reconfigured and this is old
- if (pool && tunnel->GetNumHops() == pool->GetNumOutboundHops())
- {
- tunnel->SetRecreated (true);
- pool->RecreateOutboundTunnel (tunnel);
- }
+ tunnel->SetRecreated (true);
+ pool->RecreateOutboundTunnel (tunnel);
}
- if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
- tunnel->SetState (eTunnelStateExpiring);
}
- ++it;
+ if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
+ tunnel->SetState (eTunnelStateExpiring);
}
+ ++it;
}
}
if (m_OutboundTunnels.size () < 3)
{
- // trying to create one more oubound tunnel
+ // trying to create one more outbound tunnel
auto inboundTunnel = GetNextInboundTunnel ();
auto router = i2p::transport::transports.RoutesRestricted() ?
i2p::transport::transports.GetRestrictedPeer() :
- i2p::data::netdb.GetRandomRouter (i2p::context.GetSharedRouterInfo (), false); // reachable by us
+ i2p::data::netdb.GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, true); // reachable by us
if (!inboundTunnel || !router) return;
LogPrint (eLogDebug, "Tunnel: Creating one hop outbound tunnel");
CreateTunnel<OutboundTunnel> (
@@ -704,44 +719,42 @@
}
}
- void Tunnels::ManageInboundTunnels ()
+ void Tunnels::ManageInboundTunnels (uint64_t ts)
{
- uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
+ for (auto it = m_InboundTunnels.begin (); it != m_InboundTunnels.end ();)
{
- for (auto it = m_InboundTunnels.begin (); it != m_InboundTunnels.end ();)
+ auto tunnel = *it;
+ if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT ||
+ ts + TUNNEL_EXPIRATION_TIMEOUT < tunnel->GetCreationTime ())
{
- auto tunnel = *it;
- if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
- {
- LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired");
- auto pool = tunnel->GetTunnelPool ();
- if (pool)
- pool->TunnelExpired (tunnel);
- m_Tunnels.erase (tunnel->GetTunnelID ());
- it = m_InboundTunnels.erase (it);
- }
- else
+ LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired");
+ auto pool = tunnel->GetTunnelPool ();
+ if (pool)
+ pool->TunnelExpired (tunnel);
+ m_Tunnels.erase (tunnel->GetTunnelID ());
+ it = m_InboundTunnels.erase (it);
+ }
+ else
+ {
+ if (tunnel->IsEstablished ())
{
- if (tunnel->IsEstablished ())
+ if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
- if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
+ auto pool = tunnel->GetTunnelPool ();
+ // let it die if the tunnel pool was reconfigured and has different number of hops
+ if (pool && tunnel->GetNumHops() == pool->GetNumInboundHops())
{
- auto pool = tunnel->GetTunnelPool ();
- // let it die if the tunnel pool was reconfigured and has different number of hops
- if (pool && tunnel->GetNumHops() == pool->GetNumInboundHops())
- {
- tunnel->SetRecreated (true);
- pool->RecreateInboundTunnel (tunnel);
- }
+ tunnel->SetRecreated (true);
+ pool->RecreateInboundTunnel (tunnel);
}
-
- if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
- tunnel->SetState (eTunnelStateExpiring);
- else // we don't need to cleanup expiring tunnels
- tunnel->Cleanup ();
}
- it++;
+
+ if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
+ tunnel->SetState (eTunnelStateExpiring);
+ else // we don't need to cleanup expiring tunnels
+ tunnel->Cleanup ();
}
+ it++;
}
}
@@ -768,7 +781,7 @@
auto router = i2p::transport::transports.RoutesRestricted() ?
i2p::transport::transports.GetRestrictedPeer() :
// should be reachable by us because we send build request directly
- i2p::data::netdb.GetRandomRouter (i2p::context.GetSharedRouterInfo (), false);
+ i2p::data::netdb.GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, true);
if (!router) {
LogPrint (eLogWarning, "Tunnel: Can't find any router, skip creating tunnel");
return;
@@ -780,13 +793,13 @@
}
}
- void Tunnels::ManageTransitTunnels ()
+ void Tunnels::ManageTransitTunnels (uint64_t ts)
{
- uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = m_TransitTunnels.begin (); it != m_TransitTunnels.end ();)
{
auto tunnel = *it;
- if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
+ if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT ||
+ ts + TUNNEL_EXPIRATION_TIMEOUT < tunnel->GetCreationTime ())
{
LogPrint (eLogDebug, "Tunnel: Transit tunnel with id ", tunnel->GetTunnelID (), " expired");
m_Tunnels.erase (tunnel->GetTunnelID ());
@@ -965,5 +978,14 @@
// TODO: locking
return m_OutboundTunnels.size();
}
+
+ void Tunnels::SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels)
+ {
+ if (maxNumTransitTunnels > 0 && m_MaxNumTransitTunnels != maxNumTransitTunnels)
+ {
+ LogPrint (eLogDebug, "Tunnel: Max number of transit tunnels set to ", maxNumTransitTunnels);
+ m_MaxNumTransitTunnels = maxNumTransitTunnels;
+ }
+ }
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/Tunnel.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -40,10 +40,18 @@
const int STANDARD_NUM_RECORDS = 4; // in VariableTunnelBuild message
const int MAX_NUM_RECORDS = 8;
const int HIGH_LATENCY_PER_HOP = 250; // in milliseconds
+ const int MAX_TUNNEL_MSGS_BATCH_SIZE = 100; // handle messages without interrupt
+ const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 5000;
+ const int TUNNEL_MANAGE_INTERVAL = 15; // in seconds
+ const int TUNNEL_POOLS_MANAGE_INTERVAL = 5; // in seconds
+ const int TUNNEL_MEMORY_POOL_MANAGE_INTERVAL = 120; // in seconds
const size_t I2NP_TUNNEL_MESSAGE_SIZE = TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + 34; // reserved for alignment and NTCP 16 + 6 + 12
const size_t I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE = 2*TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE + 28; // reserved for alignment and NTCP 16 + 6 + 6
+ const double TCSR_SMOOTHING_CONSTANT = 0.0005; // smoothing constant in exponentially weighted moving average
+ const double TCSR_START_VALUE = 0.1; // start value of tunnel creation success rate
+
enum TunnelState
{
eTunnelStatePending,
@@ -95,8 +103,8 @@
bool HandleTunnelBuildResponse (uint8_t * msg, size_t len);
// implements TunnelBase
- void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
- void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
+ void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
+ void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) override;
/** @brief add latency sample */
void AddLatencySample(const uint64_t ms) { m_Latency = (m_Latency + ms) >> 1; }
@@ -130,15 +138,15 @@
OutboundTunnel (std::shared_ptr<const TunnelConfig> config):
Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {};
- void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg);
- virtual void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
+ void SendTunnelDataMsgTo (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg);
+ virtual void SendTunnelDataMsgs (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
const i2p::data::IdentHash& GetEndpointIdentHash () const { return m_EndpointIdentHash; };
virtual size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); };
// implements TunnelBase
- void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg);
+ void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
- bool IsInbound() const { return false; }
+ bool IsInbound() const override { return false; }
private:
@@ -152,12 +160,12 @@
public:
InboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Endpoint (true) {};
- void HandleTunnelDataMsg (std::shared_ptr<I2NPMessage>&& msg);
+ void HandleTunnelDataMsg (std::shared_ptr<I2NPMessage>&& msg) override;
virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
- bool IsInbound() const { return true; }
+ bool IsInbound() const override { return true; }
// override TunnelBase
- void Cleanup () { m_Endpoint.Cleanup (); };
+ void Cleanup () override { m_Endpoint.Cleanup (); };
private:
@@ -169,8 +177,8 @@
public:
ZeroHopsInboundTunnel ();
- void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
- size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
+ void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
+ size_t GetNumReceivedBytes () const override { return m_NumReceivedBytes; };
private:
@@ -182,8 +190,8 @@
public:
ZeroHopsOutboundTunnel ();
- void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs);
- size_t GetNumSentBytes () const { return m_NumSentBytes; };
+ void SendTunnelDataMsgs (const std::vector<TunnelMessageBlock>& msgs) override;
+ size_t GetNumSentBytes () const override { return m_NumSentBytes; };
private:
@@ -206,7 +214,7 @@
std::shared_ptr<TunnelPool> GetExploratoryPool () const { return m_ExploratoryPool; };
std::shared_ptr<TunnelBase> GetTunnel (uint32_t tunnelID);
int GetTransitTunnelsExpirationTimeout ();
- void AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel);
+ bool AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel);
void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel);
void AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel);
std::shared_ptr<InboundTunnel> CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel);
@@ -222,6 +230,10 @@
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint);
+ void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
+ uint16_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; };
+ bool IsTooManyTransitTunnels () const { return m_TransitTunnels.size () >= m_MaxNumTransitTunnels; };
+
private:
template<class TTunnel>
@@ -234,18 +246,36 @@
void HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg);
void Run ();
- void ManageTunnels ();
- void ManageOutboundTunnels ();
- void ManageInboundTunnels ();
- void ManageTransitTunnels ();
- void ManagePendingTunnels ();
+ void ManageTunnels (uint64_t ts);
+ void ManageOutboundTunnels (uint64_t ts);
+ void ManageInboundTunnels (uint64_t ts);
+ void ManageTransitTunnels (uint64_t ts);
+ void ManagePendingTunnels (uint64_t ts);
template<class PendingTunnels>
- void ManagePendingTunnels (PendingTunnels& pendingTunnels);
+ void ManagePendingTunnels (PendingTunnels& pendingTunnels, uint64_t ts);
void ManageTunnelPools (uint64_t ts);
std::shared_ptr<ZeroHopsInboundTunnel> CreateZeroHopsInboundTunnel (std::shared_ptr<TunnelPool> pool);
std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel (std::shared_ptr<TunnelPool> pool);
+ // Calculating of tunnel creation success rate
+ void SuccesiveTunnelCreation()
+ {
+ // total TCSR
+ m_TotalNumSuccesiveTunnelCreations++;
+ // A modified version of the EWMA algorithm, where alpha is increased at the beginning to accelerate similarity
+ double alpha = TCSR_SMOOTHING_CONSTANT + (1 - TCSR_SMOOTHING_CONSTANT)/++m_TunnelCreationAttemptsNum;
+ m_TunnelCreationSuccessRate = alpha * 1 + (1 - alpha) * m_TunnelCreationSuccessRate;
+
+ }
+ void FailedTunnelCreation()
+ {
+ m_TotalNumFailedTunnelCreations++;
+
+ double alpha = TCSR_SMOOTHING_CONSTANT + (1 - TCSR_SMOOTHING_CONSTANT)/++m_TunnelCreationAttemptsNum;
+ m_TunnelCreationSuccessRate = alpha * 0 + (1 - alpha) * m_TunnelCreationSuccessRate;
+ }
+
private:
bool m_IsRunning;
@@ -262,9 +292,11 @@
i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE> > m_I2NPTunnelEndpointMessagesMemoryPool;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_MESSAGE_SIZE> > m_I2NPTunnelMessagesMemoryPool;
-
- // some stats
- int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations;
+ uint16_t m_MaxNumTransitTunnels;
+ // count of tunnels for total TCSR algorithm
+ int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations;
+ double m_TunnelCreationSuccessRate;
+ int m_TunnelCreationAttemptsNum;
public:
@@ -278,10 +310,12 @@
size_t CountOutboundTunnels() const;
int GetQueueSize () { return m_Queue.GetSize (); };
- int GetTunnelCreationSuccessRate () const // in percents
+ int GetTunnelCreationSuccessRate () const { return std::round(m_TunnelCreationSuccessRate * 100); } // in percents
+ double GetPreciseTunnelCreationSuccessRate () const { return m_TunnelCreationSuccessRate * 100; } // in percents
+ int GetTotalTunnelCreationSuccessRate () const // in percents
{
- int totalNum = m_NumSuccesiveTunnelCreations + m_NumFailedTunnelCreations;
- return totalNum ? m_NumSuccesiveTunnelCreations*100/totalNum : 0;
+ int totalNum = m_TotalNumSuccesiveTunnelCreations + m_TotalNumFailedTunnelCreations;
+ return totalNum ? m_TotalNumSuccesiveTunnelCreations*100/totalNum : 0;
}
};
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/TunnelBase.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -41,7 +41,7 @@
{
public:
- TunnelBase (uint32_t tunnelID, uint32_t nextTunnelID, i2p::data::IdentHash nextIdent):
+ TunnelBase (uint32_t tunnelID, uint32_t nextTunnelID, const i2p::data::IdentHash& nextIdent):
m_TunnelID (tunnelID), m_NextTunnelID (nextTunnelID), m_NextIdent (nextIdent),
m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {};
virtual ~TunnelBase () {};
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/TunnelEndpoint.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -208,7 +208,7 @@
if (msg.data->len + size > msg.data->maxLen)
{
// LogPrint (eLogWarning, "TunnelMessage: I2NP message size ", msg.data->maxLen, " is not enough");
- auto newMsg = NewI2NPMessage ();
+ auto newMsg = NewI2NPMessage (msg.data->len + size);
*newMsg = *(msg.data);
msg.data = newMsg;
}
@@ -297,11 +297,11 @@
if (msg.data->len + size > msg.data->maxLen)
{
LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
- auto newMsg = NewI2NPMessage ();
+ auto newMsg = NewI2NPMessage (msg.data->len + size);
*newMsg = *(msg.data);
msg.data = newMsg;
}
- if (msg.data->Concat (it->second->data.data (), size) < size) // concatenate out-of-sync fragment
+ if (msg.data->Concat (it->second->data.data (), size) < size) // concatenate out-of-sync fragment
LogPrint (eLogError, "TunnelMessage: Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen);
if (it->second->isLastFragment)
// message complete
@@ -323,11 +323,7 @@
}
uint8_t typeID = msg.data->GetTypeID ();
LogPrint (eLogDebug, "TunnelMessage: Handle fragment of ", msg.data->GetLength (), " bytes, msg type ", (int)typeID);
- // catch RI or reply with new list of routers
- if ((IsRouterInfoMsg (msg.data) || typeID == eI2NPDatabaseSearchReply) &&
- !m_IsInbound && msg.deliveryType != eDeliveryTypeLocal)
- i2p::data::netdb.PostI2NPMsg (CopyI2NPMessage (msg.data));
-
+
switch (msg.deliveryType)
{
case eDeliveryTypeLocal:
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/TunnelPool.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -76,12 +76,12 @@
if (m_NumInboundHops > size)
{
m_NumInboundHops = size;
- LogPrint (eLogInfo, "Tunnels: Inbound tunnel length has beed adjusted to ", size, " for explicit peers");
+ LogPrint (eLogInfo, "Tunnels: Inbound tunnel length has been adjusted to ", size, " for explicit peers");
}
if (m_NumOutboundHops > size)
{
m_NumOutboundHops = size;
- LogPrint (eLogInfo, "Tunnels: Outbound tunnel length has beed adjusted to ", size, " for explicit peers");
+ LogPrint (eLogInfo, "Tunnels: Outbound tunnel length has been adjusted to ", size, " for explicit peers");
}
m_NumInboundTunnels = 1;
m_NumOutboundTunnels = 1;
@@ -282,8 +282,13 @@
for (const auto& it : m_OutboundTunnels)
if (it->IsEstablished ()) num++;
}
- for (int i = num; i < m_NumOutboundTunnels; i++)
- CreateOutboundTunnel ();
+ num = m_NumOutboundTunnels - num;
+ if (num > 0)
+ {
+ if (num > TUNNEL_POOL_MAX_NUM_BUILD_REQUESTS) num = TUNNEL_POOL_MAX_NUM_BUILD_REQUESTS;
+ for (int i = 0; i < num; i++)
+ CreateOutboundTunnel ();
+ }
num = 0;
{
@@ -291,17 +296,24 @@
for (const auto& it : m_InboundTunnels)
if (it->IsEstablished ()) num++;
}
- if (!num && !m_OutboundTunnels.empty () && m_NumOutboundHops > 0)
+ if (!num && !m_OutboundTunnels.empty () && m_NumOutboundHops > 0 &&
+ m_NumInboundHops == m_NumOutboundHops)
{
for (auto it: m_OutboundTunnels)
{
+ // try to create inbound tunnel through the same path as succesive outbound
CreatePairedInboundTunnel (it);
num++;
if (num >= m_NumInboundTunnels) break;
}
}
- for (int i = num; i < m_NumInboundTunnels; i++)
- CreateInboundTunnel ();
+ num = m_NumInboundTunnels - num;
+ if (num > 0)
+ {
+ if (num > TUNNEL_POOL_MAX_NUM_BUILD_REQUESTS) num = TUNNEL_POOL_MAX_NUM_BUILD_REQUESTS;
+ for (int i = 0; i < num; i++)
+ CreateInboundTunnel ();
+ }
if (num < m_NumInboundTunnels && m_NumInboundHops <= 0 && m_LocalDestination) // zero hops IB
m_LocalDestination->SetLeaseSetUpdated (); // update LeaseSet immediately
@@ -373,7 +385,7 @@
std::unique_lock<std::mutex> l(m_TestsMutex);
m_Tests[msgID] = std::make_pair (*it1, *it2);
}
- (*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
+ (*it1)->SendTunnelDataMsgTo ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
CreateDeliveryStatusMsg (msgID));
++it1; ++it2;
}
@@ -460,17 +472,18 @@
return i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this ();
}
- std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop, bool reverse) const
+ std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop,
+ bool reverse, bool endpoint) const
{
- auto hop = IsExploratory () ? i2p::data::netdb.GetRandomRouter (prevHop, reverse):
- i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop, reverse);
+ auto hop = IsExploratory () ? i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint):
+ i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop, reverse, endpoint);
if (!hop || hop->GetProfile ()->IsBad ())
- hop = i2p::data::netdb.GetRandomRouter (prevHop, reverse);
+ hop = i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint);
return hop;
}
- bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop)
+ bool TunnelPool::StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop)
{
int start = 0;
std::shared_ptr<const i2p::data::RouterInfo> prevHop = i2p::context.GetSharedRouterInfo ();
@@ -486,9 +499,9 @@
else if (i2p::transport::transports.GetNumPeers () > 100 ||
(inbound && i2p::transport::transports.GetNumPeers () > 25))
{
- auto r = i2p::transport::transports.GetRandomPeer ();
+ auto r = i2p::transport::transports.GetRandomPeer (!IsExploratory ());
if (r && r->IsECIES () && !r->GetProfile ()->IsBad () &&
- (numHops > 1 || (r->IsV4 () && (!inbound || r->IsReachable ())))) // first inbound must be reachable
+ (numHops > 1 || (r->IsV4 () && (!inbound || r->IsPublished (true))))) // first inbound must be published ipv4
{
prevHop = r;
path.Add (r);
@@ -498,11 +511,11 @@
for(int i = start; i < numHops; i++ )
{
- auto hop = nextHop (prevHop, inbound);
+ auto hop = nextHop (prevHop, inbound, i == numHops - 1);
if (!hop && !i) // if no suitable peer found for first hop, try already connected
{
LogPrint (eLogInfo, "Tunnels: Can't select first hop for a tunnel. Trying already connected");
- hop = i2p::transport::transports.GetRandomPeer ();
+ hop = i2p::transport::transports.GetRandomPeer (false);
if (hop && !hop->IsECIES ()) hop = nullptr;
}
if (!hop)
@@ -510,12 +523,6 @@
LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ());
return false;
}
- if ((i == numHops - 1) && (!hop->IsV4 () || // doesn't support ipv4
- (inbound && !hop->IsReachable ()))) // IBGW is not reachable
- {
- auto hop1 = nextHop (prevHop, true);
- if (hop1) hop = hop1;
- }
prevHop = hop;
path.Add (hop);
}
@@ -557,14 +564,15 @@
if (m_CustomPeerSelector)
return m_CustomPeerSelector->SelectPeers(path, numHops, isInbound);
}
- return StandardSelectPeers(path, numHops, isInbound, std::bind(&TunnelPool::SelectNextHop, this, std::placeholders::_1, std::placeholders::_2));
+ return StandardSelectPeers(path, numHops, isInbound, std::bind(&TunnelPool::SelectNextHop, this,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
}
bool TunnelPool::SelectExplicitPeers (Path& path, bool isInbound)
{
+ if (!m_ExplicitPeers->size ()) return false;
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
if (numHops > (int)m_ExplicitPeers->size ()) numHops = m_ExplicitPeers->size ();
- if (!numHops) return false;
for (int i = 0; i < numHops; i++)
{
auto& ident = (*m_ExplicitPeers)[i];
@@ -628,8 +636,13 @@
outboundTunnel = tunnels.GetNextOutboundTunnel ();
LogPrint (eLogDebug, "Tunnels: Re-creating destination inbound tunnel...");
std::shared_ptr<TunnelConfig> config;
- if (m_NumInboundHops > 0 && tunnel->GetPeers().size())
- config = std::make_shared<TunnelConfig>(tunnel->GetPeers (), tunnel->IsShortBuildMessage (), tunnel->GetFarEndTransports ());
+ if (m_NumInboundHops > 0)
+ {
+ auto peers = tunnel->GetPeers();
+ if (peers.size ()&& ValidatePeers (peers))
+ config = std::make_shared<TunnelConfig>(tunnel->GetPeers (),
+ tunnel->IsShortBuildMessage (), tunnel->GetFarEndTransports ());
+ }
if (!m_NumInboundHops || config)
{
auto newTunnel = tunnels.CreateInboundTunnel (config, shared_from_this(), outboundTunnel);
@@ -693,10 +706,12 @@
{
LogPrint (eLogDebug, "Tunnels: Re-creating destination outbound tunnel...");
std::shared_ptr<TunnelConfig> config;
- if (m_NumOutboundHops > 0 && tunnel->GetPeers().size())
+ if (m_NumOutboundHops > 0)
{
- config = std::make_shared<TunnelConfig>(tunnel->GetPeers (), inboundTunnel->GetNextTunnelID (),
- inboundTunnel->GetNextIdentHash (), inboundTunnel->IsShortBuildMessage (), tunnel->GetFarEndTransports ());
+ auto peers = tunnel->GetPeers();
+ if (peers.size () && ValidatePeers (peers))
+ config = std::make_shared<TunnelConfig>(peers, inboundTunnel->GetNextTunnelID (),
+ inboundTunnel->GetNextIdentHash (), inboundTunnel->IsShortBuildMessage (), tunnel->GetFarEndTransports ());
}
if (!m_NumOutboundHops || config)
{
@@ -737,6 +752,21 @@
return m_CustomPeerSelector != nullptr;
}
+ bool TunnelPool::ValidatePeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers) const
+ {
+ bool highBandwidth = !IsExploratory ();
+ for (auto it: peers)
+ {
+ auto r = i2p::data::netdb.FindRouter (it->GetIdentHash ());
+ if (r)
+ {
+ if (r->IsHighCongestion (highBandwidth)) return false;
+ it = r->GetIdentity (); // use identity from updated RouterInfo
+ }
+ }
+ return true;
+ }
+
std::shared_ptr<InboundTunnel> TunnelPool::GetLowestLatencyInboundTunnel(std::shared_ptr<InboundTunnel> exclude) const
{
std::shared_ptr<InboundTunnel> tun = nullptr;
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/TunnelPool.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -30,6 +30,7 @@
const int TUNNEL_POOL_MANAGE_INTERVAL = 10; // in seconds
const int TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY = 16;
const int TUNNEL_POOL_MAX_OUTBOUND_TUNNELS_QUANTITY = 16;
+ const int TUNNEL_POOL_MAX_NUM_BUILD_REQUESTS = 2;
class Tunnel;
class InboundTunnel;
@@ -53,12 +54,9 @@
virtual bool SelectPeers(Path & peers, int hops, bool isInbound) = 0;
};
-
- typedef std::function<std::shared_ptr<const i2p::data::RouterInfo>(std::shared_ptr<const i2p::data::RouterInfo>, bool)> SelectHopFunc;
- bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop);
-
class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination
{
+ typedef std::function<std::shared_ptr<const i2p::data::RouterInfo>(std::shared_ptr<const i2p::data::RouterInfo>, bool, bool)> SelectHopFunc;
public:
TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels,
@@ -114,7 +112,8 @@
std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude = nullptr) const;
// for overriding tunnel peer selection
- std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop, bool reverse) const;
+ std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop, bool reverse, bool endpoint) const;
+ bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop);
private:
@@ -127,6 +126,7 @@
typename TTunnels::value_type excluded, i2p::data::RouterInfo::CompatibleTransports compatible) const;
bool SelectPeers (Path& path, bool isInbound);
bool SelectExplicitPeers (Path& path, bool isInbound);
+ bool ValidatePeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers) const;
private:
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/api.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -38,9 +38,8 @@
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);
- bool avx; i2p::config::GetOption("cpuext.avx", avx);
bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt);
- i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt);
+ i2p::crypto::InitCrypto (precomputation, aesni, forceCpuExt);
int netID; i2p::config::GetOption("netid", netID);
i2p::context.SetNetID (netID);
@@ -60,17 +59,22 @@
else
i2p::log::Logger().SendTo (i2p::fs::DataDirPath (i2p::fs::GetAppName () + ".log"));
i2p::log::Logger().Start ();
+ i2p::transport::InitTransports ();
LogPrint(eLogInfo, "API: Starting NetDB");
i2p::data::netdb.Start();
LogPrint(eLogInfo, "API: Starting Transports");
i2p::transport::transports.Start();
LogPrint(eLogInfo, "API: Starting Tunnels");
i2p::tunnel::tunnels.Start();
+ LogPrint(eLogInfo, "API: Starting Router context");
+ i2p::context.Start();
}
void StopI2P ()
{
LogPrint(eLogInfo, "API: Shutting down");
+ LogPrint(eLogInfo, "API: Stopping Router context");
+ i2p::context.Stop();
LogPrint(eLogInfo, "API: Stopping Tunnels");
i2p::tunnel::tunnels.Stop();
LogPrint(eLogInfo, "API: Stopping Transports");
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/util.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -8,13 +8,14 @@
#include <cstdlib>
#include <string>
+#include <unordered_set>
#include <boost/asio.hpp>
#include "util.h"
#include "Log.h"
#include "I2PEndian.h"
-#if not defined (__FreeBSD__)
+#if !defined (__FreeBSD__) && !defined(_MSC_VER)
#include <pthread.h>
#endif
@@ -22,6 +23,20 @@
#include <pthread_np.h>
#endif
+#if defined(__APPLE__)
+# include <AvailabilityMacros.h>
+#endif
+
+#if defined(__HAIKU__)
+#include <gnu/pthread.h>
+#include <posix/pthread.h>
+#include <posix/sys/sockio.h>
+#include <posix/sys/ioctl.h>
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE
+#include <bsd/ifaddrs.h>
+#endif
+#endif
#ifdef _WIN32
#include <stdlib.h>
@@ -33,6 +48,19 @@
#include <iphlpapi.h>
#include <shlobj.h>
+#if defined(_MSC_VER)
+const DWORD MS_VC_EXCEPTION = 0x406D1388;
+#pragma pack(push,8)
+typedef struct tagTHREADNAME_INFO
+{
+ DWORD dwType;
+ LPCSTR szName;
+ DWORD dwThreadID;
+ DWORD dwFlags;
+} THREADNAME_INFO;
+#pragma pack(pop)
+#endif
+
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
@@ -71,7 +99,8 @@
ZeroMemory(&ss, sizeof(ss));
ss.ss_family = af;
- switch(af) {
+ switch (af)
+ {
case AF_INET:
((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
break;
@@ -81,7 +110,7 @@
default:
return NULL;
}
- /* cannot direclty use &size because of strict aliasing rules */
+ /* cannot directly use &size because of strict aliasing rules */
return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0)? dst : NULL;
}
@@ -143,14 +172,37 @@
}
void SetThreadName (const char *name) {
-#if defined(__APPLE__) && !defined(__powerpc__)
+#if defined(__APPLE__)
+# if (!defined(MAC_OS_X_VERSION_10_6) || \
+ (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || \
+ defined(__POWERPC__))
+ /* pthread_setname_np is not there on <10.6 and all PPC.
+ So do nothing. */
+# else
pthread_setname_np((char*)name);
+# endif
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
pthread_set_name_np(pthread_self(), name);
#elif defined(__NetBSD__)
pthread_setname_np(pthread_self(), "%s", (void *)name);
#elif !defined(__gnu_hurd__)
+ #if defined(_MSC_VER)
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = name;
+ info.dwThreadID = -1;
+ info.dwFlags = 0;
+ #pragma warning(push)
+ #pragma warning(disable: 6320 6322)
+ __try {
+ RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER) {
+ }
+ #pragma warning(pop)
+ #else
pthread_setname_np(pthread_self(), name);
+ #endif
#endif
}
@@ -160,7 +212,7 @@
int GetMTUWindowsIpv4 (sockaddr_in inputAddress, int fallback)
{
typedef const char *(* IPN)(int af, const void *src, char *dst, socklen_t size);
- IPN inetntop = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetNtop");
+ IPN inetntop = (IPN)(void*)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetNtop");
if (!inetntop) inetntop = inet_ntop_xp; // use own implementation if not found
ULONG outBufLen = 0;
@@ -168,7 +220,7 @@
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
- if(GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
+ if (GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
== ERROR_BUFFER_OVERFLOW)
{
FREE(pAddresses);
@@ -179,7 +231,7 @@
AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
);
- if(dwRetVal != NO_ERROR)
+ if (dwRetVal != NO_ERROR)
{
LogPrint(eLogError, "NetIface: GetMTU: Enclosed GetAdaptersAddresses() call has failed");
FREE(pAddresses);
@@ -187,19 +239,17 @@
}
pCurrAddresses = pAddresses;
- while(pCurrAddresses)
+ while (pCurrAddresses)
{
- PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
-
pUnicast = pCurrAddresses->FirstUnicastAddress;
- if(pUnicast == nullptr)
+ if (pUnicast == nullptr)
LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv4 address, this is not supported");
- for(int i = 0; pUnicast != nullptr; ++i)
+ while (pUnicast != nullptr)
{
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr;
- if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr)
+ if (localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr)
{
char addr[INET_ADDRSTRLEN];
inetntop(AF_INET, &(((struct sockaddr_in *)localInterfaceAddress)->sin_addr), addr, INET_ADDRSTRLEN);
@@ -223,7 +273,7 @@
int GetMTUWindowsIpv6 (sockaddr_in6 inputAddress, int fallback)
{
typedef const char *(* IPN)(int af, const void *src, char *dst, socklen_t size);
- IPN inetntop = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetNtop");
+ IPN inetntop = (IPN)(void*)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetNtop");
if (!inetntop) inetntop = inet_ntop_xp; // use own implementation if not found
ULONG outBufLen = 0;
@@ -253,12 +303,11 @@
pCurrAddresses = pAddresses;
while (pCurrAddresses)
{
- PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
pUnicast = pCurrAddresses->FirstUnicastAddress;
if (pUnicast == nullptr)
LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv6 address, this is not supported");
- for (int i = 0; pUnicast != nullptr; ++i)
+ while (pUnicast != nullptr)
{
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr;
@@ -303,16 +352,16 @@
#endif
typedef int (* IPN)(int af, const char *src, void *dst);
- IPN inetpton = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetPton");
+ IPN inetpton = (IPN)(void*)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetPton");
if (!inetpton) inetpton = inet_pton_xp; // use own implementation if not found
- if(localAddress.is_v4())
+ if (localAddress.is_v4())
{
sockaddr_in inputAddress;
inetpton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr));
return GetMTUWindowsIpv4(inputAddress, fallback);
}
- else if(localAddress.is_v6())
+ else if (localAddress.is_v6())
{
sockaddr_in6 inputAddress;
inetpton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
@@ -328,7 +377,7 @@
int GetMTUUnix (const boost::asio::ip::address& localAddress, int fallback)
{
ifaddrs* ifaddr, *ifa = nullptr;
- if(getifaddrs(&ifaddr) == -1)
+ if (getifaddrs(&ifaddr) == -1)
{
LogPrint(eLogError, "NetIface: Can't call getifaddrs(): ", strerror(errno));
return fallback;
@@ -336,34 +385,34 @@
int family = 0;
// look for interface matching local address
- for(ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
+ for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
{
- if(!ifa->ifa_addr)
+ if (!ifa->ifa_addr)
continue;
family = ifa->ifa_addr->sa_family;
- if(family == AF_INET && localAddress.is_v4())
+ if (family == AF_INET && localAddress.is_v4())
{
sockaddr_in* sa = (sockaddr_in*) ifa->ifa_addr;
- if(!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4))
+ if (!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4))
break; // address matches
}
- else if(family == AF_INET6 && localAddress.is_v6())
+ else if (family == AF_INET6 && localAddress.is_v6())
{
sockaddr_in6* sa = (sockaddr_in6*) ifa->ifa_addr;
- if(!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16))
+ if (!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16))
break; // address matches
}
}
int mtu = fallback;
- if(ifa && family)
+ if (ifa && family)
{ // interface found?
int fd = socket(family, SOCK_DGRAM, 0);
- if(fd > 0)
+ if (fd > 0)
{
ifreq ifr;
strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ-1); // set interface for query
- if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0)
+ if (ioctl(fd, SIOCGIFMTU, &ifr) >= 0)
mtu = ifr.ifr_mtu; // MTU
else
LogPrint (eLogError, "NetIface: Failed to run ioctl: ", strerror(errno));
@@ -396,7 +445,7 @@
{
#ifdef _WIN32
LogPrint(eLogError, "NetIface: Cannot get address by interface name, not implemented on WIN32");
- if(ipv6)
+ if (ipv6)
return boost::asio::ip::address::from_string("::1");
else
return boost::asio::ip::address::from_string("127.0.0.1");
@@ -415,7 +464,7 @@
// match
char addr[INET6_ADDRSTRLEN];
memset (addr, 0, INET6_ADDRSTRLEN);
- if(af == AF_INET)
+ if (af == AF_INET)
inet_ntop(af, &((sockaddr_in *)cur->ifa_addr)->sin_addr, addr, INET6_ADDRSTRLEN);
else
inet_ntop(af, &((sockaddr_in6 *)cur->ifa_addr)->sin6_addr, addr, INET6_ADDRSTRLEN);
@@ -431,9 +480,9 @@
LogPrint(eLogError, "NetIface: Exception while searching address using ifaddr: ", ex.what());
}
- if(addrs) freeifaddrs(addrs);
+ if (addrs) freeifaddrs(addrs);
std::string fallback;
- if(ipv6)
+ if (ipv6)
{
fallback = "::1";
LogPrint(eLogWarning, "NetIface: Cannot find IPv6 address for interface ", ifname);
@@ -477,6 +526,22 @@
return IsYggdrasilAddress (addr.to_v6 ().to_bytes ().data ());
}
+ bool IsPortInReservedRange (const uint16_t port) noexcept
+ {
+ // https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers (Feb. 3, 2023) + Tor browser (9150)
+ static const std::unordered_set<uint16_t> reservedPorts{
+ 9119,9150,9306,9312,9389,9418,9535,9536,9695,
+ 9800,9899,10000,10050,10051,10110,10212,
+ 10933,11001,11112,11235,11371,12222,12223,
+ 13075,13400,13720,13721,13724,13782,13783,
+ 13785,13786,15345,17224,17225,17500,18104,
+ 19788,19812,19813,19814,19999,20000,24465,
+ 24554,26000,27000,27001,27002,27003,27004,
+ 27005,27006,27007,27008,27009,28000};
+
+ return (reservedPorts.find(port) != reservedPorts.end());
+ }
+
boost::asio::ip::address_v6 GetYggdrasilAddress ()
{
#if defined(_WIN32)
@@ -485,7 +550,7 @@
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
- if(GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
+ if (GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
== ERROR_BUFFER_OVERFLOW)
{
FREE(pAddresses);
@@ -496,7 +561,7 @@
AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
);
- if(dwRetVal != NO_ERROR)
+ if (dwRetVal != NO_ERROR)
{
LogPrint(eLogError, "NetIface: GetYggdrasilAddress(): enclosed GetAdaptersAddresses() call has failed");
FREE(pAddresses);
@@ -504,12 +569,11 @@
}
pCurrAddresses = pAddresses;
- while(pCurrAddresses)
+ while (pCurrAddresses)
{
- PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
pUnicast = pCurrAddresses->FirstUnicastAddress;
- for(int i = 0; pUnicast != nullptr; ++i)
+ while (pUnicast != nullptr)
{
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr;
@@ -553,7 +617,7 @@
LogPrint(eLogError, "NetIface: Exception while searching Yggdrasill address using ifaddr: ", ex.what());
}
LogPrint(eLogWarning, "NetIface: Interface with Yggdrasil network address not found");
- if(addrs) freeifaddrs(addrs);
+ if (addrs) freeifaddrs(addrs);
return boost::asio::ip::address_v6 ();
#endif
}
@@ -573,7 +637,7 @@
{
// https://en.wikipedia.org/wiki/Reserved_IP_addresses
if (host.is_unspecified ()) return false;
- if(host.is_v4())
+ if (host.is_v4())
{
static const std::vector< std::pair<uint32_t, uint32_t> > reservedIPv4Ranges {
address_pair_v4("0.0.0.0", "0.255.255.255"),
@@ -593,14 +657,15 @@
};
uint32_t ipv4_address = host.to_v4 ().to_ulong ();
- for(const auto& it : reservedIPv4Ranges) {
+ for (const auto& it : reservedIPv4Ranges) {
if (ipv4_address >= it.first && ipv4_address <= it.second)
return true;
}
}
- if(host.is_v6())
+ if (host.is_v6())
{
static const std::vector< std::pair<boost::asio::ip::address_v6::bytes_type, boost::asio::ip::address_v6::bytes_type> > reservedIPv6Ranges {
+ address_pair_v6("64:ff9b::", "64:ff9b:ffff:ffff:ffff:ffff:ffff:ffff"), // NAT64
address_pair_v6("2001:db8::", "2001:db8:ffff:ffff:ffff:ffff:ffff:ffff"),
address_pair_v6("fc00::", "fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"),
address_pair_v6("fe80::", "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff"),
@@ -610,7 +675,7 @@
};
boost::asio::ip::address_v6::bytes_type ipv6_address = host.to_v6 ().to_bytes ();
- for(const auto& it : reservedIPv6Ranges) {
+ for (const auto& it : reservedIPv6Ranges) {
if (ipv6_address >= it.first && ipv6_address <= it.second)
return true;
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/util.h
^
|
@@ -112,7 +112,7 @@
};
template<class T>
- class MemoryPoolMt: public MemoryPool<T>
+ class MemoryPoolMt: private MemoryPool<T>
{
public:
@@ -224,6 +224,7 @@
bool IsLocalAddress (const boost::asio::ip::address& addr);
bool IsInReservedRange (const boost::asio::ip::address& host);
bool IsYggdrasilAddress (const boost::asio::ip::address& addr);
+ bool IsPortInReservedRange (const uint16_t port) noexcept;
}
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd/version.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2024, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -11,16 +11,18 @@
#define CODENAME "Purple"
+#define XSTRINGIZE(x) STRINGIZE(x)
#define STRINGIZE(x) #x
+
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
#define I2PD_VERSION_MAJOR 2
-#define I2PD_VERSION_MINOR 43
-#define I2PD_VERSION_MICRO 0
+#define I2PD_VERSION_MINOR 50
+#define I2PD_VERSION_MICRO 2
#define I2PD_VERSION_PATCH 0
#ifdef GITVER
- #define I2PD_VERSION GITVER
+ #define I2PD_VERSION XSTRINGIZE(GITVER)
#else
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
#endif
@@ -31,7 +33,7 @@
#define I2P_VERSION_MAJOR 0
#define I2P_VERSION_MINOR 9
-#define I2P_VERSION_MICRO 55
+#define I2P_VERSION_MICRO 61
#define I2P_VERSION_PATCH 0
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
#define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/AddressBook.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -313,14 +313,14 @@
{
i2p::config::GetOption("addressbook.enabled", m_IsEnabled);
if (m_IsEnabled)
- {
+ {
if (!m_Storage)
m_Storage = new AddressBookFilesystemStorage;
m_Storage->Init();
LoadHosts (); /* try storage, then hosts.txt, then download */
StartSubscriptions ();
StartLookups ();
- }
+ }
}
void AddressBook::StartResolvers ()
@@ -397,6 +397,29 @@
return nullptr;
}
+ bool AddressBook::RecordExists (const std::string& address, const std::string& jump)
+ {
+ auto addr = FindAddress(address);
+ if (!addr)
+ return false;
+
+ auto pos = jump.find(".b32.i2p");
+ if (pos != std::string::npos)
+ {
+ i2p::data::IdentHash identHash;
+ if (identHash.FromBase32(jump.substr (0, pos)) && identHash == addr->identHash)
+ return true;
+ }
+ else
+ {
+ i2p::data::IdentityEx ident;
+ if (ident.FromBase64 (jump) && ident.GetIdentHash () == addr->identHash)
+ return true;
+ }
+
+ return false;
+ }
+
void AddressBook::InsertAddress (const std::string& address, const std::string& jump)
{
auto pos = jump.find(".b32.i2p");
@@ -567,6 +590,7 @@
void AddressBook::LoadLocal ()
{
+ if (!m_Storage) return;
std::map<std::string, std::shared_ptr<Address>> localAddresses;
m_Storage->LoadLocal (localAddresses);
for (const auto& it: localAddresses)
@@ -647,7 +671,7 @@
this, std::placeholders::_1));
}
else
- LogPrint (eLogError, "Addressbook: Can't start subscriptions: missing shared local destination");
+ LogPrint (eLogCritical, "Addressbook: Can't start subscriptions: missing shared local destination");
}
void AddressBook::StopSubscriptions ()
@@ -819,40 +843,22 @@
}
else
m_Ident = addr->identHash;
- /* this code block still needs some love */
- std::condition_variable newDataReceived;
- std::mutex newDataReceivedMutex;
- auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (m_Ident);
- if (!leaseSet)
- {
- std::unique_lock<std::mutex> l(newDataReceivedMutex);
- i2p::client::context.GetSharedLocalDestination ()->RequestDestination (m_Ident,
- [&newDataReceived, &leaseSet, &newDataReceivedMutex](std::shared_ptr<i2p::data::LeaseSet> ls)
- {
- leaseSet = ls;
- std::unique_lock<std::mutex> l1(newDataReceivedMutex);
- newDataReceived.notify_all ();
- });
- if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout)
- {
- LogPrint (eLogError, "Addressbook: Subscription LeaseSet request timeout expired");
- i2p::client::context.GetSharedLocalDestination ()->CancelDestinationRequest (m_Ident, false); // don't notify, because we know it already
- return false;
- }
- }
- if (!leaseSet) {
- /* still no leaseset found */
+ // save url parts for later use
+ std::string dest_host = url.host;
+ int dest_port = url.port ? url.port : 80;
+ // try to create stream to addressbook site
+ auto stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (m_Ident, dest_port);
+ if (!stream)
+ {
LogPrint (eLogError, "Addressbook: LeaseSet for address ", url.host, " not found");
return false;
}
- if (m_Etag.empty() && m_LastModified.empty()) {
+ if (m_Etag.empty() && m_LastModified.empty())
+ {
m_Book.GetEtag (m_Ident, m_Etag, m_LastModified);
LogPrint (eLogDebug, "Addressbook: Loaded for ", url.host, ": ETag: ", m_Etag, ", Last-Modified: ", m_LastModified);
}
- /* save url parts for later use */
- std::string dest_host = url.host;
- int dest_port = url.port ? url.port : 80;
- /* create http request & send it */
+ // create http request & send it
i2p::http::HTTPReq req;
req.AddHeader("Host", dest_host);
req.AddHeader("User-Agent", "Wget/1.11.4");
@@ -863,34 +869,29 @@
req.AddHeader("If-None-Match", m_Etag);
if (!m_LastModified.empty())
req.AddHeader("If-Modified-Since", m_LastModified);
- /* convert url to relative */
+ // convert url to relative
url.schema = "";
url.host = "";
req.uri = url.to_string();
req.version = "HTTP/1.1";
- auto stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (leaseSet, dest_port);
std::string request = req.to_string();
stream->Send ((const uint8_t *) request.data(), request.length());
- /* read response */
+ // read response
std::string response;
uint8_t recv_buf[4096];
bool end = false;
int numAttempts = 0;
while (!end)
{
- stream->AsyncReceive (boost::asio::buffer (recv_buf, 4096),
- [&](const boost::system::error_code& ecode, std::size_t bytes_transferred)
- {
- if (bytes_transferred)
- response.append ((char *)recv_buf, bytes_transferred);
- if (ecode == boost::asio::error::timed_out || !stream->IsOpen ())
- end = true;
- newDataReceived.notify_all ();
- },
- SUBSCRIPTION_REQUEST_TIMEOUT);
- std::unique_lock<std::mutex> l(newDataReceivedMutex);
- // wait 1 more second
- if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT + 1)) == std::cv_status::timeout)
+ size_t received = stream->Receive (recv_buf, 4096, SUBSCRIPTION_REQUEST_TIMEOUT);
+ if (received)
+ {
+ response.append ((char *)recv_buf, received);
+ if (!stream->IsOpen ()) end = true;
+ }
+ else if (!stream->IsOpen ())
+ end = true;
+ else
{
LogPrint (eLogError, "Addressbook: Subscriptions request timeout expired");
numAttempts++;
@@ -900,7 +901,7 @@
// process remaining buffer
while (size_t len = stream->ReadSome (recv_buf, sizeof(recv_buf)))
response.append ((char *)recv_buf, len);
- /* parse response */
+ // parse response
i2p::http::HTTPRes res;
int res_head_len = res.parse(response);
if (res_head_len < 0)
@@ -913,7 +914,7 @@
LogPrint(eLogError, "Addressbook: Incomplete http response from ", dest_host, ", interrupted by timeout");
return false;
}
- /* assert: res_head_len > 0 */
+ // assert: res_head_len > 0
response.erase(0, res_head_len);
if (res.code == 304)
{
@@ -936,7 +937,7 @@
LogPrint(eLogError, "Addressbook: Response size mismatch, expected: ", len, ", got: ", response.length(), "bytes");
return false;
}
- /* assert: res.code == 200 */
+ // assert: res.code == 200
auto it = res.headers.find("ETag");
if (it != res.headers.end()) m_Etag = it->second;
it = res.headers.find("Last-Modified");
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/AddressBook.h
^
|
@@ -90,6 +90,8 @@
void InsertAddress (const std::string& address, const std::string& jump); // for jump links
void InsertFullAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
+ bool RecordExists (const std::string& address, const std::string& jump);
+
bool LoadHostsFromStream (std::istream& f, bool is_update);
void DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified);
//This method returns the ".b32.i2p" address
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/BOB.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -127,7 +127,7 @@
connection->I2PConnect (receiver->data, receiver->dataLen);
}
- BOBI2POutboundTunnel::BOBI2POutboundTunnel (const std::string& outhost, int port,
+ BOBI2POutboundTunnel::BOBI2POutboundTunnel (const std::string& outhost, uint16_t port,
std::shared_ptr<ClientDestination> localDestination, bool quiet): BOBI2PTunnel (localDestination),
m_Endpoint (boost::asio::ip::address::from_string (outhost), port), m_IsQuiet (quiet)
{
@@ -156,7 +156,7 @@
{
if (stream)
{
- auto conn = std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), m_Endpoint, m_IsQuiet);
+ auto conn = std::make_shared<I2PTunnelConnection> (this, stream, m_Endpoint, m_IsQuiet);
AddHandler (conn);
conn->Connect ();
}
@@ -164,7 +164,7 @@
BOBDestination::BOBDestination (std::shared_ptr<ClientDestination> localDestination,
const std::string &nickname, const std::string &inhost, const std::string &outhost,
- const int inport, const int outport, const bool quiet):
+ const uint16_t inport, const uint16_t outport, const bool quiet):
m_LocalDestination (localDestination),
m_OutboundTunnel (nullptr), m_InboundTunnel (nullptr),
m_Nickname(nickname), m_InHost(inhost), m_OutHost(outhost),
@@ -209,7 +209,7 @@
}
}
- void BOBDestination::CreateInboundTunnel (int port, const std::string& inhost)
+ void BOBDestination::CreateInboundTunnel (uint16_t port, const std::string& inhost)
{
if (!m_InboundTunnel)
{
@@ -230,7 +230,7 @@
}
}
- void BOBDestination::CreateOutboundTunnel (const std::string& outhost, int port, bool quiet)
+ void BOBDestination::CreateOutboundTunnel (const std::string& outhost, uint16_t port, bool quiet)
{
if (!m_OutboundTunnel)
{
@@ -357,13 +357,13 @@
os << data << std::endl;
}
- void BOBCommandSession::BuildStatusLine(bool currentTunnel, BOBDestination *dest, std::string &out)
+ void BOBCommandSession::BuildStatusLine(bool currentTunnel, std::shared_ptr<BOBDestination> dest, std::string &out)
{
// helper lambdas
const auto issetStr = [](const std::string &str) { return str.empty() ? "not_set" : str; }; // for inhost, outhost
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 destReady = [](const BOBDestination * const dest) { return dest->IsRunning(); };
+ const auto destReady = [](const BOBDestination * const dest) { return dest && dest->IsRunning(); };
const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str
// tunnel info
@@ -373,9 +373,9 @@
const std::string outhost = issetStr(currentTunnel ? m_OutHost : dest->GetOutHost());
const std::string inport = issetNum(currentTunnel ? m_InPort : dest->GetInPort());
const std::string outport = issetNum(currentTunnel ? m_OutPort : dest->GetOutPort());
- const bool keys = destExists(dest); // key must exist when destination is created
- const bool starting = destExists(dest) && !destReady(dest);
- const bool running = destExists(dest) && destReady(dest);
+ const bool keys = destExists(dest.get ()); // key must exist when destination is created
+ const bool starting = destExists(dest.get ()) && !destReady(dest.get ());
+ const bool running = destExists(dest.get ()) && destReady(dest.get ());
const bool stopping = false;
// build line
@@ -446,7 +446,7 @@
if (!m_CurrentDestination)
{
- m_CurrentDestination = new BOBDestination (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options), // deleted in clear command
+ m_CurrentDestination = std::make_shared<BOBDestination> (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options), // deleted in clear command
m_Nickname, m_InHost, m_OutHost, m_InPort, m_OutPort, m_IsQuiet);
m_Owner.AddDestination (m_Nickname, m_CurrentDestination);
}
@@ -547,7 +547,7 @@
}
- m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType);
+ m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType, true);
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
}
@@ -595,9 +595,12 @@
LogPrint (eLogDebug, "BOB: outport ", operand);
if (*operand)
{
- m_OutPort = std::stoi(operand);
- if (m_OutPort >= 0)
+ int port = std::stoi(operand);
+ if (port >= 0 && port < 65536)
+ {
+ m_OutPort = port;
SendReplyOK ("outbound port set");
+ }
else
SendReplyError ("port out of range");
}
@@ -622,9 +625,12 @@
LogPrint (eLogDebug, "BOB: inport ", operand);
if (*operand)
{
- m_InPort = std::stoi(operand);
- if (m_InPort >= 0)
+ int port = std::stoi(operand);
+ if (port >= 0 && port < 65536)
+ {
+ m_InPort = port;
SendReplyOK ("inbound port set");
+ }
else
SendReplyError ("port out of range");
}
@@ -660,7 +666,13 @@
SendReplyError ("Address Not found");
return;
}
- auto localDestination = m_CurrentDestination ? m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination ();
+ auto localDestination = (m_CurrentDestination && m_CurrentDestination->IsRunning ()) ?
+ m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination ();
+ if (!localDestination)
+ {
+ SendReplyError ("No local destination");
+ return;
+ }
if (addr->IsIdentHash ())
{
// we might have leaseset already
@@ -814,7 +826,7 @@
}
}
- BOBCommandChannel::BOBCommandChannel (const std::string& address, int port):
+ BOBCommandChannel::BOBCommandChannel (const std::string& address, uint16_t port):
RunnableService ("BOB"),
m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port))
{
@@ -869,8 +881,6 @@
{
if (IsRunning ())
Stop ();
- for (const auto& it: m_Destinations)
- delete it.second;
}
void BOBCommandChannel::Start ()
@@ -887,9 +897,9 @@
StopIOService ();
}
- void BOBCommandChannel::AddDestination (const std::string& name, BOBDestination * dest)
+ void BOBCommandChannel::AddDestination (const std::string& name, std::shared_ptr<BOBDestination> dest)
{
- m_Destinations[name] = dest;
+ m_Destinations.emplace (name, dest);
}
void BOBCommandChannel::DeleteDestination (const std::string& name)
@@ -898,12 +908,11 @@
if (it != m_Destinations.end ())
{
it->second->Stop ();
- delete it->second;
m_Destinations.erase (it);
}
}
- BOBDestination * BOBCommandChannel::FindDestination (const std::string& name)
+ std::shared_ptr<BOBDestination> BOBCommandChannel::FindDestination (const std::string& name)
{
auto it = m_Destinations.find (name);
if (it != m_Destinations.end ())
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/BOB.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -124,7 +124,7 @@
{
public:
- BOBI2POutboundTunnel (const std::string& outhost, int port, std::shared_ptr<ClientDestination> localDestination, bool quiet);
+ BOBI2POutboundTunnel (const std::string& outhost, uint16_t port, std::shared_ptr<ClientDestination> localDestination, bool quiet);
void Start ();
void Stop ();
@@ -149,19 +149,19 @@
BOBDestination (std::shared_ptr<ClientDestination> localDestination,
const std::string &nickname, const std::string &inhost, const std::string &outhost,
- const int inport, const int outport, const bool quiet);
+ const uint16_t inport, const uint16_t outport, const bool quiet);
~BOBDestination ();
void Start ();
void Stop ();
void StopTunnels ();
- void CreateInboundTunnel (int port, const std::string& inhost);
- void CreateOutboundTunnel (const std::string& outhost, int port, bool quiet);
+ void CreateInboundTunnel (uint16_t port, const std::string& inhost);
+ void CreateOutboundTunnel (const std::string& outhost, uint16_t port, bool quiet);
const std::string& GetNickname() const { return m_Nickname; }
const std::string& GetInHost() const { return m_InHost; }
const std::string& GetOutHost() const { return m_OutHost; }
- int GetInPort() const { return m_InPort; }
- int GetOutPort() const { return m_OutPort; }
+ uint16_t GetInPort() const { return m_InPort; }
+ uint16_t GetOutPort() const { return m_OutPort; }
bool GetQuiet() const { return m_Quiet; }
bool IsRunning() const { return m_IsRunning; }
const i2p::data::PrivateKeys& GetKeys () const { return m_LocalDestination->GetPrivateKeys (); };
@@ -175,7 +175,7 @@
std::string m_Nickname;
std::string m_InHost, m_OutHost;
- int m_InPort, m_OutPort;
+ uint16_t m_InPort, m_OutPort;
bool m_Quiet;
bool m_IsRunning;
};
@@ -228,7 +228,7 @@
void SendReplyError (const char * msg);
void SendRaw (const char * data);
- void BuildStatusLine(bool currentTunnel, BOBDestination *destination, std::string &out);
+ void BuildStatusLine(bool currentTunnel, std::shared_ptr<BOBDestination> destination, std::string &out);
private:
@@ -237,10 +237,10 @@
boost::asio::streambuf m_ReceiveBuffer, m_SendBuffer;
bool m_IsOpen, m_IsQuiet, m_IsActive;
std::string m_Nickname, m_InHost, m_OutHost;
- int m_InPort, m_OutPort;
+ uint16_t m_InPort, m_OutPort;
i2p::data::PrivateKeys m_Keys;
std::map<std::string, std::string> m_Options;
- BOBDestination * m_CurrentDestination;
+ std::shared_ptr<BOBDestination> m_CurrentDestination;
};
typedef void (BOBCommandSession::*BOBCommandHandler)(const char * operand, size_t len);
@@ -248,16 +248,16 @@
{
public:
- BOBCommandChannel (const std::string& address, int port);
+ BOBCommandChannel (const std::string& address, uint16_t port);
~BOBCommandChannel ();
void Start ();
void Stop ();
boost::asio::io_service& GetService () { return GetIOService (); };
- void AddDestination (const std::string& name, BOBDestination * dest);
+ void AddDestination (const std::string& name, std::shared_ptr<BOBDestination> dest);
void DeleteDestination (const std::string& name);
- BOBDestination * FindDestination (const std::string& name);
+ std::shared_ptr<BOBDestination> FindDestination (const std::string& name);
private:
@@ -267,7 +267,7 @@
private:
boost::asio::ip::tcp::acceptor m_Acceptor;
- std::map<std::string, BOBDestination *> m_Destinations;
+ std::map<std::string, std::shared_ptr<BOBDestination> > m_Destinations;
std::map<std::string, BOBCommandHandler> m_CommandHandlers;
std::map<std::string, std::string> m_HelpStrings;
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/ClientContext.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -63,18 +63,19 @@
if (sam)
{
std::string samAddr; i2p::config::GetOption("sam.address", samAddr);
- uint16_t samPort; i2p::config::GetOption("sam.port", samPort);
+ uint16_t samPortTCP; i2p::config::GetOption("sam.port", samPortTCP);
+ uint16_t samPortUDP; i2p::config::GetOption("sam.portudp", samPortUDP);
bool singleThread; i2p::config::GetOption("sam.singlethread", singleThread);
- LogPrint(eLogInfo, "Clients: Starting SAM bridge at ", samAddr, ":", samPort);
+ LogPrint(eLogInfo, "Clients: Starting SAM bridge at ", samAddr, ":[", samPortTCP, "|", samPortUDP, "]");
try
{
- m_SamBridge = new SAMBridge (samAddr, samPort, singleThread);
+ m_SamBridge = new SAMBridge (samAddr, samPortTCP, samPortUDP, singleThread);
m_SamBridge->Start ();
}
catch (std::exception& e)
{
- LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what());
- ThrowFatal ("Unable to start SAM bridge at ", samAddr, ":", samPort, ": ", e.what ());
+ LogPrint(eLogCritical, "Clients: Exception in SAM bridge: ", e.what());
+ ThrowFatal ("Unable to start SAM bridge at ", samAddr, ":[", samPortTCP, "|", samPortUDP,"]: ", e.what ());
}
}
@@ -91,7 +92,7 @@
}
catch (std::exception& e)
{
- LogPrint(eLogError, "Clients: Exception in BOB bridge: ", e.what());
+ LogPrint(eLogCritical, "Clients: Exception in BOB bridge: ", e.what());
ThrowFatal ("Unable to start BOB bridge at ", bobAddr, ":", bobPort, ": ", e.what ());
}
}
@@ -111,7 +112,7 @@
}
catch (std::exception& e)
{
- LogPrint(eLogError, "Clients: Exception in I2CP: ", e.what());
+ LogPrint(eLogCritical, "Clients: Exception in I2CP: ", e.what());
ThrowFatal ("Unable to start I2CP at ", i2cpAddr, ":", i2cpPort, ": ", e.what ());
}
}
@@ -185,22 +186,30 @@
LogPrint(eLogInfo, "Clients: Stopping AddressBook");
m_AddressBook.Stop ();
+ LogPrint(eLogInfo, "Clients: Stopping UDP Tunnels");
{
std::lock_guard<std::mutex> lock(m_ForwardsMutex);
m_ServerForwards.clear();
m_ClientForwards.clear();
}
+ LogPrint(eLogInfo, "Clients: Stopping UDP Tunnels timers");
if (m_CleanupUDPTimer)
{
m_CleanupUDPTimer->cancel ();
m_CleanupUDPTimer = nullptr;
}
- for (auto& it: m_Destinations)
- it.second->Stop ();
- m_Destinations.clear ();
+ {
+ LogPrint(eLogInfo, "Clients: Stopping Destinations");
+ std::lock_guard<std::mutex> lock(m_DestinationsMutex);
+ for (auto& it: m_Destinations)
+ it.second->Stop ();
+ LogPrint(eLogInfo, "Clients: Stopping Destinations - Clear");
+ m_Destinations.clear ();
+ }
+ LogPrint(eLogInfo, "Clients: Stopping SharedLocalDestination");
m_SharedLocalDestination->Release ();
m_SharedLocalDestination = nullptr;
}
@@ -261,7 +270,7 @@
static const std::string transient("transient");
if (!filename.compare (0, transient.length (), transient)) // starts with transient
{
- keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
+ keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true);
LogPrint (eLogInfo, "Clients: New transient keys address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
return true;
}
@@ -278,7 +287,7 @@
s.read ((char *)buf, len);
if(!keys.FromBuffer (buf, len))
{
- LogPrint (eLogError, "Clients: Failed to load keyfile ", filename);
+ LogPrint (eLogCritical, "Clients: Failed to load keyfile ", filename);
success = false;
}
else
@@ -287,8 +296,8 @@
}
else
{
- LogPrint (eLogError, "Clients: Can't open file ", fullPath, " Creating new one with signature type ", sigType, " crypto type ", cryptoType);
- keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
+ LogPrint (eLogCritical, "Clients: Can't open file ", fullPath, " Creating new one with signature type ", sigType, " crypto type ", cryptoType);
+ keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true);
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
size_t len = keys.GetFullLen ();
uint8_t * buf = new uint8_t[len];
@@ -328,7 +337,7 @@
i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType,
const std::map<std::string, std::string> * params)
{
- i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
+ i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true);
auto localDestination = std::make_shared<RunnableClientDestination> (keys, isPublic, params);
AddLocalDestination (localDestination);
return localDestination;
@@ -339,7 +348,7 @@
i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType,
const std::map<std::string, std::string> * params)
{
- i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
+ i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true);
auto localDestination = std::make_shared<ClientDestination> (service, keys, isPublic, params);
AddLocalDestination (localDestination);
return localDestination;
@@ -568,12 +577,12 @@
std::string dest;
if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT)
dest = section.second.get<std::string> (I2P_CLIENT_TUNNEL_DESTINATION);
- int port = section.second.get<int> (I2P_CLIENT_TUNNEL_PORT);
+ uint16_t port = section.second.get<uint16_t> (I2P_CLIENT_TUNNEL_PORT);
// optional params
- bool matchTunnels = section.second.get(I2P_CLIENT_TUNNEL_MATCH_TUNNELS, false);
- std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, "transient");
- std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1");
- int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0);
+ bool matchTunnels = section.second.get (I2P_CLIENT_TUNNEL_MATCH_TUNNELS, false);
+ std::string keys = section.second.get<std::string> (I2P_CLIENT_TUNNEL_KEYS, "transient");
+ std::string address = section.second.get<std::string> (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1");
+ uint16_t destinationPort = section.second.get<uint16_t> (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0);
i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
i2p::data::CryptoKeyType cryptoType = section.second.get (I2P_CLIENT_TUNNEL_CRYPTO_TYPE, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL);
// I2CP
@@ -711,21 +720,22 @@
{
// mandatory params
std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST);
- int port = section.second.get<int> (I2P_SERVER_TUNNEL_PORT);
+ uint16_t port = section.second.get<uint16_t> (I2P_SERVER_TUNNEL_PORT);
std::string keys = section.second.get<std::string> (I2P_SERVER_TUNNEL_KEYS);
// optional params
- int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0);
- std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
+ uint16_t inPort = section.second.get<uint16_t> (I2P_SERVER_TUNNEL_INPORT, port);
+ std::string accessList = section.second.get<std::string> (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
if(accessList == "")
- accessList=section.second.get (I2P_SERVER_TUNNEL_WHITE_LIST, "");
- std::string hostOverride = section.second.get (I2P_SERVER_TUNNEL_HOST_OVERRIDE, "");
+ accessList = section.second.get<std::string> (I2P_SERVER_TUNNEL_WHITE_LIST, "");
+ std::string hostOverride = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST_OVERRIDE, "");
std::string webircpass = section.second.get<std::string> (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, "");
bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, false);
i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
i2p::data::CryptoKeyType cryptoType = section.second.get (I2P_CLIENT_TUNNEL_CRYPTO_TYPE, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL);
std::string address = section.second.get<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "");
- bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
+ bool isUniqueLocal = section.second.get (I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
+ bool ssl = section.second.get (I2P_SERVER_TUNNEL_SSL, false);
// I2CP
std::map<std::string, std::string> options;
@@ -799,11 +809,13 @@
if (!address.empty ())
serverTunnel->SetLocalAddress (address);
- if(!isUniqueLocal)
+ if (!isUniqueLocal)
{
LogPrint(eLogInfo, "Clients: Disabling loopback address mapping");
serverTunnel->SetUniqueLocal(isUniqueLocal);
}
+ if (ssl)
+ serverTunnel->SetSSL (true);
if (accessList.length () > 0)
{
std::set<i2p::data::IdentHash> idents;
@@ -847,7 +859,7 @@
}
catch (std::exception& ex)
{
- LogPrint (eLogError, "Clients: Can't read tunnel ", name, " params: ", ex.what ());
+ LogPrint (eLogCritical, "Clients: Can't read tunnel ", name, " params: ", ex.what ());
ThrowFatal ("Unable to start tunnel ", name, ": ", ex.what ());
}
}
@@ -865,7 +877,7 @@
std::string httpOutProxyURL; i2p::config::GetOption("httpproxy.outproxy", httpOutProxyURL);
bool httpAddresshelper; i2p::config::GetOption("httpproxy.addresshelper", httpAddresshelper);
if (httpAddresshelper)
- i2p::config::GetOption("addressbook.enabled", httpAddresshelper); // addresshelper is not supported without address book
+ i2p::config::GetOption("addressbook.enabled", httpAddresshelper); // addresshelper is not supported without address book
i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType);
LogPrint(eLogInfo, "Clients: Starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort);
if (httpProxyKeys.length () > 0)
@@ -879,7 +891,7 @@
if (localDestination) localDestination->Acquire ();
}
else
- LogPrint(eLogError, "Clients: Failed to load HTTP Proxy key");
+ LogPrint(eLogCritical, "Clients: Failed to load HTTP Proxy key");
}
try
{
@@ -888,7 +900,7 @@
}
catch (std::exception& e)
{
- LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what());
+ LogPrint(eLogCritical, "Clients: Exception in HTTP Proxy: ", e.what());
ThrowFatal ("Unable to start HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort, ": ", e.what ());
}
}
@@ -926,7 +938,7 @@
if (localDestination) localDestination->Acquire ();
}
else
- LogPrint(eLogError, "Clients: Failed to load SOCKS Proxy key");
+ LogPrint(eLogCritical, "Clients: Failed to load SOCKS Proxy key");
}
try
{
@@ -936,7 +948,7 @@
}
catch (std::exception& e)
{
- LogPrint(eLogError, "Clients: Exception in SOCKS Proxy: ", e.what());
+ LogPrint(eLogCritical, "Clients: Exception in SOCKS Proxy: ", e.what());
ThrowFatal ("Unable to start SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort, ": ", e.what ());
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/ClientContext.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -18,6 +18,7 @@
#include "HTTPProxy.h"
#include "SOCKS.h"
#include "I2PTunnel.h"
+#include "UDPTunnel.h"
#include "SAM.h"
#include "BOB.h"
#include "I2CP.h"
@@ -61,7 +62,7 @@
const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword";
const char I2P_SERVER_TUNNEL_ADDRESS[] = "address";
const char I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL[] = "enableuniquelocal";
-
+ const char I2P_SERVER_TUNNEL_SSL[] = "ssl";
class ClientContext
{
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/HTTPProxy.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -36,12 +36,14 @@
"reg.i2p",
"stats.i2p",
"identiguy.i2p",
+ "notbob.i2p"
};
static const std::map<std::string, std::string> jumpservices = {
{ "reg.i2p", "http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/jump/" },
{ "identiguy.i2p", "http://3mzmrus2oron5fxptw7hw2puho3bnqmw2hqy7nw64dsrrjwdilva.b32.i2p/cgi-bin/query?hostname=" },
{ "stats.i2p", "http://7tbay5p4kzeekxvyvbf6v7eauazemsnnl2aoyqhg5jzpr5eke7tq.b32.i2p/cgi-bin/jump.cgi?a=" },
+ { "notbob.i2p", "http://nytzrhrjjfsutowojvxi7hphesskpqqr65wpistz6wa7cpajhp7a.b32.i2p/cgi-bin/jump.cgi?q=" }
};
static const char *pageHead =
@@ -73,15 +75,17 @@
void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
void Terminate();
void AsyncSockRead();
- bool ExtractAddressHelper(i2p::http::URL & url, std::string & b64, bool & confirm);
- void SanitizeHTTPRequest(i2p::http::HTTPReq & req);
+ static bool ExtractAddressHelper(i2p::http::URL& url, std::string& jump, bool& confirm);
+ static bool VerifyAddressHelper (const std::string& jump);
+ static void SanitizeHTTPRequest(i2p::http::HTTPReq& req);
void SentHTTPFailed(const boost::system::error_code & ecode);
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
/* error helpers */
void GenericProxyError(const std::string& title, const std::string& description);
void GenericProxyInfo(const std::string& title, const std::string& description);
- void HostNotFound(std::string & host);
- void SendProxyError(std::string & content);
+ void HostNotFound(std::string& host);
+ void SendProxyError(std::string& content);
+ void SendRedirect(std::string& address);
void ForwardToUpstreamProxy();
void HandleUpstreamHTTPProxyConnect(const boost::system::error_code & ec);
@@ -105,12 +109,12 @@
std::shared_ptr<boost::asio::ip::tcp::socket> m_sock;
std::shared_ptr<boost::asio::ip::tcp::socket> m_proxysock;
boost::asio::ip::tcp::resolver m_proxy_resolver;
- std::string m_OutproxyUrl;
+ std::string m_OutproxyUrl, m_Response;
bool m_Addresshelper;
i2p::http::URL m_ProxyURL;
i2p::http::URL m_RequestURL;
uint8_t m_socks_buf[255+8]; // for socks request/response
- ssize_t m_req_len;
+ int m_req_len;
i2p::http::URL m_ClientRequestURL;
i2p::http::HTTPReq m_ClientRequest;
i2p::http::HTTPRes m_ClientResponse;
@@ -174,7 +178,7 @@
SendProxyError(content);
}
- void HTTPReqHandler::HostNotFound(std::string & host) {
+ void HTTPReqHandler::HostNotFound(std::string& host) {
std::stringstream ss;
ss << "<h1>" << tr("Proxy error: Host not found") << "</h1>\r\n"
<< "<p>" << tr("Remote host not found in router's addressbook") << "</p>\r\n"
@@ -191,7 +195,7 @@
SendProxyError(content);
}
- void HTTPReqHandler::SendProxyError(std::string & content)
+ void HTTPReqHandler::SendProxyError(std::string& content)
{
i2p::http::HTTPRes res;
res.code = 500;
@@ -202,12 +206,23 @@
<< "<body>" << content << "</body>\r\n"
<< "</html>\r\n";
res.body = ss.str();
- std::string response = res.to_string();
- boost::asio::async_write(*m_sock, boost::asio::buffer(response), boost::asio::transfer_all(),
+ m_Response = res.to_string();
+ boost::asio::async_write(*m_sock, boost::asio::buffer(m_Response), boost::asio::transfer_all(),
std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
}
- bool HTTPReqHandler::ExtractAddressHelper(i2p::http::URL & url, std::string & b64, bool & confirm)
+ void HTTPReqHandler::SendRedirect(std::string& address)
+ {
+ i2p::http::HTTPRes res;
+ res.code = 302;
+ res.add_header("Location", address);
+ res.add_header("Connection", "close");
+ m_Response = res.to_string();
+ boost::asio::async_write(*m_sock, boost::asio::buffer(m_Response), boost::asio::transfer_all(),
+ std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
+ }
+
+ bool HTTPReqHandler::ExtractAddressHelper(i2p::http::URL& url, std::string& jump, bool& confirm)
{
confirm = false;
const char *param = "i2paddresshelper=";
@@ -223,20 +238,78 @@
std::string value = params["i2paddresshelper"];
len += value.length();
- b64 = i2p::http::UrlDecode(value);
+ jump = i2p::http::UrlDecode(value);
+ if (!VerifyAddressHelper (jump))
+ {
+ LogPrint (eLogError, "HTTPProxy: Malformed jump link ", jump);
+ return false;
+ }
+
// if we need update exists, request formed with update param
- if (params["update"] == "true") { len += std::strlen("&update=true"); confirm = true; }
- if (pos != 0 && url.query[pos-1] == '&') { pos--; len++; } // if helper is not only one query option
+ if (params["update"] == "true")
+ {
+ len += std::strlen("&update=true");
+ confirm = true;
+ }
+
+ // if helper is not only one query option and it placed after user's query
+ if (pos != 0 && url.query[pos-1] == '&')
+ {
+ pos--;
+ len++;
+ }
+ // if helper is not only one query option and it placed before user's query
+ else if (pos == 0 && url.query.length () > len && url.query[len] == '&')
+ {
+ // we don't touch the '?' but remove the trailing '&'
+ len++;
+ }
+ else
+ {
+ // there is no more query options, resetting hasquery flag
+ url.hasquery = false;
+ }
+
+ // reset hasquery flag and remove addresshelper from URL
url.query.replace(pos, len, "");
return true;
}
- void HTTPReqHandler::SanitizeHTTPRequest(i2p::http::HTTPReq & req)
+ bool HTTPReqHandler::VerifyAddressHelper (const std::string& jump)
+ {
+ auto pos = jump.find(".b32.i2p");
+ if (pos != std::string::npos)
+ {
+ auto b32 = jump.substr (0, pos);
+ for (auto& ch: b32)
+ if (!i2p::data::IsBase32(ch)) return false;
+ return true;
+ }
+ else
+ {
+ bool padding = false;
+ for (auto& ch: jump)
+ {
+ if (ch == '=')
+ padding = true;
+ else
+ {
+ if (padding) return false; // other chars after padding
+ if (!i2p::data::IsBase64(ch)) return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ void HTTPReqHandler::SanitizeHTTPRequest(i2p::http::HTTPReq& req)
{
/* drop common headers */
req.RemoveHeader("Via");
req.RemoveHeader("From");
req.RemoveHeader("Forwarded");
+ req.RemoveHeader("DNT"); // Useless DoNotTrack flag
req.RemoveHeader("Accept", "Accept-Encoding"); // Accept*, but Accept-Encoding
/* drop proxy-disclosing headers */
req.RemoveHeader("X-Forwarded");
@@ -245,6 +318,18 @@
req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)");
/**
+ * i2pd PR #1816:
+ * Android Webview send this with the value set to the application ID, so we drop it,
+ * but only if it does not belong to an AJAX request (*HttpRequest, like XMLHttpRequest).
+ */
+ if(req.GetHeader("X-Requested-With") != "") {
+ auto h = req.GetHeader ("X-Requested-With");
+ auto x = h.find("HttpRequest");
+ if (x == std::string::npos) // not found
+ req.RemoveHeader("X-Requested-With");
+ }
+
+ /**
* according to i2p ticket #1862:
* leave Referer if requested URL with same schema, host and port,
* otherwise, drop it.
@@ -294,28 +379,63 @@
if (!m_Addresshelper)
{
LogPrint(eLogWarning, "HTTPProxy: Addresshelper request rejected");
- GenericProxyError(tr("Invalid request"), tr("addresshelper is not supported"));
+ GenericProxyError(tr("Invalid request"), tr("Addresshelper is not supported"));
+ return true;
+ }
+
+ if (i2p::client::context.GetAddressBook ().RecordExists (m_RequestURL.host, jump))
+ {
+ std::string full_url = m_RequestURL.to_string();
+ SendRedirect(full_url);
return true;
}
- if (!i2p::client::context.GetAddressBook ().FindAddress (m_RequestURL.host) || m_Confirm)
+ else if (!i2p::client::context.GetAddressBook ().FindAddress (m_RequestURL.host) || m_Confirm)
{
+ const std::string referer_raw = m_ClientRequest.GetHeader("Referer");
+ i2p::http::URL referer_url;
+ if (!referer_raw.empty ())
+ {
+ referer_url.parse (referer_raw);
+ }
+ if (m_RequestURL.host != referer_url.host)
+ {
+ if (m_Confirm) // Attempt to forced overwriting by link with "&update=true" from harmful URL
+ {
+ LogPrint (eLogWarning, "HTTPProxy: Address update from addresshelper rejected for ", m_RequestURL.host, " (referer is ", m_RequestURL.host.empty() ? "empty" : "harmful", ")");
+ std::string full_url = m_RequestURL.to_string();
+ std::stringstream ss;
+ ss << tr("Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.",
+ m_RequestURL.host.c_str(), full_url.c_str(), (full_url.find('?') != std::string::npos ? "&i2paddresshelper=" : "?i2paddresshelper="), jump.c_str());
+ GenericProxyInfo(tr("Addresshelper forced update rejected"), ss.str());
+ }
+ else // Preventing unauthorized additions to the address book
+ {
+ LogPrint (eLogDebug, "HTTPProxy: Adding address from addresshelper for ", m_RequestURL.host, " (generate refer-base page)");
+ std::string full_url = m_RequestURL.to_string();
+ std::stringstream ss;
+ ss << tr("To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.",
+ m_RequestURL.host.c_str(), full_url.c_str(), (full_url.find('?') != std::string::npos ? "&i2paddresshelper=" : "?i2paddresshelper="), jump.c_str());
+ GenericProxyInfo(tr("Addresshelper request"), ss.str());
+ }
+ return true; /* request processed */
+ }
+
i2p::client::context.GetAddressBook ().InsertAddress (m_RequestURL.host, jump);
LogPrint (eLogInfo, "HTTPProxy: Added address from addresshelper for ", m_RequestURL.host);
std::string full_url = m_RequestURL.to_string();
std::stringstream ss;
- ss << tr("Host") <<" " << m_RequestURL.host << " " << tr("added to router's addressbook from helper") << ". ";
- ss << tr("Click here to proceed:") << " <a href=\"" << full_url << "\">" << tr("Continue") << "</a>.";
- GenericProxyInfo(tr("Addresshelper found"), ss.str());
+ ss << tr("Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.",
+ m_RequestURL.host.c_str(), full_url.c_str());
+ GenericProxyInfo(tr("Addresshelper adding"), ss.str());
return true; /* request processed */
}
else
{
std::string full_url = m_RequestURL.to_string();
std::stringstream ss;
- ss << tr("Host") << " " << m_RequestURL.host << " <font color=red>" << tr("already in router's addressbook") << "</font>. ";
- ss << tr(/* tr: The "record" means addressbook's record. That message appears when domain was already added to addressbook, but helper link is opened for it. */ "Click here to update record:" ) << " <a href=\"" << full_url << (full_url.find('?') != std::string::npos ? "&i2paddresshelper=" : "?i2paddresshelper=");
- ss << jump << "&update=true\">" << tr("Continue") << "</a>.";
- GenericProxyInfo(tr("Addresshelper found"), ss.str());
+ ss << tr("Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.",
+ m_RequestURL.host.c_str(), full_url.c_str(), (full_url.find('?') != std::string::npos ? "&i2paddresshelper=" : "?i2paddresshelper="), jump.c_str());
+ GenericProxyInfo(tr("Addresshelper update"), ss.str());
return true; /* request processed */
}
}
@@ -328,7 +448,7 @@
auto pos = uri.find(":");
if(pos == std::string::npos || pos == uri.size() - 1)
{
- GenericProxyError(tr("Invalid request"), tr("invalid request uri"));
+ GenericProxyError(tr("Invalid request"), tr("Invalid request URI"));
return true;
}
else
@@ -388,10 +508,10 @@
if(m_ProxyURL.parse(m_OutproxyUrl))
ForwardToUpstreamProxy();
else
- GenericProxyError(tr("Outproxy failure"), tr("bad outproxy settings"));
+ GenericProxyError(tr("Outproxy failure"), tr("Bad outproxy settings"));
} else {
LogPrint (eLogWarning, "HTTPProxy: Outproxy failure for ", dest_host, ": no outproxy enabled");
- std::stringstream ss; ss << tr("Host") << " " << dest_host << " " << tr("not inside I2P network, but outproxy is not enabled");
+ std::stringstream ss; ss << tr("Host %s is not inside I2P network, but outproxy is not enabled", dest_host.c_str());
GenericProxyError(tr("Outproxy failure"), ss.str());
}
return true;
@@ -480,13 +600,13 @@
else
{
/* unknown type, complain */
- GenericProxyError(tr("unknown outproxy url"), m_ProxyURL.to_string());
+ GenericProxyError(tr("Unknown outproxy URL"), m_ProxyURL.to_string());
}
}
void HTTPReqHandler::HandleUpstreamProxyResolved(const boost::system::error_code & ec, boost::asio::ip::tcp::resolver::iterator it, ProxyResolvedHandler handler)
{
- if(ec) GenericProxyError(tr("cannot resolve upstream proxy"), ec.message());
+ if(ec) GenericProxyError(tr("Cannot resolve upstream proxy"), ec.message());
else handler(*it);
}
@@ -494,7 +614,7 @@
{
if(!ec) {
if(m_RequestURL.host.size() > 255) {
- GenericProxyError(tr("hostname too long"), m_RequestURL.host);
+ GenericProxyError(tr("Hostname is too long"), m_RequestURL.host);
return;
}
uint16_t port = m_RequestURL.port;
@@ -521,13 +641,13 @@
reqsize += host.size();
m_socks_buf[++reqsize] = 0;
boost::asio::async_write(*m_proxysock, boost::asio::buffer(m_socks_buf, reqsize), boost::asio::transfer_all(), std::bind(&HTTPReqHandler::HandleSocksProxySendHandshake, this, std::placeholders::_1, std::placeholders::_2));
- } else GenericProxyError(tr("cannot connect to upstream socks proxy"), ec.message());
+ } else GenericProxyError(tr("Cannot connect to upstream SOCKS proxy"), ec.message());
}
void HTTPReqHandler::HandleSocksProxySendHandshake(const boost::system::error_code & ec, std::size_t bytes_transferred)
{
LogPrint(eLogDebug, "HTTPProxy: Upstream SOCKS handshake sent");
- if(ec) GenericProxyError(tr("Cannot negotiate with socks proxy"), ec.message());
+ if(ec) GenericProxyError(tr("Cannot negotiate with SOCKS proxy"), ec.message());
else m_proxysock->async_read_some(boost::asio::buffer(m_socks_buf, 8), std::bind(&HTTPReqHandler::HandleSocksProxyReply, this, std::placeholders::_1, std::placeholders::_2));
}
@@ -569,7 +689,7 @@
}
else
{
- GenericProxyError(tr("CONNECT error"), tr("Failed to Connect"));
+ GenericProxyError(tr("CONNECT error"), tr("Failed to connect"));
}
}
@@ -580,7 +700,7 @@
m_send_buf = m_ClientResponse.to_string();
boost::asio::async_write(*m_sock, boost::asio::buffer(m_send_buf), boost::asio::transfer_all(), [&] (const boost::system::error_code & ec, std::size_t transferred)
{
- if(ec) GenericProxyError(tr("socks proxy error"), ec.message());
+ if(ec) GenericProxyError(tr("SOCKS proxy error"), ec.message());
else HandoverToUpstreamProxy();
});
} else {
@@ -588,7 +708,7 @@
LogPrint(eLogDebug, "HTTPProxy: Send ", m_send_buf.size(), " bytes");
boost::asio::async_write(*m_proxysock, boost::asio::buffer(m_send_buf), boost::asio::transfer_all(), [&](const boost::system::error_code & ec, std::size_t transferred)
{
- if(ec) GenericProxyError(tr("failed to send request to upstream"), ec.message());
+ if(ec) GenericProxyError(tr("Failed to send request to upstream"), ec.message());
else HandoverToUpstreamProxy();
});
}
@@ -606,18 +726,18 @@
ss << "error code: ";
ss << (int) m_socks_buf[1];
std::string msg = ss.str();
- GenericProxyError(tr("socks proxy error"), msg);
+ GenericProxyError(tr("SOCKS proxy error"), msg);
}
}
- else GenericProxyError(tr("No Reply From socks proxy"), ec.message());
+ else GenericProxyError(tr("No reply from SOCKS proxy"), ec.message());
}
void HTTPReqHandler::HandleUpstreamHTTPProxyConnect(const boost::system::error_code & ec)
{
if(!ec) {
LogPrint(eLogDebug, "HTTPProxy: Connected to http upstream");
- GenericProxyError(tr("cannot connect"), tr("http out proxy not implemented"));
- } else GenericProxyError(tr("cannot connect to upstream http proxy"), ec.message());
+ GenericProxyError(tr("Cannot connect"), tr("HTTP out proxy not implemented"));
+ } else GenericProxyError(tr("Cannot connect to upstream HTTP proxy"), ec.message());
}
/* will be called after some data received from client */
@@ -662,7 +782,7 @@
Done (shared_from_this());
}
- HTTPProxy::HTTPProxy(const std::string& name, const std::string& address, int port, const std::string & outproxy, bool addresshelper, std::shared_ptr<i2p::client::ClientDestination> localDestination):
+ HTTPProxy::HTTPProxy(const std::string& name, const std::string& address, uint16_t port, const std::string & outproxy, bool addresshelper, std::shared_ptr<i2p::client::ClientDestination> localDestination):
TCPIPAcceptor (address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()),
m_Name (name), m_OutproxyUrl (outproxy), m_Addresshelper (addresshelper)
{
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/HTTPProxy.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -15,8 +15,8 @@
{
public:
- HTTPProxy(const std::string& name, const std::string& address, int port, const std::string & outproxy, bool addresshelper, std::shared_ptr<i2p::client::ClientDestination> localDestination);
- HTTPProxy(const std::string& name, const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr) :
+ HTTPProxy(const std::string& name, const std::string& address, uint16_t port, const std::string & outproxy, bool addresshelper, std::shared_ptr<i2p::client::ClientDestination> localDestination);
+ HTTPProxy(const std::string& name, const std::string& address, uint16_t port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr) :
HTTPProxy(name, address, port, "", true, localDestination) {} ;
~HTTPProxy() {};
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/I2CP.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -230,7 +230,7 @@
remoteLease->tunnelGateway, remoteLease->tunnelID,
garlic
});
- outboundTunnel->SendTunnelDataMsg (msgs);
+ outboundTunnel->SendTunnelDataMsgs (msgs);
return true;
}
else
@@ -936,7 +936,7 @@
}
}
- I2CPServer::I2CPServer (const std::string& interface, int port, bool isSingleThread):
+ I2CPServer::I2CPServer (const std::string& interface, uint16_t port, bool isSingleThread):
RunnableService ("I2CP"), m_IsSingleThread (isSingleThread),
m_Acceptor (GetIOService (),
boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(interface), port))
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/I2CP.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -210,7 +210,7 @@
{
public:
- I2CPServer (const std::string& interface, int port, bool isSingleThread);
+ I2CPServer (const std::string& interface, uint16_t port, bool isSingleThread);
~I2CPServer ();
void Start ();
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/I2PService.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -107,7 +107,7 @@
m_ReadyTimerTriggered = false;
}
- void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) {
+ void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, uint16_t port) {
assert(streamRequestComplete);
auto address = i2p::client::context.GetAddressBook ().GetAddress (dest);
if (address)
@@ -119,7 +119,7 @@
}
}
- void I2PService::CreateStream(StreamRequestComplete streamRequestComplete, std::shared_ptr<const Address> address, int port)
+ void I2PService::CreateStream(StreamRequestComplete streamRequestComplete, std::shared_ptr<const Address> address, uint16_t port)
{
if(m_ConnectTimeout && !m_LocalDestination->IsReady())
{
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/I2PService.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -59,8 +59,8 @@
if (dest) dest->Acquire ();
m_LocalDestination = dest;
}
- void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port = 0);
- void CreateStream(StreamRequestComplete complete, std::shared_ptr<const Address> address, int port);
+ void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, uint16_t port = 0);
+ void CreateStream(StreamRequestComplete complete, std::shared_ptr<const Address> address, uint16_t port);
inline boost::asio::io_service& GetService () { return m_LocalDestination->GetService (); }
virtual void Start () = 0;
@@ -155,11 +155,11 @@
{
public:
- TCPIPAcceptor (const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination = nullptr) :
+ TCPIPAcceptor (const std::string& address, uint16_t port, std::shared_ptr<ClientDestination> localDestination = nullptr) :
I2PService(localDestination),
m_LocalEndpoint (boost::asio::ip::address::from_string(address), port),
m_Timer (GetService ()) {}
- TCPIPAcceptor (const std::string& address, int port, i2p::data::SigningKeyType kt) :
+ TCPIPAcceptor (const std::string& address, uint16_t port, i2p::data::SigningKeyType kt) :
I2PService(kt),
m_LocalEndpoint (boost::asio::ip::address::from_string(address), port),
m_Timer (GetService ()) {}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/I2PTunnel.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -21,7 +21,7 @@
{
/** set standard socket options */
- static void I2PTunnelSetSocketOptions(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
+ static void I2PTunnelSetSocketOptions (std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{
if (socket && socket->is_open())
{
@@ -31,7 +31,7 @@
}
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
- std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port):
+ std::shared_ptr<const i2p::data::LeaseSet> leaseSet, uint16_t port):
I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()),
m_IsQuiet (true)
{
@@ -46,10 +46,13 @@
}
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
- std::shared_ptr<boost::asio::ip::tcp::socket> socket, const boost::asio::ip::tcp::endpoint& target, bool quiet):
- I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream),
- m_RemoteEndpoint (target), m_IsQuiet (quiet)
- {
+ const boost::asio::ip::tcp::endpoint& target, bool quiet,
+ std::shared_ptr<boost::asio::ssl::context> sslCtx):
+ I2PServiceHandler(owner), m_Stream (stream), m_RemoteEndpoint (target), m_IsQuiet (quiet)
+ {
+ m_Socket = std::make_shared<boost::asio::ip::tcp::socket> (owner->GetService ());
+ if (sslCtx)
+ m_SSL = std::make_shared<boost::asio::ssl::stream<boost::asio::ip::tcp::socket&> > (*m_Socket, *sslCtx);
}
I2PTunnelConnection::~I2PTunnelConnection ()
@@ -69,7 +72,7 @@
Receive ();
}
- static boost::asio::ip::address GetLoopbackAddressFor(const i2p::data::IdentHash & addr)
+ boost::asio::ip::address GetLoopbackAddressFor(const i2p::data::IdentHash & addr)
{
boost::asio::ip::address_v4::bytes_type bytes;
const uint8_t * ident = addr;
@@ -80,24 +83,26 @@
}
#ifdef __linux__
- static void MapToLoopback(const std::shared_ptr<boost::asio::ip::tcp::socket> & sock, const i2p::data::IdentHash & addr)
+ static void MapToLoopback(std::shared_ptr<boost::asio::ip::tcp::socket> sock, const i2p::data::IdentHash & addr)
{
- // bind to 127.x.x.x address
- // where x.x.x are first three bytes from ident
- auto ourIP = GetLoopbackAddressFor(addr);
- boost::system::error_code ec;
- sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0), ec);
- if (ec)
- LogPrint (eLogError, "I2PTunnel: Can't bind ourIP to ", ourIP.to_string (), ": ", ec.message ());
-
+ if (sock)
+ {
+ // bind to 127.x.x.x address
+ // where x.x.x are first three bytes from ident
+ auto ourIP = GetLoopbackAddressFor(addr);
+ boost::system::error_code ec;
+ sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0), ec);
+ if (ec)
+ LogPrint (eLogError, "I2PTunnel: Can't bind ourIP to ", ourIP.to_string (), ": ", ec.message ());
+ }
}
#endif
void I2PTunnelConnection::Connect (bool isUniqueLocal)
{
- I2PTunnelSetSocketOptions(m_Socket);
if (m_Socket)
{
+ I2PTunnelSetSocketOptions (m_Socket);
#ifdef __linux__
if (isUniqueLocal && m_RemoteEndpoint.address ().is_v4 () &&
m_RemoteEndpoint.address ().to_v4 ().to_bytes ()[0] == 127)
@@ -131,6 +136,7 @@
void I2PTunnelConnection::Terminate ()
{
if (Kill()) return;
+ if (m_SSL) m_SSL = nullptr;
if (m_Stream)
{
m_Stream->Close ();
@@ -145,12 +151,17 @@
void I2PTunnelConnection::Receive ()
{
- m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
- std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (),
- std::placeholders::_1, std::placeholders::_2));
+ if (m_SSL)
+ m_SSL->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
+ std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (),
+ std::placeholders::_1, std::placeholders::_2));
+ else
+ m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
+ std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (),
+ std::placeholders::_1, std::placeholders::_2));
}
- void I2PTunnelConnection::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
+ void I2PTunnelConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (ecode)
{
@@ -239,8 +250,12 @@
void I2PTunnelConnection::Write (const uint8_t * buf, size_t len)
{
- boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (),
- std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
+ if (m_SSL)
+ boost::asio::async_write (*m_SSL, boost::asio::buffer (buf, len), boost::asio::transfer_all (),
+ std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
+ else
+ boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (),
+ std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
}
void I2PTunnelConnection::HandleConnect (const boost::system::error_code& ecode)
@@ -253,20 +268,43 @@
else
{
LogPrint (eLogDebug, "I2PTunnel: Connected");
- if (m_IsQuiet)
- StreamReceive ();
+ if (m_SSL)
+ m_SSL->async_handshake (boost::asio::ssl::stream_base::client,
+ std::bind (&I2PTunnelConnection::HandleHandshake, shared_from_this (), std::placeholders::_1));
else
- {
- // send destination first like received from I2P
- std::string dest = m_Stream->GetRemoteIdentity ()->ToBase64 ();
- dest += "\n";
- if(sizeof(m_StreamBuffer) >= dest.size()) {
- memcpy (m_StreamBuffer, dest.c_str (), dest.size ());
- }
- HandleStreamReceive (boost::system::error_code (), dest.size ());
+ Established ();
+ }
+ }
+
+ void I2PTunnelConnection::HandleHandshake (const boost::system::error_code& ecode)
+ {
+ if (ecode)
+ {
+ LogPrint (eLogError, "I2PTunnel: Handshake error: ", ecode.message ());
+ Terminate ();
+ }
+ else
+ {
+ LogPrint (eLogDebug, "I2PTunnel: SSL connected");
+ Established ();
+ }
+ }
+
+ void I2PTunnelConnection::Established ()
+ {
+ if (m_IsQuiet)
+ StreamReceive ();
+ else
+ {
+ // send destination first like received from I2P
+ std::string dest = m_Stream->GetRemoteIdentity ()->ToBase64 ();
+ dest += "\n";
+ if(sizeof(m_StreamBuffer) >= dest.size()) {
+ memcpy (m_StreamBuffer, dest.c_str (), dest.size ());
}
- Receive ();
+ HandleStreamReceive (boost::system::error_code (), dest.size ());
}
+ Receive ();
}
void I2PClientTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len)
@@ -308,7 +346,12 @@
}
}
else
+ {
+ // insert incomplete line back
+ m_InHeader.clear ();
+ m_InHeader << line;
break;
+ }
}
if (endOfHeader)
@@ -321,15 +364,24 @@
m_HeaderSent = true;
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
}
+ else if (m_OutHeader.tellp () < I2P_TUNNEL_HTTP_MAX_HEADER_SIZE)
+ StreamReceive (); // read more header
+ else
+ {
+ LogPrint (eLogError, "I2PTunnel: HTTP header exceeds max size ", I2P_TUNNEL_HTTP_MAX_HEADER_SIZE);
+ Terminate ();
+ }
}
}
I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
- std::shared_ptr<boost::asio::ip::tcp::socket> socket,
- const boost::asio::ip::tcp::endpoint& target, const std::string& host):
- I2PTunnelConnection (owner, stream, socket, target), m_Host (host),
+ const boost::asio::ip::tcp::endpoint& target, const std::string& host,
+ std::shared_ptr<boost::asio::ssl::context> sslCtx):
+ I2PTunnelConnection (owner, stream, target, true, sslCtx), m_Host (host),
m_HeaderSent (false), m_ResponseHeaderSent (false), m_From (stream->GetRemoteIdentity ())
{
+ if (sslCtx)
+ SSL_set_tlsext_host_name(GetSSL ()->native_handle(), host.c_str ());
}
void I2PServerTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len)
@@ -345,7 +397,8 @@
while (!endOfHeader)
{
std::getline(m_InHeader, line);
- if (!m_InHeader.fail ())
+ if (m_InHeader.fail ()) break;
+ if (!m_InHeader.eof ())
{
if (line == "\r") endOfHeader = true;
else
@@ -353,7 +406,7 @@
// strip up some headers
static const std::vector<std::string> excluded // list of excluded headers
{
- "Keep-Alive:", "X-I2P"
+ "Keep-Alive:", "X-I2P"
};
bool matched = false;
for (const auto& it: excluded)
@@ -362,7 +415,7 @@
matched = true;
break;
}
- if (matched) break;
+ if (matched) continue;
// replace some headers
if (!m_Host.empty () && boost::iequals (line.substr (0, 5), "Host:"))
@@ -375,13 +428,18 @@
else
m_OutHeader << "Connection: close\r\n";
connection = true;
- }
- else // forward as is
+ }
+ else // forward as is
m_OutHeader << line << "\n";
}
}
else
+ {
+ // insert incomplete line back
+ m_InHeader.clear ();
+ m_InHeader << line;
break;
+ }
}
if (endOfHeader)
@@ -404,6 +462,13 @@
m_HeaderSent = true;
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
}
+ else if (m_OutHeader.tellp () < I2P_TUNNEL_HTTP_MAX_HEADER_SIZE)
+ StreamReceive (); // read more header
+ else
+ {
+ LogPrint (eLogError, "I2PTunnel: HTTP header exceeds max size ", I2P_TUNNEL_HTTP_MAX_HEADER_SIZE);
+ Terminate ();
+ }
}
}
@@ -421,7 +486,8 @@
while (!endOfHeader)
{
std::getline(m_InHeader, line);
- if (!m_InHeader.fail ())
+ if (m_InHeader.fail ()) break;
+ if (!m_InHeader.eof ())
{
if (line == "\r") endOfHeader = true;
else
@@ -442,7 +508,12 @@
}
}
else
+ {
+ // insert incomplete line back
+ m_InHeader.clear ();
+ m_InHeader << line;
break;
+ }
}
if (endOfHeader)
@@ -460,9 +531,9 @@
}
I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
- std::shared_ptr<boost::asio::ip::tcp::socket> socket,
- const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass):
- I2PTunnelConnection (owner, stream, socket, target), m_From (stream->GetRemoteIdentity ()),
+ const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass,
+ std::shared_ptr<boost::asio::ssl::context> sslCtx):
+ I2PTunnelConnection (owner, stream, target, true, sslCtx), m_From (stream->GetRemoteIdentity ()),
m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass)
{
}
@@ -473,7 +544,8 @@
if (m_NeedsWebIrc)
{
m_NeedsWebIrc = false;
- m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " " << GetSocket ()->local_endpoint ().address () << std::endl;
+ m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ())
+ << " " << GetSocket ()->local_endpoint ().address () << std::endl;
}
m_InPacket.clear ();
@@ -509,7 +581,7 @@
{
public:
I2PClientTunnelHandler (I2PClientTunnel * parent, std::shared_ptr<const Address> address,
- int destinationPort, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
+ uint16_t destinationPort, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
I2PServiceHandler(parent), m_Address(address),
m_DestinationPort (destinationPort), m_Socket(socket) {};
void Handle();
@@ -517,7 +589,7 @@
private:
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
std::shared_ptr<const Address> m_Address;
- int m_DestinationPort;
+ uint16_t m_DestinationPort;
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
};
@@ -558,7 +630,7 @@
}
I2PClientTunnel::I2PClientTunnel (const std::string& name, const std::string& destination,
- const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort):
+ const std::string& address, uint16_t port, std::shared_ptr<ClientDestination> localDestination, uint16_t destinationPort):
TCPIPAcceptor (address, port, localDestination), m_Name (name), m_Destination (destination),
m_DestinationPort (destinationPort), m_KeepAliveInterval (0)
{
@@ -633,10 +705,12 @@
}
I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address,
- int port, std::shared_ptr<ClientDestination> localDestination, int inport, bool gzip):
+ uint16_t port, std::shared_ptr<ClientDestination> localDestination, uint16_t inport, bool gzip):
I2PService (localDestination), m_IsUniqueLocal(true), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false)
{
- m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port, gzip);
+ m_PortDestination = localDestination->GetStreamingDestination (inport);
+ if (!m_PortDestination) // default destination
+ m_PortDestination = localDestination->CreateStreamingDestination (inport, gzip);
}
void I2PServerTunnel::Start ()
@@ -665,7 +739,7 @@
auto localDestination = GetLocalDestination ();
if (localDestination)
localDestination->StopAcceptingStreams ();
-
+
ClearHandlers ();
}
@@ -739,6 +813,17 @@
LogPrint (eLogError, "I2PTunnel: Can't set local address ", localAddress);
}
+ void I2PServerTunnel::SetSSL (bool ssl)
+ {
+ if (ssl)
+ {
+ m_SSLCtx = std::make_shared<boost::asio::ssl::context> (boost::asio::ssl::context::sslv23);
+ m_SSLCtx->set_verify_mode(boost::asio::ssl::context::verify_none);
+ }
+ else
+ m_SSLCtx = nullptr;
+ }
+
void I2PServerTunnel::Accept ()
{
if (m_PortDestination)
@@ -779,13 +864,13 @@
std::shared_ptr<I2PTunnelConnection> I2PServerTunnel::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{
- return std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint ());
+ return std::make_shared<I2PTunnelConnection> (this, stream, GetEndpoint (), true, m_SSLCtx);
}
I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& name, const std::string& address,
- int port, std::shared_ptr<ClientDestination> localDestination,
- const std::string& host, int inport, bool gzip):
+ uint16_t port, std::shared_ptr<ClientDestination> localDestination,
+ const std::string& host, uint16_t inport, bool gzip):
I2PServerTunnel (name, address, port, localDestination, inport, gzip),
m_Host (host)
{
@@ -793,13 +878,12 @@
std::shared_ptr<I2PTunnelConnection> I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{
- return std::make_shared<I2PServerTunnelConnectionHTTP> (this, stream,
- std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), m_Host);
+ return std::make_shared<I2PServerTunnelConnectionHTTP> (this, stream, GetEndpoint (), m_Host, GetSSLCtx ());
}
I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address,
- int port, std::shared_ptr<ClientDestination> localDestination,
- const std::string& webircpass, int inport, bool gzip):
+ uint16_t port, std::shared_ptr<ClientDestination> localDestination,
+ const std::string& webircpass, uint16_t inport, bool gzip):
I2PServerTunnel (name, address, port, localDestination, inport, gzip),
m_WebircPass (webircpass)
{
@@ -807,371 +891,7 @@
std::shared_ptr<I2PTunnelConnection> I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{
- return std::make_shared<I2PTunnelConnectionIRC> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), this->m_WebircPass);
- }
-
- void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
- {
- if (!m_LastSession || m_LastSession->Identity.GetLL()[0] != from.GetIdentHash ().GetLL()[0] || fromPort != m_LastSession->RemotePort)
- {
- std::lock_guard<std::mutex> lock(m_SessionsMutex);
- m_LastSession = ObtainUDPSession(from, toPort, fromPort);
- }
- m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint);
- m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch();
- }
-
- void I2PUDPServerTunnel::HandleRecvFromI2PRaw (uint16_t, uint16_t, const uint8_t * buf, size_t len)
- {
- if (m_LastSession)
- {
- m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint);
- m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch();
- }
- }
-
- void I2PUDPServerTunnel::ExpireStale(const uint64_t delta)
- {
- std::lock_guard<std::mutex> lock(m_SessionsMutex);
- uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
- auto itr = m_Sessions.begin();
- while(itr != m_Sessions.end()) {
- if(now - (*itr)->LastActivity >= delta )
- itr = m_Sessions.erase(itr);
- else
- ++itr;
- }
- }
-
- void I2PUDPClientTunnel::ExpireStale(const uint64_t delta)
- {
- std::lock_guard<std::mutex> lock(m_SessionsMutex);
- uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
- std::vector<uint16_t> removePorts;
- for (const auto & s : m_Sessions) {
- if (now - s.second->second >= delta)
- removePorts.push_back(s.first);
- }
- for(auto port : removePorts) {
- m_Sessions.erase(port);
- }
- }
-
- UDPSessionPtr I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort)
- {
- auto ih = from.GetIdentHash();
- for (auto & s : m_Sessions )
- {
- if (s->Identity.GetLL()[0] == ih.GetLL()[0] && remotePort == s->RemotePort)
- {
- /** found existing session */
- LogPrint(eLogDebug, "UDPServer: Found session ", s->IPSocket.local_endpoint(), " ", ih.ToBase32());
- return s;
- }
- }
- boost::asio::ip::address addr;
- /** create new udp session */
- if(m_IsUniqueLocal && m_LocalAddress.is_loopback())
- {
- auto ident = from.GetIdentHash();
- addr = GetLoopbackAddressFor(ident);
- }
- else
- addr = m_LocalAddress;
- boost::asio::ip::udp::endpoint ep(addr, 0);
- m_Sessions.push_back(std::make_shared<UDPSession>(ep, m_LocalDest, m_RemoteEndpoint, &ih, localPort, remotePort));
- auto & back = m_Sessions.back();
- return back;
- }
-
- UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint,
- const std::shared_ptr<i2p::client::ClientDestination> & localDestination,
- boost::asio::ip::udp::endpoint endpoint, const i2p::data::IdentHash * to,
- uint16_t ourPort, uint16_t theirPort) :
- m_Destination(localDestination->GetDatagramDestination()),
- IPSocket(localDestination->GetService(), localEndpoint),
- SendEndpoint(endpoint),
- LastActivity(i2p::util::GetMillisecondsSinceEpoch()),
- LocalPort(ourPort),
- RemotePort(theirPort)
- {
- IPSocket.set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU ));
- memcpy(Identity, to->data(), 32);
- Receive();
- }
-
- void UDPSession::Receive()
- {
- LogPrint(eLogDebug, "UDPSession: Receive");
- IPSocket.async_receive_from(boost::asio::buffer(m_Buffer, I2P_UDP_MAX_MTU),
- FromEndpoint, std::bind(&UDPSession::HandleReceived, this, std::placeholders::_1, std::placeholders::_2));
- }
-
- void UDPSession::HandleReceived(const boost::system::error_code & ecode, std::size_t len)
- {
- if(!ecode)
- {
- LogPrint(eLogDebug, "UDPSession: Forward ", len, "B from ", FromEndpoint);
- auto ts = i2p::util::GetMillisecondsSinceEpoch();
- auto session = m_Destination->GetSession (Identity);
- if (ts > LastActivity + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL)
- m_Destination->SendDatagram(session, m_Buffer, len, LocalPort, RemotePort);
- else
- m_Destination->SendRawDatagram(session, m_Buffer, len, LocalPort, RemotePort);
- size_t numPackets = 0;
- while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE)
- {
- boost::system::error_code ec;
- size_t moreBytes = IPSocket.available(ec);
- if (ec || !moreBytes) break;
- len = IPSocket.receive_from (boost::asio::buffer (m_Buffer, I2P_UDP_MAX_MTU), FromEndpoint, 0, ec);
- m_Destination->SendRawDatagram (session, m_Buffer, len, LocalPort, RemotePort);
- numPackets++;
- }
- if (numPackets > 0)
- LogPrint(eLogDebug, "UDPSession: Forward more ", numPackets, "packets B from ", FromEndpoint);
- m_Destination->FlushSendQueue (session);
- LastActivity = ts;
- Receive();
- }
- else
- LogPrint(eLogError, "UDPSession: ", ecode.message());
- }
-
- I2PUDPServerTunnel::I2PUDPServerTunnel (const std::string & name, std::shared_ptr<i2p::client::ClientDestination> localDestination,
- boost::asio::ip::address localAddress, boost::asio::ip::udp::endpoint forwardTo, uint16_t port, bool gzip) :
- m_IsUniqueLocal (true), m_Name (name), m_LocalAddress (localAddress),
- m_RemoteEndpoint (forwardTo), m_LocalDest (localDestination), m_Gzip (gzip)
- {
- }
-
- I2PUDPServerTunnel::~I2PUDPServerTunnel ()
- {
- Stop ();
- }
-
- void I2PUDPServerTunnel::Start ()
- {
- m_LocalDest->Start ();
-
- auto dgram = m_LocalDest->CreateDatagramDestination (m_Gzip);
- dgram->SetReceiver (std::bind (&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
- dgram->SetRawReceiver (std::bind (&I2PUDPServerTunnel::HandleRecvFromI2PRaw, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
- }
-
- void I2PUDPServerTunnel::Stop ()
- {
- auto dgram = m_LocalDest->GetDatagramDestination ();
- if (dgram) dgram->ResetReceiver ();
- }
-
- std::vector<std::shared_ptr<DatagramSessionInfo> > I2PUDPServerTunnel::GetSessions ()
- {
- std::vector<std::shared_ptr<DatagramSessionInfo> > sessions;
- std::lock_guard<std::mutex> lock (m_SessionsMutex);
-
- for (UDPSessionPtr s: m_Sessions)
- {
- if (!s->m_Destination) continue;
- auto info = s->m_Destination->GetInfoForRemote (s->Identity);
- if (!info) continue;
-
- auto sinfo = std::make_shared<DatagramSessionInfo> ();
- sinfo->Name = m_Name;
- sinfo->LocalIdent = std::make_shared<i2p::data::IdentHash> (m_LocalDest->GetIdentHash ().data ());
- sinfo->RemoteIdent = std::make_shared<i2p::data::IdentHash> (s->Identity.data ());
- sinfo->CurrentIBGW = info->IBGW;
- sinfo->CurrentOBEP = info->OBEP;
- sessions.push_back (sinfo);
- }
- return sessions;
- }
-
- I2PUDPClientTunnel::I2PUDPClientTunnel (const std::string & name, const std::string &remoteDest,
- boost::asio::ip::udp::endpoint localEndpoint,
- std::shared_ptr<i2p::client::ClientDestination> localDestination,
- uint16_t remotePort, bool gzip) :
- m_Name (name), m_RemoteDest (remoteDest), m_LocalDest (localDestination), m_LocalEndpoint (localEndpoint),
- m_RemoteIdent (nullptr), m_ResolveThread (nullptr), m_LocalSocket (nullptr), RemotePort (remotePort),
- m_LastPort (0), m_cancel_resolve (false), m_Gzip (gzip)
- {
- }
-
- I2PUDPClientTunnel::~I2PUDPClientTunnel ()
- {
- Stop ();
- }
-
- void I2PUDPClientTunnel::Start ()
- {
- // Reset flag in case of tunnel reload
- if (m_cancel_resolve) m_cancel_resolve = false;
-
- m_LocalSocket.reset (new boost::asio::ip::udp::socket (m_LocalDest->GetService (), m_LocalEndpoint));
- m_LocalSocket->set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU));
- m_LocalSocket->set_option (boost::asio::socket_base::reuse_address (true));
-
- auto dgram = m_LocalDest->CreateDatagramDestination (m_Gzip);
- dgram->SetReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2P, this,
- std::placeholders::_1, std::placeholders::_2,
- std::placeholders::_3, std::placeholders::_4,
- std::placeholders::_5));
- dgram->SetRawReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2PRaw, this,
- std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
-
- m_LocalDest->Start ();
- if (m_ResolveThread == nullptr)
- m_ResolveThread = new std::thread (std::bind (&I2PUDPClientTunnel::TryResolving, this));
- RecvFromLocal ();
- }
-
- void I2PUDPClientTunnel::Stop ()
- {
- auto dgram = m_LocalDest->GetDatagramDestination ();
- if (dgram) dgram->ResetReceiver ();
- m_cancel_resolve = true;
-
- m_Sessions.clear();
-
- if(m_LocalSocket && m_LocalSocket->is_open ())
- m_LocalSocket->close ();
-
- if(m_ResolveThread)
- {
- m_ResolveThread->join ();
- delete m_ResolveThread;
- m_ResolveThread = nullptr;
- }
- if (m_RemoteIdent)
- {
- delete m_RemoteIdent;
- m_RemoteIdent = nullptr;
- }
- }
-
- void I2PUDPClientTunnel::RecvFromLocal ()
- {
- m_LocalSocket->async_receive_from (boost::asio::buffer (m_RecvBuff, I2P_UDP_MAX_MTU),
- m_RecvEndpoint, std::bind (&I2PUDPClientTunnel::HandleRecvFromLocal, this, std::placeholders::_1, std::placeholders::_2));
- }
-
- void I2PUDPClientTunnel::HandleRecvFromLocal (const boost::system::error_code & ec, std::size_t transferred)
- {
- if (m_cancel_resolve) {
- LogPrint (eLogDebug, "UDP Client: Ignoring incomming data: stopping");
- return;
- }
- if (ec) {
- LogPrint (eLogError, "UDP Client: Reading from socket error: ", ec.message (), ". Restarting listener...");
- RecvFromLocal (); // Restart listener and continue work
- return;
- }
- if (!m_RemoteIdent) {
- LogPrint (eLogWarning, "UDP Client: Remote endpoint not resolved yet");
- RecvFromLocal ();
- return; // drop, remote not resolved
- }
- auto remotePort = m_RecvEndpoint.port ();
- if (!m_LastPort || m_LastPort != remotePort)
- {
- auto itr = m_Sessions.find (remotePort);
- if (itr != m_Sessions.end ())
- m_LastSession = itr->second;
- else
- {
- m_LastSession = std::make_shared<UDPConvo> (boost::asio::ip::udp::endpoint (m_RecvEndpoint), 0);
- m_Sessions.emplace (remotePort, m_LastSession);
- }
- m_LastPort = remotePort;
- }
- // send off to remote i2p destination
- auto ts = i2p::util::GetMillisecondsSinceEpoch ();
- LogPrint (eLogDebug, "UDP Client: Send ", transferred, " to ", m_RemoteIdent->ToBase32 (), ":", RemotePort);
- auto session = m_LocalDest->GetDatagramDestination ()->GetSession (*m_RemoteIdent);
- if (ts > m_LastSession->second + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL)
- m_LocalDest->GetDatagramDestination ()->SendDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
- else
- m_LocalDest->GetDatagramDestination ()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
- size_t numPackets = 0;
- while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE)
- {
- boost::system::error_code ec;
- size_t moreBytes = m_LocalSocket->available (ec);
- if (ec || !moreBytes) break;
- transferred = m_LocalSocket->receive_from (boost::asio::buffer (m_RecvBuff, I2P_UDP_MAX_MTU), m_RecvEndpoint, 0, ec);
- remotePort = m_RecvEndpoint.port ();
- // TODO: check remotePort
- m_LocalDest->GetDatagramDestination ()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
- numPackets++;
- }
- if (numPackets)
- LogPrint (eLogDebug, "UDP Client: Sent ", numPackets, " more packets to ", m_RemoteIdent->ToBase32 ());
- m_LocalDest->GetDatagramDestination ()->FlushSendQueue (session);
-
- // mark convo as active
- if (m_LastSession)
- m_LastSession->second = ts;
- RecvFromLocal ();
- }
-
- std::vector<std::shared_ptr<DatagramSessionInfo> > I2PUDPClientTunnel::GetSessions ()
- {
- // TODO: implement
- std::vector<std::shared_ptr<DatagramSessionInfo> > infos;
- return infos;
- }
-
- void I2PUDPClientTunnel::TryResolving ()
- {
- i2p::util::SetThreadName ("UDP Resolver");
- LogPrint (eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest);
-
- std::shared_ptr<const Address> addr;
- while (!(addr = context.GetAddressBook().GetAddress(m_RemoteDest)) && !m_cancel_resolve)
- {
- LogPrint (eLogWarning, "UDP Tunnel: Failed to lookup ", m_RemoteDest);
- std::this_thread::sleep_for (std::chrono::seconds (1));
- }
- if (m_cancel_resolve)
- {
- LogPrint(eLogError, "UDP Tunnel: Lookup of ", m_RemoteDest, " was cancelled");
- return;
- }
- if (!addr || !addr->IsIdentHash ())
- {
- LogPrint (eLogError, "UDP Tunnel: ", m_RemoteDest, " not found");
- return;
- }
- m_RemoteIdent = new i2p::data::IdentHash;
- *m_RemoteIdent = addr->identHash;
- LogPrint(eLogInfo, "UDP Tunnel: Resolved ", m_RemoteDest, " to ", m_RemoteIdent->ToBase32 ());
- }
-
- void I2PUDPClientTunnel::HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
- {
- if (m_RemoteIdent && from.GetIdentHash() == *m_RemoteIdent)
- HandleRecvFromI2PRaw (fromPort, toPort, buf, len);
- else
- LogPrint(eLogWarning, "UDP Client: Unwarranted traffic from ", from.GetIdentHash().ToBase32 ());
- }
-
- void I2PUDPClientTunnel::HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
- {
- auto itr = m_Sessions.find (toPort);
- // found convo ?
- if (itr != m_Sessions.end ())
- {
- // found convo
- if (len > 0)
- {
- LogPrint (eLogDebug, "UDP Client: Got ", len, "B from ", m_RemoteIdent ? m_RemoteIdent->ToBase32 () : "");
- m_LocalSocket->send_to (boost::asio::buffer (buf, len), itr->second->first);
- // mark convo as active
- itr->second->second = i2p::util::GetMillisecondsSinceEpoch ();
- }
- }
- else
- LogPrint (eLogWarning, "UDP Client: Not tracking udp session using port ", (int) toPort);
+ return std::make_shared<I2PTunnelConnectionIRC> (this, stream, GetEndpoint (), m_WebircPass, GetSSLCtx ());
}
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/I2PTunnel.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -16,9 +16,9 @@
#include <memory>
#include <sstream>
#include <boost/asio.hpp>
+#include <boost/asio/ssl.hpp>
#include "Identity.h"
#include "Destination.h"
-#include "Datagram.h"
#include "Streaming.h"
#include "I2PService.h"
#include "AddressBook.h"
@@ -34,17 +34,19 @@
const char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64
const char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64
const char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // .b32.i2p address
+ const int I2P_TUNNEL_HTTP_MAX_HEADER_SIZE = 8192;
class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this<I2PTunnelConnection>
{
public:
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
- std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port = 0); // to I2P
+ std::shared_ptr<const i2p::data::LeaseSet> leaseSet, uint16_t port = 0); // to I2P
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<i2p::stream::Stream> stream); // to I2P using simplified API
- I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
- const boost::asio::ip::tcp::endpoint& target, bool quiet = true); // from I2P
+ I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
+ const boost::asio::ip::tcp::endpoint& target, bool quiet = true,
+ std::shared_ptr<boost::asio::ssl::context> sslCtx = nullptr); // from I2P
~I2PTunnelConnection ();
void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0);
void Connect (bool isUniqueLocal = true);
@@ -55,21 +57,27 @@
void Terminate ();
void Receive ();
- void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
+ void StreamReceive ();
virtual void Write (const uint8_t * buf, size_t len); // can be overloaded
- void HandleWrite (const boost::system::error_code& ecode);
virtual void WriteToStream (const uint8_t * buf, size_t len); // can be overloaded
- void StreamReceive ();
- void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
- void HandleConnect (const boost::system::error_code& ecode);
+ std::shared_ptr<boost::asio::ip::tcp::socket> GetSocket () const { return m_Socket; };
+ std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket&> > GetSSL () const { return m_SSL; };
+
+ private:
- std::shared_ptr<const boost::asio::ip::tcp::socket> GetSocket () const { return m_Socket; };
+ void HandleConnect (const boost::system::error_code& ecode);
+ void HandleHandshake (const boost::system::error_code& ecode);
+ void Established ();
+ void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
+ void HandleWrite (const boost::system::error_code& ecode);
+ void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
private:
uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE];
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
+ std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket&> > m_SSL;
std::shared_ptr<i2p::stream::Stream> m_Stream;
boost::asio::ip::tcp::endpoint m_RemoteEndpoint;
bool m_IsQuiet; // don't send destination
@@ -99,8 +107,8 @@
public:
I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
- std::shared_ptr<boost::asio::ip::tcp::socket> socket,
- const boost::asio::ip::tcp::endpoint& target, const std::string& host);
+ const boost::asio::ip::tcp::endpoint& target, const std::string& host,
+ std::shared_ptr<boost::asio::ssl::context> sslCtx = nullptr);
protected:
@@ -120,8 +128,8 @@
public:
I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
- std::shared_ptr<boost::asio::ip::tcp::socket> socket,
- const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass);
+ const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass,
+ std::shared_ptr<boost::asio::ssl::context> sslCtx = nullptr);
protected:
@@ -146,7 +154,7 @@
public:
I2PClientTunnel (const std::string& name, const std::string& destination,
- const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort = 0);
+ const std::string& address, uint16_t port, std::shared_ptr<ClientDestination> localDestination, uint16_t destinationPort = 0);
~I2PClientTunnel () {}
void Start ();
@@ -166,173 +174,17 @@
std::string m_Name, m_Destination;
std::shared_ptr<const Address> m_Address;
- int m_DestinationPort;
+ uint16_t m_DestinationPort;
uint32_t m_KeepAliveInterval;
std::unique_ptr<boost::asio::deadline_timer> m_KeepAliveTimer;
};
-
- /** 2 minute timeout for udp sessions */
- const uint64_t I2P_UDP_SESSION_TIMEOUT = 1000 * 60 * 2;
- const uint64_t I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL = 100; // in milliseconds
-
- /** max size for i2p udp */
- const size_t I2P_UDP_MAX_MTU = 64*1024;
-
- struct UDPSession
- {
- i2p::datagram::DatagramDestination * m_Destination;
- boost::asio::ip::udp::socket IPSocket;
- i2p::data::IdentHash Identity;
- boost::asio::ip::udp::endpoint FromEndpoint;
- boost::asio::ip::udp::endpoint SendEndpoint;
- uint64_t LastActivity;
-
- uint16_t LocalPort;
- uint16_t RemotePort;
-
- uint8_t m_Buffer[I2P_UDP_MAX_MTU];
-
- UDPSession(boost::asio::ip::udp::endpoint localEndpoint,
- const std::shared_ptr<i2p::client::ClientDestination> & localDestination,
- boost::asio::ip::udp::endpoint remote, const i2p::data::IdentHash * ident,
- uint16_t ourPort, uint16_t theirPort);
- void HandleReceived(const boost::system::error_code & ecode, std::size_t len);
- void Receive();
- };
-
-
- /** read only info about a datagram session */
- struct DatagramSessionInfo
- {
- /** the name of this forward */
- std::string Name;
- /** ident hash of local destination */
- std::shared_ptr<const i2p::data::IdentHash> LocalIdent;
- /** ident hash of remote destination */
- std::shared_ptr<const i2p::data::IdentHash> RemoteIdent;
- /** ident hash of IBGW in use currently in this session or nullptr if none is set */
- std::shared_ptr<const i2p::data::IdentHash> CurrentIBGW;
- /** ident hash of OBEP in use for this session or nullptr if none is set */
- std::shared_ptr<const i2p::data::IdentHash> CurrentOBEP;
- /** i2p router's udp endpoint */
- boost::asio::ip::udp::endpoint LocalEndpoint;
- /** client's udp endpoint */
- boost::asio::ip::udp::endpoint RemoteEndpoint;
- /** how long has this converstation been idle in ms */
- uint64_t idle;
- };
-
- typedef std::shared_ptr<UDPSession> UDPSessionPtr;
-
- /** server side udp tunnel, many i2p inbound to 1 ip outbound */
- class I2PUDPServerTunnel
- {
- public:
-
- I2PUDPServerTunnel (const std::string & name,
- std::shared_ptr<i2p::client::ClientDestination> localDestination,
- boost::asio::ip::address localAddress,
- boost::asio::ip::udp::endpoint forwardTo, uint16_t port, bool gzip);
- ~I2PUDPServerTunnel ();
-
- /** expire stale udp conversations */
- void ExpireStale (const uint64_t delta=I2P_UDP_SESSION_TIMEOUT);
- void Start ();
- void Stop ();
- const char * GetName () const { return m_Name.c_str(); }
- std::vector<std::shared_ptr<DatagramSessionInfo> > GetSessions ();
- std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDest; }
-
- void SetUniqueLocal (bool isUniqueLocal = true) { m_IsUniqueLocal = isUniqueLocal; }
-
- private:
-
- void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
- void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
- UDPSessionPtr ObtainUDPSession (const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort);
-
- private:
-
- bool m_IsUniqueLocal;
- const std::string m_Name;
- boost::asio::ip::address m_LocalAddress;
- boost::asio::ip::udp::endpoint m_RemoteEndpoint;
- std::mutex m_SessionsMutex;
- std::vector<UDPSessionPtr> m_Sessions;
- std::shared_ptr<i2p::client::ClientDestination> m_LocalDest;
- UDPSessionPtr m_LastSession;
- bool m_Gzip;
-
- public:
-
- bool isUpdated; // transient, used during reload only
- };
-
- class I2PUDPClientTunnel
- {
- public:
-
- I2PUDPClientTunnel (const std::string & name, const std::string &remoteDest,
- boost::asio::ip::udp::endpoint localEndpoint, std::shared_ptr<i2p::client::ClientDestination> localDestination,
- uint16_t remotePort, bool gzip);
- ~I2PUDPClientTunnel ();
-
- void Start ();
- void Stop ();
- const char * GetName () const { return m_Name.c_str(); }
- std::vector<std::shared_ptr<DatagramSessionInfo> > GetSessions ();
-
- bool IsLocalDestination (const i2p::data::IdentHash & destination) const { return destination == m_LocalDest->GetIdentHash(); }
-
- std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDest; }
- inline void SetLocalDestination (std::shared_ptr<ClientDestination> dest)
- {
- if (m_LocalDest) m_LocalDest->Release ();
- if (dest) dest->Acquire ();
- m_LocalDest = dest;
- }
-
- void ExpireStale (const uint64_t delta=I2P_UDP_SESSION_TIMEOUT);
-
- private:
-
- typedef std::pair<boost::asio::ip::udp::endpoint, uint64_t> UDPConvo;
- void RecvFromLocal ();
- void HandleRecvFromLocal (const boost::system::error_code & e, std::size_t transferred);
- void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
- void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
- void TryResolving ();
-
- private:
-
- const std::string m_Name;
- std::mutex m_SessionsMutex;
- std::unordered_map<uint16_t, std::shared_ptr<UDPConvo> > m_Sessions; // maps i2p port -> local udp convo
- const std::string m_RemoteDest;
- std::shared_ptr<i2p::client::ClientDestination> m_LocalDest;
- const boost::asio::ip::udp::endpoint m_LocalEndpoint;
- i2p::data::IdentHash * m_RemoteIdent;
- std::thread * m_ResolveThread;
- std::unique_ptr<boost::asio::ip::udp::socket> m_LocalSocket;
- boost::asio::ip::udp::endpoint m_RecvEndpoint;
- uint8_t m_RecvBuff[I2P_UDP_MAX_MTU];
- uint16_t RemotePort, m_LastPort;
- bool m_cancel_resolve;
- bool m_Gzip;
- std::shared_ptr<UDPConvo> m_LastSession;
-
- public:
-
- bool isUpdated; // transient, used during reload only
- };
-
class I2PServerTunnel: public I2PService
{
public:
- I2PServerTunnel (const std::string& name, const std::string& address, int port,
- std::shared_ptr<ClientDestination> localDestination, int inport = 0, bool gzip = true);
+ I2PServerTunnel (const std::string& name, const std::string& address, uint16_t port,
+ std::shared_ptr<ClientDestination> localDestination, uint16_t inport = 0, bool gzip = true);
void Start ();
void Stop ();
@@ -342,10 +194,13 @@
void SetUniqueLocal (bool isUniqueLocal) { m_IsUniqueLocal = isUniqueLocal; }
bool IsUniqueLocal () const { return m_IsUniqueLocal; }
+ void SetSSL (bool ssl);
+ std::shared_ptr<boost::asio::ssl::context> GetSSLCtx () const { return m_SSLCtx; };
+
void SetLocalAddress (const std::string& localAddress);
const std::string& GetAddress() const { return m_Address; }
- int GetPort () const { return m_Port; };
+ uint16_t GetPort () const { return m_Port; };
uint16_t GetLocalPort () const { return m_PortDestination->GetLocalPort (); };
const boost::asio::ip::tcp::endpoint& GetEndpoint () const { return m_Endpoint; }
@@ -364,21 +219,22 @@
bool m_IsUniqueLocal;
std::string m_Name, m_Address;
- int m_Port;
+ uint16_t m_Port;
boost::asio::ip::tcp::endpoint m_Endpoint;
std::shared_ptr<i2p::stream::StreamingDestination> m_PortDestination;
std::set<i2p::data::IdentHash> m_AccessList;
bool m_IsAccessList;
std::unique_ptr<boost::asio::ip::address> m_LocalAddress;
+ std::shared_ptr<boost::asio::ssl::context> m_SSLCtx;
};
class I2PServerTunnelHTTP: public I2PServerTunnel
{
public:
- I2PServerTunnelHTTP (const std::string& name, const std::string& address, int port,
+ I2PServerTunnelHTTP (const std::string& name, const std::string& address, uint16_t port,
std::shared_ptr<ClientDestination> localDestination, const std::string& host,
- int inport = 0, bool gzip = true);
+ uint16_t inport = 0, bool gzip = true);
private:
@@ -393,9 +249,9 @@
{
public:
- I2PServerTunnelIRC (const std::string& name, const std::string& address, int port,
+ I2PServerTunnelIRC (const std::string& name, const std::string& address, uint16_t port,
std::shared_ptr<ClientDestination> localDestination, const std::string& webircpass,
- int inport = 0, bool gzip = true);
+ uint16_t inport = 0, bool gzip = true);
private:
@@ -405,6 +261,8 @@
std::string m_WebircPass;
};
+
+ boost::asio::ip::address GetLoopbackAddressFor(const i2p::data::IdentHash & addr);
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/MatchedDestination.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -72,8 +72,9 @@
bool MatchedTunnelDestination::SelectPeers(i2p::tunnel::Path & path, int hops, bool inbound)
{
auto pool = GetTunnelPool();
- if(!i2p::tunnel::StandardSelectPeers(path, hops, inbound,
- std::bind(&i2p::tunnel::TunnelPool::SelectNextHop, pool, std::placeholders::_1, std::placeholders::_2)))
+ if(!pool || !pool->StandardSelectPeers(path, hops, inbound,
+ std::bind(&i2p::tunnel::TunnelPool::SelectNextHop, pool, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3)))
return false;
// more here for outbound tunnels
if(!inbound && m_RemoteLeaseSet)
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/SAM.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2022, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -360,7 +360,7 @@
if (type == eSAMSessionTypeUnknown)
{
// unknown style
- SendI2PError("Unknown STYLE");
+ SendSessionI2PError("Unknown STYLE");
return;
}
@@ -375,14 +375,14 @@
if (e)
{
// not an ip address
- SendI2PError("Invalid IP Address in HOST");
+ SendSessionI2PError("Invalid IP Address in HOST");
return;
}
auto port = std::stoi(params[SAM_PARAM_PORT]);
if (port == -1)
{
- SendI2PError("Invalid port");
+ SendSessionI2PError("Invalid port");
return;
}
forward = std::make_shared<boost::asio::ip::udp::endpoint>(addr, port);
@@ -440,18 +440,23 @@
{
if (ecode != boost::asio::error::operation_aborted)
{
- auto session = m_Owner.FindSession(m_ID);
- if(session)
+ if (m_Socket.is_open ())
{
- if (session->GetLocalDestination ()->IsReady ())
- SendSessionCreateReplyOk ();
- else
+ auto session = m_Owner.FindSession(m_ID);
+ if(session)
{
- m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
- m_Timer.async_wait (std::bind (&SAMSocket::HandleSessionReadinessCheckTimer,
- shared_from_this (), std::placeholders::_1));
+ if (session->GetLocalDestination ()->IsReady ())
+ SendSessionCreateReplyOk ();
+ else
+ {
+ m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
+ m_Timer.async_wait (std::bind (&SAMSocket::HandleSessionReadinessCheckTimer,
+ shared_from_this (), std::placeholders::_1));
+ }
}
}
+ else
+ Terminate ("SAM: session socket closed");
}
}
@@ -479,7 +484,7 @@
LogPrint (eLogDebug, "SAM: Stream connect: ", buf);
if ( m_SocketType != eSAMSocketTypeUnknown)
{
- SendI2PError ("Socket already in use");
+ SendSessionI2PError ("Socket already in use");
return;
}
std::map<std::string, std::string> params;
@@ -577,7 +582,7 @@
LogPrint (eLogDebug, "SAM: Stream accept: ", buf);
if ( m_SocketType != eSAMSocketTypeUnknown)
{
- SendI2PError ("Socket already in use");
+ SendSessionI2PError ("Socket already in use");
return;
}
std::map<std::string, std::string> params;
@@ -593,9 +598,31 @@
if (!session->GetLocalDestination ()->IsAcceptingStreams ())
{
m_IsAccepting = true;
+ SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
session->GetLocalDestination ()->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1));
}
- SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
+ else
+ {
+ auto ts = i2p::util::GetSecondsSinceEpoch ();
+ while (!session->acceptQueue.empty () && session->acceptQueue.front ().second + SAM_SESSION_MAX_ACCEPT_INTERVAL > ts)
+ {
+ auto socket = session->acceptQueue.front ().first;
+ session->acceptQueue.pop_front ();
+ if (socket)
+ m_Owner.GetService ().post (std::bind(&SAMSocket::TerminateClose, socket));
+ }
+ if (session->acceptQueue.size () < SAM_SESSION_MAX_ACCEPT_QUEUE_SIZE)
+ {
+ // already accepting, queue up
+ SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
+ session->acceptQueue.push_back (std::make_pair(shared_from_this(), ts));
+ }
+ else
+ {
+ LogPrint (eLogInfo, "SAM: Session ", m_ID, " accept queue is full ", session->acceptQueue.size ());
+ SendStreamI2PError ("Already accepting");
+ }
+ }
}
else
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
@@ -615,26 +642,26 @@
}
if (session->GetLocalDestination ()->IsAcceptingStreams ())
{
- SendI2PError ("Already accepting");
+ SendSessionI2PError ("Already accepting");
return;
}
auto it = params.find (SAM_PARAM_PORT);
if (it == params.end ())
{
- SendI2PError ("PORT is missing");
+ SendSessionI2PError ("PORT is missing");
return;
}
auto port = std::stoi (it->second);
if (port <= 0 || port >= 0xFFFF)
{
- SendI2PError ("Invalid PORT");
+ SendSessionI2PError ("Invalid PORT");
return;
}
boost::system::error_code ec;
auto ep = m_Socket.remote_endpoint (ec);
if (ec)
{
- SendI2PError ("Socket error");
+ SendSessionI2PError ("Socket error");
return;
}
ep.port (port);
@@ -709,7 +736,7 @@
LogPrint (eLogWarning, "SAM: ", SAM_PARAM_CRYPTO_TYPE, "error: ", ex.what ());
}
}
- auto keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType);
+ auto keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType, true);
#ifdef _MSC_VER
size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY,
keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ());
@@ -786,13 +813,13 @@
if (type == eSAMSessionTypeUnknown)
{
// unknown style
- SendI2PError("Unsupported STYLE");
+ SendSessionI2PError("Unsupported STYLE");
return;
}
auto fromPort = std::stoi(params[SAM_PARAM_FROM_PORT]);
if (fromPort == -1)
{
- SendI2PError("Invalid from port");
+ SendSessionI2PError("Invalid from port");
return;
}
auto subsession = std::make_shared<SAMSubSession>(masterSession, id, type, fromPort);
@@ -805,7 +832,7 @@
SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_ID, strlen(SAM_SESSION_CREATE_DUPLICATED_ID), false);
}
else
- SendI2PError ("Wrong session type");
+ SendSessionI2PError ("Wrong session type");
}
void SAMSocket::ProcessSessionRemove (char * buf, size_t len)
@@ -827,12 +854,12 @@
SendSessionCreateReplyOk ();
}
else
- SendI2PError ("Wrong session type");
+ SendSessionI2PError ("Wrong session type");
}
- void SAMSocket::SendI2PError(const std::string & msg)
+ void SAMSocket::SendSessionI2PError(const std::string & msg)
{
- LogPrint (eLogError, "SAM: I2P error: ", msg);
+ LogPrint (eLogError, "SAM: Session I2P error: ", msg);
#ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_STATUS_I2P_ERROR, msg.c_str());
#else
@@ -841,6 +868,17 @@
SendMessageReply (m_Buffer, len, true);
}
+ void SAMSocket::SendStreamI2PError(const std::string & msg)
+ {
+ LogPrint (eLogError, "SAM: Stream I2P error: ", msg);
+#ifdef _MSC_VER
+ size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_STREAM_STATUS_I2P_ERROR, msg.c_str());
+#else
+ size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_STREAM_STATUS_I2P_ERROR, msg.c_str());
+#endif
+ SendMessageReply (m_Buffer, len, true);
+ }
+
void SAMSocket::HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::string name)
{
if (leaseSet)
@@ -1035,16 +1073,27 @@
m_Stream = stream;
context.GetAddressBook ().InsertFullAddress (stream->GetRemoteIdentity ());
auto session = m_Owner.FindSession (m_ID);
- if (session)
+ if (session && !session->acceptQueue.empty ())
{
- // find more pending acceptors
- for (auto & it: m_Owner.ListSockets (m_ID))
- if (it->m_SocketType == eSAMSocketTypeAcceptor)
+ // pending acceptors
+ auto ts = i2p::util::GetSecondsSinceEpoch ();
+ while (!session->acceptQueue.empty () && session->acceptQueue.front ().second + SAM_SESSION_MAX_ACCEPT_INTERVAL > ts)
+ {
+ auto socket = session->acceptQueue.front ().first;
+ session->acceptQueue.pop_front ();
+ if (socket)
+ m_Owner.GetService ().post (std::bind(&SAMSocket::TerminateClose, socket));
+ }
+ if (!session->acceptQueue.empty ())
+ {
+ auto socket = session->acceptQueue.front ().first;
+ session->acceptQueue.pop_front ();
+ if (socket && socket->GetSocketType () == eSAMSocketTypeAcceptor)
{
- it->m_IsAccepting = true;
- session->GetLocalDestination ()->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, it, std::placeholders::_1));
- break;
+ socket->m_IsAccepting = true;
+ session->GetLocalDestination ()->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, socket, std::placeholders::_1));
}
+ }
}
if (!m_IsSilent)
{
@@ -1212,7 +1261,7 @@
subsessions.clear ();
}
- SAMSubSession::SAMSubSession (std::shared_ptr<SAMMasterSession> master, const std::string& name, SAMSessionType type, int port):
+ SAMSubSession::SAMSubSession (std::shared_ptr<SAMMasterSession> master, const std::string& name, SAMSessionType type, uint16_t port):
SAMSession (master->m_Bridge, name, type), masterSession (master), inPort (port)
{
if (Type == eSAMSessionTypeStream)
@@ -1239,10 +1288,10 @@
// TODO: implement datagrams
}
- SAMBridge::SAMBridge (const std::string& address, int port, bool singleThread):
+ SAMBridge::SAMBridge (const std::string& address, uint16_t portTCP, uint16_t portUDP, bool singleThread):
RunnableService ("SAM"), m_IsSingleThread (singleThread),
- m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)),
- m_DatagramEndpoint (boost::asio::ip::address::from_string(address), port-1), m_DatagramSocket (GetIOService (), m_DatagramEndpoint),
+ m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), portTCP)),
+ m_DatagramEndpoint (boost::asio::ip::address::from_string(address), (!portUDP) ? portTCP-1 : portUDP), m_DatagramSocket (GetIOService (), m_DatagramEndpoint),
m_SignatureTypes
{
{"DSA_SHA1", i2p::data::SIGNING_KEY_TYPE_DSA_SHA1},
@@ -1481,7 +1530,7 @@
auto localDest = session->GetLocalDestination ();
auto datagramDest = localDest ? localDest->GetDatagramDestination () : nullptr;
if (datagramDest)
- {
+ {
i2p::data::IdentityEx dest;
dest.FromBase64 (destination);
if (session->Type == eSAMSessionTypeDatagram)
@@ -1490,7 +1539,7 @@
datagramDest->SendRawDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ());
else
LogPrint (eLogError, "SAM: Unexpected session type ", (int)session->Type, "for session ", sessionID);
- }
+ }
else
LogPrint (eLogError, "SAM: Datagram destination is not set for session ", sessionID);
}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/SAM.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2021, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -30,7 +30,10 @@
{
const size_t SAM_SOCKET_BUFFER_SIZE = 8192;
const int SAM_SOCKET_CONNECTION_MAX_IDLE = 3600; // in seconds
- const int SAM_SESSION_READINESS_CHECK_INTERVAL = 20; // in seconds
+ const int SAM_SESSION_READINESS_CHECK_INTERVAL = 3; // in seconds
+ const size_t SAM_SESSION_MAX_ACCEPT_QUEUE_SIZE = 50;
+ const size_t SAM_SESSION_MAX_ACCEPT_INTERVAL = 3; // in seconds
+
const char SAM_HANDSHAKE[] = "HELLO VERSION";
const char SAM_HANDSHAKE_REPLY[] = "HELLO REPLY RESULT=OK VERSION=%s\n";
const char SAM_HANDSHAKE_NOVERSION[] = "HELLO REPLY RESULT=NOVERSION\n";
@@ -49,7 +52,7 @@
const char SAM_STREAM_STATUS_INVALID_ID[] = "STREAM STATUS RESULT=INVALID_ID\n";
const char SAM_STREAM_STATUS_INVALID_KEY[] = "STREAM STATUS RESULT=INVALID_KEY\n";
const char SAM_STREAM_STATUS_CANT_REACH_PEER[] = "STREAM STATUS RESULT=CANT_REACH_PEER\n";
- const char SAM_STREAM_STATUS_I2P_ERROR[] = "STREAM STATUS RESULT=I2P_ERROR\n";
+ const char SAM_STREAM_STATUS_I2P_ERROR[] = "STREAM STATUS RESULT=I2P_ERROR MESSAGE=\"%s\"\n";
const char SAM_STREAM_ACCEPT[] = "STREAM ACCEPT";
const char SAM_STREAM_FORWARD[] = "STREAM FORWARD";
const char SAM_DATAGRAM_SEND[] = "DATAGRAM SEND";
@@ -141,7 +144,8 @@
void ProcessNamingLookup (char * buf, size_t len);
void ProcessSessionAdd (char * buf, size_t len);
void ProcessSessionRemove (char * buf, size_t len);
- void SendI2PError(const std::string & msg);
+ void SendSessionI2PError(const std::string & msg);
+ void SendStreamI2PError(const std::string & msg);
size_t ProcessDatagramSend (char * buf, size_t len, const char * data); // from SAM 1.0
void ExtractParams (char * buf, std::map<std::string, std::string>& params);
@@ -188,7 +192,8 @@
std::string Name;
SAMSessionType Type;
std::shared_ptr<boost::asio::ip::udp::endpoint> UDPEndpoint; // TODO: move
-
+ std::list<std::pair<std::shared_ptr<SAMSocket>, uint64_t> > acceptQueue; // socket, receive time in seconds
+
SAMSession (SAMBridge & parent, const std::string & name, SAMSessionType type);
virtual ~SAMSession () {};
@@ -221,9 +226,9 @@
struct SAMSubSession: public SAMSession
{
std::shared_ptr<SAMMasterSession> masterSession;
- int inPort;
+ uint16_t inPort;
- SAMSubSession (std::shared_ptr<SAMMasterSession> master, const std::string& name, SAMSessionType type, int port);
+ SAMSubSession (std::shared_ptr<SAMMasterSession> master, const std::string& name, SAMSessionType type, uint16_t port);
// implements SAMSession
std::shared_ptr<ClientDestination> GetLocalDestination ();
void StopLocalDestination ();
@@ -233,7 +238,7 @@
{
public:
- SAMBridge (const std::string& address, int port, bool singleThread);
+ SAMBridge (const std::string& address, uint16_t portTCP, uint16_t portUDP, bool singleThread);
~SAMBridge ();
void Start ();
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/SOCKS.cpp
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -27,7 +27,7 @@
static const size_t socks_buffer_size = 8192;
static const size_t max_socks_hostname_size = 255; // Limit for socks5 and bad idea to traverse
- static const size_t SOCKS_FORWARDER_BUFFER_SIZE = 8192;
+ //static const size_t SOCKS_FORWARDER_BUFFER_SIZE = 8192;
static const size_t SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE = 8;
@@ -66,6 +66,11 @@
GET5_IPV6,
GET5_HOST_SIZE,
GET5_HOST,
+ GET5_USERPASSWD,
+ GET5_USER_SIZE,
+ GET5_USER,
+ GET5_PASSWD_SIZE,
+ GET5_PASSWD,
READY,
UPSTREAM_RESOLVE,
UPSTREAM_CONNECT,
@@ -129,6 +134,7 @@
boost::asio::const_buffers_1 GenerateSOCKS5Response(errTypes error, addrTypes type, const address &addr, uint16_t port);
boost::asio::const_buffers_1 GenerateUpstreamRequest();
bool Socks5ChooseAuth();
+ void Socks5UserPasswdResponse ();
void SocksRequestFailed(errTypes error);
void SocksRequestSuccess();
void SentSocksFailed(const boost::system::error_code & ecode);
@@ -324,6 +330,15 @@
}
}
+ void SOCKSHandler::Socks5UserPasswdResponse ()
+ {
+ m_response[0] = 1; // Version of the subnegotiation
+ m_response[1] = 0; // Response code
+ LogPrint(eLogDebug, "SOCKS: v5 user/password response");
+ boost::asio::async_write(*m_sock, boost::asio::const_buffers_1(m_response, 2),
+ std::bind(&SOCKSHandler::SentSocksResponse, shared_from_this(), std::placeholders::_1));
+ }
+
/* All hope is lost beyond this point */
void SOCKSHandler::SocksRequestFailed(SOCKSHandler::errTypes error)
{
@@ -438,10 +453,15 @@
m_parseleft --;
if (*sock_buff == AUTH_NONE)
m_authchosen = AUTH_NONE;
+ else if (*sock_buff == AUTH_USERPASSWD)
+ m_authchosen = AUTH_USERPASSWD;
if ( m_parseleft == 0 )
{
if (!Socks5ChooseAuth()) return false;
- EnterState(GET5_REQUESTV);
+ if (m_authchosen == AUTH_USERPASSWD)
+ EnterState(GET5_USERPASSWD);
+ else
+ EnterState(GET5_REQUESTV);
}
break;
case GET_COMMAND:
@@ -557,6 +577,44 @@
m_parseleft--;
if (m_parseleft == 0) EnterState(GET_PORT);
break;
+ case GET5_USERPASSWD:
+ if (*sock_buff != 1)
+ {
+ LogPrint(eLogError,"SOCKS: v5 rejected invalid username/password subnegotiation: ", ((int)*sock_buff));
+ SocksRequestFailed(SOCKS5_GEN_FAIL);
+ return false;
+ }
+ EnterState(GET5_USER_SIZE);
+ break;
+ case GET5_USER_SIZE:
+ if (*sock_buff)
+ EnterState(GET5_USER, *sock_buff);
+ else // empty user
+ EnterState(GET5_PASSWD_SIZE);
+ break;
+ case GET5_USER:
+ // skip user for now
+ m_parseleft--;
+ if (m_parseleft == 0) EnterState(GET5_PASSWD_SIZE);
+ break;
+ case GET5_PASSWD_SIZE:
+ if (*sock_buff)
+ EnterState(GET5_PASSWD, *sock_buff);
+ else // empty password
+ {
+ Socks5UserPasswdResponse ();
+ EnterState(GET5_REQUESTV);
+ }
+ break;
+ case GET5_PASSWD:
+ // skip passwd for now
+ m_parseleft--;
+ if (m_parseleft == 0)
+ {
+ Socks5UserPasswdResponse ();
+ EnterState(GET5_REQUESTV);
+ }
+ break;
default:
LogPrint(eLogError, "SOCKS: Parse state?? ", m_state);
Terminate();
@@ -788,7 +846,7 @@
shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}
- SOCKSServer::SOCKSServer(const std::string& name, const std::string& address, int port,
+ SOCKSServer::SOCKSServer(const std::string& name, const std::string& address, uint16_t port,
bool outEnable, const std::string& outAddress, uint16_t outPort,
std::shared_ptr<i2p::client::ClientDestination> localDestination) :
TCPIPAcceptor (address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()), m_Name (name)
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/SOCKS.h
^
|
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013-2020, The PurpleI2P Project
+* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -23,7 +23,7 @@
{
public:
- SOCKSServer(const std::string& name, const std::string& address, int port, bool outEnable, const std::string& outAddress, uint16_t outPort,
+ SOCKSServer(const std::string& name, const std::string& address, uint16_t port, bool outEnable, const std::string& outAddress, uint16_t outPort,
std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
~SOCKSServer() {};
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/UDPTunnel.cpp
^
|
@@ -0,0 +1,377 @@
+/*
+* Copyright (c) 2013-2022, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*/
+
+#include "Log.h"
+#include "util.h"
+#include "ClientContext.h"
+#include "I2PTunnel.h" // for GetLoopbackAddressFor
+#include "UDPTunnel.h"
+
+namespace i2p
+{
+namespace client
+{
+ void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
+ {
+ if (!m_LastSession || m_LastSession->Identity.GetLL()[0] != from.GetIdentHash ().GetLL()[0] || fromPort != m_LastSession->RemotePort)
+ {
+ std::lock_guard<std::mutex> lock(m_SessionsMutex);
+ m_LastSession = ObtainUDPSession(from, toPort, fromPort);
+ }
+ m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint);
+ m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch();
+ }
+
+ void I2PUDPServerTunnel::HandleRecvFromI2PRaw (uint16_t, uint16_t, const uint8_t * buf, size_t len)
+ {
+ if (m_LastSession)
+ {
+ m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint);
+ m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch();
+ }
+ }
+
+ void I2PUDPServerTunnel::ExpireStale(const uint64_t delta)
+ {
+ std::lock_guard<std::mutex> lock(m_SessionsMutex);
+ uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
+ auto itr = m_Sessions.begin();
+ while(itr != m_Sessions.end()) {
+ if(now - (*itr)->LastActivity >= delta )
+ itr = m_Sessions.erase(itr);
+ else
+ ++itr;
+ }
+ }
+
+ void I2PUDPClientTunnel::ExpireStale(const uint64_t delta)
+ {
+ std::lock_guard<std::mutex> lock(m_SessionsMutex);
+ uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
+ std::vector<uint16_t> removePorts;
+ for (const auto & s : m_Sessions) {
+ if (now - s.second->second >= delta)
+ removePorts.push_back(s.first);
+ }
+ for(auto port : removePorts) {
+ m_Sessions.erase(port);
+ }
+ }
+
+ UDPSessionPtr I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort)
+ {
+ auto ih = from.GetIdentHash();
+ for (auto & s : m_Sessions )
+ {
+ if (s->Identity.GetLL()[0] == ih.GetLL()[0] && remotePort == s->RemotePort)
+ {
+ /** found existing session */
+ LogPrint(eLogDebug, "UDPServer: Found session ", s->IPSocket.local_endpoint(), " ", ih.ToBase32());
+ return s;
+ }
+ }
+ boost::asio::ip::address addr;
+ /** create new udp session */
+ if(m_IsUniqueLocal && m_LocalAddress.is_loopback())
+ {
+ auto ident = from.GetIdentHash();
+ addr = GetLoopbackAddressFor(ident);
+ }
+ else
+ addr = m_LocalAddress;
+ boost::asio::ip::udp::endpoint ep(addr, 0);
+ m_Sessions.push_back(std::make_shared<UDPSession>(ep, m_LocalDest, m_RemoteEndpoint, ih, localPort, remotePort));
+ auto & back = m_Sessions.back();
+ return back;
+ }
+
+ UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint,
+ const std::shared_ptr<i2p::client::ClientDestination> & localDestination,
+ const boost::asio::ip::udp::endpoint& endpoint, const i2p::data::IdentHash& to,
+ uint16_t ourPort, uint16_t theirPort) :
+ m_Destination(localDestination->GetDatagramDestination()),
+ IPSocket(localDestination->GetService(), localEndpoint),
+ Identity (to), SendEndpoint(endpoint),
+ LastActivity(i2p::util::GetMillisecondsSinceEpoch()),
+ LocalPort(ourPort),
+ RemotePort(theirPort)
+ {
+ IPSocket.set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU ));
+ Receive();
+ }
+
+ void UDPSession::Receive()
+ {
+ LogPrint(eLogDebug, "UDPSession: Receive");
+ IPSocket.async_receive_from(boost::asio::buffer(m_Buffer, I2P_UDP_MAX_MTU),
+ FromEndpoint, std::bind(&UDPSession::HandleReceived, this, std::placeholders::_1, std::placeholders::_2));
+ }
+
+ void UDPSession::HandleReceived(const boost::system::error_code & ecode, std::size_t len)
+ {
+ if(!ecode)
+ {
+ LogPrint(eLogDebug, "UDPSession: Forward ", len, "B from ", FromEndpoint);
+ auto ts = i2p::util::GetMillisecondsSinceEpoch();
+ auto session = m_Destination->GetSession (Identity);
+ if (ts > LastActivity + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL)
+ m_Destination->SendDatagram(session, m_Buffer, len, LocalPort, RemotePort);
+ else
+ m_Destination->SendRawDatagram(session, m_Buffer, len, LocalPort, RemotePort);
+ size_t numPackets = 0;
+ while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE)
+ {
+ boost::system::error_code ec;
+ size_t moreBytes = IPSocket.available(ec);
+ if (ec || !moreBytes) break;
+ len = IPSocket.receive_from (boost::asio::buffer (m_Buffer, I2P_UDP_MAX_MTU), FromEndpoint, 0, ec);
+ m_Destination->SendRawDatagram (session, m_Buffer, len, LocalPort, RemotePort);
+ numPackets++;
+ }
+ if (numPackets > 0)
+ LogPrint(eLogDebug, "UDPSession: Forward more ", numPackets, "packets B from ", FromEndpoint);
+ m_Destination->FlushSendQueue (session);
+ LastActivity = ts;
+ Receive();
+ }
+ else
+ LogPrint(eLogError, "UDPSession: ", ecode.message());
+ }
+
+ I2PUDPServerTunnel::I2PUDPServerTunnel (const std::string & name, std::shared_ptr<i2p::client::ClientDestination> localDestination,
+ const boost::asio::ip::address& localAddress, const boost::asio::ip::udp::endpoint& forwardTo, uint16_t port, bool gzip) :
+ m_IsUniqueLocal (true), m_Name (name), m_LocalAddress (localAddress),
+ m_RemoteEndpoint (forwardTo), m_LocalDest (localDestination), m_Gzip (gzip)
+ {
+ }
+
+ I2PUDPServerTunnel::~I2PUDPServerTunnel ()
+ {
+ Stop ();
+ }
+
+ void I2PUDPServerTunnel::Start ()
+ {
+ m_LocalDest->Start ();
+
+ auto dgram = m_LocalDest->CreateDatagramDestination (m_Gzip);
+ dgram->SetReceiver (std::bind (&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
+ dgram->SetRawReceiver (std::bind (&I2PUDPServerTunnel::HandleRecvFromI2PRaw, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
+ }
+
+ void I2PUDPServerTunnel::Stop ()
+ {
+ auto dgram = m_LocalDest->GetDatagramDestination ();
+ if (dgram) dgram->ResetReceiver ();
+ }
+
+ std::vector<std::shared_ptr<DatagramSessionInfo> > I2PUDPServerTunnel::GetSessions ()
+ {
+ std::vector<std::shared_ptr<DatagramSessionInfo> > sessions;
+ std::lock_guard<std::mutex> lock (m_SessionsMutex);
+
+ for (UDPSessionPtr s: m_Sessions)
+ {
+ if (!s->m_Destination) continue;
+ auto info = s->m_Destination->GetInfoForRemote (s->Identity);
+ if (!info) continue;
+
+ auto sinfo = std::make_shared<DatagramSessionInfo> ();
+ sinfo->Name = m_Name;
+ sinfo->LocalIdent = std::make_shared<i2p::data::IdentHash> (m_LocalDest->GetIdentHash ().data ());
+ sinfo->RemoteIdent = std::make_shared<i2p::data::IdentHash> (s->Identity.data ());
+ sinfo->CurrentIBGW = info->IBGW;
+ sinfo->CurrentOBEP = info->OBEP;
+ sessions.push_back (sinfo);
+ }
+ return sessions;
+ }
+
+ I2PUDPClientTunnel::I2PUDPClientTunnel (const std::string & name, const std::string &remoteDest,
+ const boost::asio::ip::udp::endpoint& localEndpoint,
+ std::shared_ptr<i2p::client::ClientDestination> localDestination,
+ uint16_t remotePort, bool gzip) :
+ m_Name (name), m_RemoteDest (remoteDest), m_LocalDest (localDestination), m_LocalEndpoint (localEndpoint),
+ m_ResolveThread (nullptr), m_LocalSocket (nullptr), RemotePort (remotePort),
+ m_LastPort (0), m_cancel_resolve (false), m_Gzip (gzip)
+ {
+ }
+
+ I2PUDPClientTunnel::~I2PUDPClientTunnel ()
+ {
+ Stop ();
+ }
+
+ void I2PUDPClientTunnel::Start ()
+ {
+ // Reset flag in case of tunnel reload
+ if (m_cancel_resolve) m_cancel_resolve = false;
+
+ m_LocalSocket.reset (new boost::asio::ip::udp::socket (m_LocalDest->GetService (), m_LocalEndpoint));
+ m_LocalSocket->set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU));
+ m_LocalSocket->set_option (boost::asio::socket_base::reuse_address (true));
+
+ auto dgram = m_LocalDest->CreateDatagramDestination (m_Gzip);
+ dgram->SetReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2P, this,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, std::placeholders::_4,
+ std::placeholders::_5));
+ dgram->SetRawReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2PRaw, this,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
+
+ m_LocalDest->Start ();
+ if (m_ResolveThread == nullptr)
+ m_ResolveThread = new std::thread (std::bind (&I2PUDPClientTunnel::TryResolving, this));
+ RecvFromLocal ();
+ }
+
+ void I2PUDPClientTunnel::Stop ()
+ {
+ auto dgram = m_LocalDest->GetDatagramDestination ();
+ if (dgram) dgram->ResetReceiver ();
+ m_cancel_resolve = true;
+
+ m_Sessions.clear();
+
+ if(m_LocalSocket && m_LocalSocket->is_open ())
+ m_LocalSocket->close ();
+
+ if(m_ResolveThread)
+ {
+ m_ResolveThread->join ();
+ delete m_ResolveThread;
+ m_ResolveThread = nullptr;
+ }
+ m_RemoteAddr = nullptr;
+ }
+
+ void I2PUDPClientTunnel::RecvFromLocal ()
+ {
+ m_LocalSocket->async_receive_from (boost::asio::buffer (m_RecvBuff, I2P_UDP_MAX_MTU),
+ m_RecvEndpoint, std::bind (&I2PUDPClientTunnel::HandleRecvFromLocal, this, std::placeholders::_1, std::placeholders::_2));
+ }
+
+ void I2PUDPClientTunnel::HandleRecvFromLocal (const boost::system::error_code & ec, std::size_t transferred)
+ {
+ if (m_cancel_resolve) {
+ LogPrint (eLogDebug, "UDP Client: Ignoring incoming data: stopping");
+ return;
+ }
+ if (ec) {
+ LogPrint (eLogError, "UDP Client: Reading from socket error: ", ec.message (), ". Restarting listener...");
+ RecvFromLocal (); // Restart listener and continue work
+ return;
+ }
+ if (!m_RemoteAddr || !m_RemoteAddr->IsIdentHash ()) // TODO: handle B33
+ {
+ LogPrint (eLogWarning, "UDP Client: Remote endpoint not resolved yet");
+ RecvFromLocal ();
+ return; // drop, remote not resolved
+ }
+ auto remotePort = m_RecvEndpoint.port ();
+ if (!m_LastPort || m_LastPort != remotePort)
+ {
+ auto itr = m_Sessions.find (remotePort);
+ if (itr != m_Sessions.end ())
+ m_LastSession = itr->second;
+ else
+ {
+ m_LastSession = std::make_shared<UDPConvo> (boost::asio::ip::udp::endpoint (m_RecvEndpoint), 0);
+ m_Sessions.emplace (remotePort, m_LastSession);
+ }
+ m_LastPort = remotePort;
+ }
+ // send off to remote i2p destination
+ auto ts = i2p::util::GetMillisecondsSinceEpoch ();
+ LogPrint (eLogDebug, "UDP Client: Send ", transferred, " to ", m_RemoteAddr->identHash.ToBase32 (), ":", RemotePort);
+ auto session = m_LocalDest->GetDatagramDestination ()->GetSession (m_RemoteAddr->identHash);
+ if (ts > m_LastSession->second + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL)
+ m_LocalDest->GetDatagramDestination ()->SendDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
+ else
+ m_LocalDest->GetDatagramDestination ()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
+ size_t numPackets = 0;
+ while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE)
+ {
+ boost::system::error_code ec;
+ size_t moreBytes = m_LocalSocket->available (ec);
+ if (ec || !moreBytes) break;
+ transferred = m_LocalSocket->receive_from (boost::asio::buffer (m_RecvBuff, I2P_UDP_MAX_MTU), m_RecvEndpoint, 0, ec);
+ remotePort = m_RecvEndpoint.port ();
+ // TODO: check remotePort
+ m_LocalDest->GetDatagramDestination ()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
+ numPackets++;
+ }
+ if (numPackets)
+ LogPrint (eLogDebug, "UDP Client: Sent ", numPackets, " more packets to ", m_RemoteAddr->identHash.ToBase32 ());
+ m_LocalDest->GetDatagramDestination ()->FlushSendQueue (session);
+
+ // mark convo as active
+ if (m_LastSession)
+ m_LastSession->second = ts;
+ RecvFromLocal ();
+ }
+
+ std::vector<std::shared_ptr<DatagramSessionInfo> > I2PUDPClientTunnel::GetSessions ()
+ {
+ // TODO: implement
+ std::vector<std::shared_ptr<DatagramSessionInfo> > infos;
+ return infos;
+ }
+
+ void I2PUDPClientTunnel::TryResolving ()
+ {
+ i2p::util::SetThreadName ("UDP Resolver");
+ LogPrint (eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest);
+
+ while (!(m_RemoteAddr = context.GetAddressBook().GetAddress(m_RemoteDest)) && !m_cancel_resolve)
+ {
+ LogPrint (eLogWarning, "UDP Tunnel: Failed to lookup ", m_RemoteDest);
+ std::this_thread::sleep_for (std::chrono::seconds (1));
+ }
+ if (m_cancel_resolve)
+ {
+ LogPrint(eLogError, "UDP Tunnel: Lookup of ", m_RemoteDest, " was cancelled");
+ return;
+ }
+ if (!m_RemoteAddr)
+ {
+ LogPrint (eLogError, "UDP Tunnel: ", m_RemoteDest, " not found");
+ return;
+ }
+ LogPrint(eLogInfo, "UDP Tunnel: Resolved ", m_RemoteDest, " to ", m_RemoteAddr->identHash.ToBase32 ());
+ }
+
+ void I2PUDPClientTunnel::HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
+ {
+ if (m_RemoteAddr && from.GetIdentHash() == m_RemoteAddr->identHash)
+ HandleRecvFromI2PRaw (fromPort, toPort, buf, len);
+ else
+ LogPrint(eLogWarning, "UDP Client: Unwarranted traffic from ", from.GetIdentHash().ToBase32 ());
+ }
+
+ void I2PUDPClientTunnel::HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
+ {
+ auto itr = m_Sessions.find (toPort);
+ // found convo ?
+ if (itr != m_Sessions.end ())
+ {
+ // found convo
+ if (len > 0)
+ {
+ LogPrint (eLogDebug, "UDP Client: Got ", len, "B from ", m_RemoteAddr ? m_RemoteAddr->identHash.ToBase32 () : "");
+ m_LocalSocket->send_to (boost::asio::buffer (buf, len), itr->second->first);
+ // mark convo as active
+ itr->second->second = i2p::util::GetMillisecondsSinceEpoch ();
+ }
+ }
+ else
+ LogPrint (eLogWarning, "UDP Client: Not tracking udp session using port ", (int) toPort);
+ }
+
+}
+}
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/libi2pd_client/UDPTunnel.h
^
|
@@ -0,0 +1,187 @@
+/*
+* Copyright (c) 2013-2022, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*/
+
+#ifndef UDPTUNNEL_H__
+#define UDPTUNNEL_H__
+
+#include <inttypes.h>
+#include <string>
+#include <memory>
+#include <thread>
+#include <vector>
+#include <unordered_map>
+#include <boost/asio.hpp>
+#include "Identity.h"
+#include "Destination.h"
+#include "Datagram.h"
+#include "AddressBook.h"
+
+namespace i2p
+{
+namespace client
+{
+ /** 2 minute timeout for udp sessions */
+ const uint64_t I2P_UDP_SESSION_TIMEOUT = 1000 * 60 * 2;
+ const uint64_t I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL = 100; // in milliseconds
+
+ /** max size for i2p udp */
+ const size_t I2P_UDP_MAX_MTU = 64*1024;
+
+ struct UDPSession
+ {
+ i2p::datagram::DatagramDestination * m_Destination;
+ boost::asio::ip::udp::socket IPSocket;
+ i2p::data::IdentHash Identity;
+ boost::asio::ip::udp::endpoint FromEndpoint;
+ boost::asio::ip::udp::endpoint SendEndpoint;
+ uint64_t LastActivity;
+
+ uint16_t LocalPort;
+ uint16_t RemotePort;
+
+ uint8_t m_Buffer[I2P_UDP_MAX_MTU];
+
+ UDPSession(boost::asio::ip::udp::endpoint localEndpoint,
+ const std::shared_ptr<i2p::client::ClientDestination> & localDestination,
+ const boost::asio::ip::udp::endpoint& remote, const i2p::data::IdentHash& ident,
+ uint16_t ourPort, uint16_t theirPort);
+ void HandleReceived(const boost::system::error_code & ecode, std::size_t len);
+ void Receive();
+ };
+
+
+ /** read only info about a datagram session */
+ struct DatagramSessionInfo
+ {
+ /** the name of this forward */
+ std::string Name;
+ /** ident hash of local destination */
+ std::shared_ptr<const i2p::data::IdentHash> LocalIdent;
+ /** ident hash of remote destination */
+ std::shared_ptr<const i2p::data::IdentHash> RemoteIdent;
+ /** ident hash of IBGW in use currently in this session or nullptr if none is set */
+ std::shared_ptr<const i2p::data::IdentHash> CurrentIBGW;
+ /** ident hash of OBEP in use for this session or nullptr if none is set */
+ std::shared_ptr<const i2p::data::IdentHash> CurrentOBEP;
+ /** i2p router's udp endpoint */
+ boost::asio::ip::udp::endpoint LocalEndpoint;
+ /** client's udp endpoint */
+ boost::asio::ip::udp::endpoint RemoteEndpoint;
+ /** how long has this converstation been idle in ms */
+ uint64_t idle;
+ };
+
+ typedef std::shared_ptr<UDPSession> UDPSessionPtr;
+
+ /** server side udp tunnel, many i2p inbound to 1 ip outbound */
+ class I2PUDPServerTunnel
+ {
+ public:
+
+ I2PUDPServerTunnel (const std::string & name,
+ std::shared_ptr<i2p::client::ClientDestination> localDestination,
+ const boost::asio::ip::address& localAddress,
+ const boost::asio::ip::udp::endpoint& forwardTo, uint16_t port, bool gzip);
+ ~I2PUDPServerTunnel ();
+
+ /** expire stale udp conversations */
+ void ExpireStale (const uint64_t delta=I2P_UDP_SESSION_TIMEOUT);
+ void Start ();
+ void Stop ();
+ const char * GetName () const { return m_Name.c_str(); }
+ std::vector<std::shared_ptr<DatagramSessionInfo> > GetSessions ();
+ std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDest; }
+
+ void SetUniqueLocal (bool isUniqueLocal = true) { m_IsUniqueLocal = isUniqueLocal; }
+
+ private:
+
+ void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
+ void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
+ UDPSessionPtr ObtainUDPSession (const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort);
+
+ private:
+
+ bool m_IsUniqueLocal;
+ const std::string m_Name;
+ boost::asio::ip::address m_LocalAddress;
+ boost::asio::ip::udp::endpoint m_RemoteEndpoint;
+ std::mutex m_SessionsMutex;
+ std::vector<UDPSessionPtr> m_Sessions;
+ std::shared_ptr<i2p::client::ClientDestination> m_LocalDest;
+ UDPSessionPtr m_LastSession;
+ bool m_Gzip;
+
+ public:
+
+ bool isUpdated; // transient, used during reload only
+ };
+
+ class I2PUDPClientTunnel
+ {
+ public:
+
+ I2PUDPClientTunnel (const std::string & name, const std::string &remoteDest,
+ const boost::asio::ip::udp::endpoint& localEndpoint, std::shared_ptr<i2p::client::ClientDestination> localDestination,
+ uint16_t remotePort, bool gzip);
+ ~I2PUDPClientTunnel ();
+
+ void Start ();
+ void Stop ();
+ const char * GetName () const { return m_Name.c_str(); }
+ std::vector<std::shared_ptr<DatagramSessionInfo> > GetSessions ();
+
+ bool IsLocalDestination (const i2p::data::IdentHash & destination) const { return destination == m_LocalDest->GetIdentHash(); }
+
+ std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDest; }
+ inline void SetLocalDestination (std::shared_ptr<ClientDestination> dest)
+ {
+ if (m_LocalDest) m_LocalDest->Release ();
+ if (dest) dest->Acquire ();
+ m_LocalDest = dest;
+ }
+
+ void ExpireStale (const uint64_t delta=I2P_UDP_SESSION_TIMEOUT);
+
+ private:
+
+ typedef std::pair<boost::asio::ip::udp::endpoint, uint64_t> UDPConvo;
+ void RecvFromLocal ();
+ void HandleRecvFromLocal (const boost::system::error_code & e, std::size_t transferred);
+ void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
+ void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
+ void TryResolving ();
+
+ private:
+
+ const std::string m_Name;
+ std::mutex m_SessionsMutex;
+ std::unordered_map<uint16_t, std::shared_ptr<UDPConvo> > m_Sessions; // maps i2p port -> local udp convo
+ const std::string m_RemoteDest;
+ std::shared_ptr<i2p::client::ClientDestination> m_LocalDest;
+ const boost::asio::ip::udp::endpoint m_LocalEndpoint;
+ std::shared_ptr<const Address> m_RemoteAddr;
+ std::thread * m_ResolveThread;
+ std::unique_ptr<boost::asio::ip::udp::socket> m_LocalSocket;
+ boost::asio::ip::udp::endpoint m_RecvEndpoint;
+ uint8_t m_RecvBuff[I2P_UDP_MAX_MTU];
+ uint16_t RemotePort, m_LastPort;
+ bool m_cancel_resolve;
+ bool m_Gzip;
+ std::shared_ptr<UDPConvo> m_LastSession;
+
+ public:
+
+ bool isUpdated; // transient, used during reload only
+ };
+
+
+}
+}
+
+#endif
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/.gitignore
^
|
@@ -0,0 +1,12 @@
+/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-x25519
+/test-aeadchacha20poly1305
+/test-blinding
+/test-elligator
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/CMakeLists.txt
^
|
@@ -0,0 +1,123 @@
+enable_testing()
+find_package(Check 0.9.10 REQUIRED)
+include_directories(${CHECK_INCLUDE_DIRS})
+
+# Compiler flags:
+if(APPLE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -Wl,-undefined,dynamic_lookup")
+else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -Wl,--unresolved-symbols=ignore-in-object-files")
+endif()
+
+set(TEST_PATH ${CMAKE_CURRENT_BINARY_DIR})
+
+include_directories(
+ ../libi2pd
+ ${Boost_INCLUDE_DIRS}
+ ${OPENSSL_INCLUDE_DIR}
+)
+
+set(test-http-merge_chunked_SRCS
+ test-http-merge_chunked.cpp
+)
+
+set(test-http-req_SRCS
+ test-http-req.cpp
+)
+
+set(test-http-res_SRCS
+ test-http-res.cpp
+)
+
+set(test-http-url_decode_SRCS
+ test-http-url_decode.cpp
+)
+
+set(test-http-url_SRCS
+ test-http-url.cpp
+)
+
+set(test-base-64_SRCS
+ test-base-64.cpp
+)
+
+set(test-gost_SRCS
+ test-gost.cpp
+)
+
+set(test-gost-sig_SRCS
+ test-gost-sig.cpp
+)
+
+set(test-x25519_SRCS
+ test-x25519.cpp
+)
+
+set(test-aeadchacha20poly1305_SRCS
+ test-aeadchacha20poly1305.cpp
+)
+
+set(test-blinding_SRCS
+ test-blinding.cpp
+)
+
+SET(test-elligator_SRCS
+ test-elligator.cpp
+)
+
+set(test-eddsa_SRCS
+ test-eddsa.cpp
+)
+
+add_executable(test-http-merge_chunked ${test-http-merge_chunked_SRCS})
+add_executable(test-http-req ${test-http-req_SRCS})
+add_executable(test-http-res ${test-http-res_SRCS})
+add_executable(test-http-url_decode ${test-http-url_decode_SRCS})
+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})
+add_executable(test-eddsa ${test-eddsa_SRCS})
+
+set(LIBS
+ libi2pd
+ ${Boost_LIBRARIES}
+ OpenSSL::SSL
+ OpenSSL::Crypto
+ ZLIB::ZLIB
+ Threads::Threads
+ ${CHECK_LDFLAGS}
+ ${CMAKE_REQUIRED_LIBRARIES}
+)
+
+target_link_libraries(test-http-merge_chunked ${LIBS})
+target_link_libraries(test-http-req ${LIBS})
+target_link_libraries(test-http-res ${LIBS})
+target_link_libraries(test-http-url_decode ${LIBS})
+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})
+target_link_libraries(test-eddsa ${LIBS})
+
+add_test(test-http-merge_chunked ${TEST_PATH}/test-http-merge_chunked)
+add_test(test-http-req ${TEST_PATH}/test-http-req)
+add_test(test-http-res ${TEST_PATH}/test-http-res)
+add_test(test-http-url_decode ${TEST_PATH}/test-http-url_decode)
+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)
+add_test(test-eddsa ${TEST_PATH}/test-eddsa)
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/Makefile
^
|
@@ -1,36 +1,66 @@
-CXXFLAGS += -Wall -Wno-unused-parameter -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -pthread -Wl,--unresolved-symbols=ignore-in-object-files
+SYS := $(shell $(CXX) -dumpmachine)
+
+CXXFLAGS += -Wall -Wno-unused-parameter -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -DOPENSSL_SUPPRESS_DEPRECATED -pthread -Wl,--unresolved-symbols=ignore-in-object-files
INCFLAGS += -I../libi2pd
-TESTS = test-gost test-gost-sig test-base-64 test-x25519 test-aeadchacha20poly1305 test-blinding test-elligator
+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-x25519 test-aeadchacha20poly1305 test-blinding \
+ test-elligator test-eddsa
+
+ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
+ CXXFLAGS += -DWIN32_LEAN_AND_MEAN
+ LDFLAGS += -mwindows -static
+ BOOST_SUFFIX = -mt
+ NEEDED_LDLIBS = -lwsock32 -lws2_32 -lgdi32 -liphlpapi -lole32
+endif
+
+LDLIBS = \
+ -lboost_filesystem$(BOOST_SUFFIX) \
+ -lboost_program_options$(BOOST_SUFFIX) \
+ -lssl \
+ -lcrypto \
+ -lz \
+ $(NEEDED_LDLIBS) \
+ -lpthread
+
all: $(TESTS) run
-test-http-%: ../libi2pd/HTTP.cpp test-http-%.cpp
- $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^
+$(LIBI2PD):
+ @echo "Building libi2pd.a ..." && cd .. && $(MAKE) libi2pd.a
+
+test-http-%: test-http-%.cpp $(LIBI2PD)
+ $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+
+test-base-%: test-base-%.cpp $(LIBI2PD)
+ $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
-test-base-%: ../libi2pd/Base.cpp test-base-%.cpp
- $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^
+test-gost: test-gost.cpp $(LIBI2PD)
+ $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
-test-gost: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp test-gost.cpp
- $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto
+test-gost-sig: test-gost-sig.cpp $(LIBI2PD)
+ $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
-test-gost-sig: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Crypto.cpp ../libi2pd/Log.cpp test-gost-sig.cpp
- $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
+test-x25519: test-x25519.cpp $(LIBI2PD)
+ $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
-test-x25519: ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/Crypto.cpp test-x25519.cpp
- $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
+test-aeadchacha20poly1305: test-aeadchacha20poly1305.cpp $(LIBI2PD)
+ $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
-test-aeadchacha20poly1305: ../libi2pd/Crypto.cpp ../libi2pd/ChaCha20.cpp ../libi2pd/Poly1305.cpp test-aeadchacha20poly1305.cpp
- $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
+test-blinding: test-blinding.cpp $(LIBI2PD)
+ $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
-test-blinding: ../libi2pd/Crypto.cpp ../libi2pd/Blinding.cpp ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/util.cpp ../libi2pd/Identity.cpp ../libi2pd/Signature.cpp ../libi2pd/Timestamp.cpp test-blinding.cpp
- $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
+test-elligator: test-elligator.cpp $(LIBI2PD)
+ $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
-test-elligator: ../libi2pd/Elligator.cpp ../libi2pd/Crypto.cpp test-elligator.cpp
- $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
+test-eddsa: test-eddsa.cpp $(LIBI2PD)
+ $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
run: $(TESTS)
- @for TEST in $(TESTS); do ./$$TEST ; done
+ @for TEST in $(TESTS); do echo Running $$TEST; ./$$TEST ; done
clean:
rm -f $(TESTS)
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/test-aeadchacha20poly1305.cpp
^
|
@@ -7,28 +7,28 @@
char text[] = "Ladies and Gentlemen of the class of '99: If I could offer you "
"only one tip for the future, sunscreen would be it."; // 114 bytes
-uint8_t key[32] =
+uint8_t key[32] =
{
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
};
-uint8_t ad[12] =
+uint8_t ad[12] =
{
0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7
};
-uint8_t nonce[12] =
+uint8_t nonce[12] =
{
0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
};
-uint8_t tag[16] =
+uint8_t tag[16] =
{
0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
};
-uint8_t encrypted[114] =
+uint8_t encrypted[114] =
{
0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
@@ -53,7 +53,7 @@
assert (memcmp (buf1, text, 114) == 0);
// test encryption of multiple buffers
memcpy (buf, text, 114);
- std::vector<std::pair<uint8_t*, std::size_t> > bufs{ std::make_pair (buf, 20), std::make_pair (buf + 20, 10), std::make_pair (buf + 30, 70), std::make_pair (buf + 100, 14) };
+ std::vector<std::pair<uint8_t*, std::size_t> > bufs{ std::make_pair (buf, 20), std::make_pair (buf + 20, 10), std::make_pair (buf + 30, 70), std::make_pair (buf + 100, 14) };
i2p::crypto::AEADChaCha20Poly1305Encrypt (bufs, key, nonce, buf + 114);
i2p::crypto::AEADChaCha20Poly1305 (buf, 114, nullptr, 0, key, nonce, buf1, 114, false);
assert (memcmp (buf1, text, 114) == 0);
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/test-blinding.cpp
^
|
@@ -13,31 +13,29 @@
{
auto keys = PrivateKeys::CreateRandomKeys (sigType);
BlindedPublicKey blindedKey (keys.GetPublic ());
- auto timestamp = GetSecondsSinceEpoch ();
+ auto timestamp = GetSecondsSinceEpoch ();
char date[9];
GetDateString (timestamp, date);
- uint8_t blindedPriv[64], blindedPub[128];
+ uint8_t blindedPriv[32], blindedPub[32];
auto publicKeyLen = blindedKey.BlindPrivateKey (keys.GetSigningPrivateKey (), date, blindedPriv, blindedPub);
- uint8_t blindedPub1[128];
+ uint8_t blindedPub1[32];
blindedKey.GetBlindedKey (date, blindedPub1);
// check if public key produced from private blinded key matches blided public key
assert (!memcmp (blindedPub, blindedPub1, publicKeyLen));
// try to sign and verify
- std::unique_ptr<Signer> blindedSigner (PrivateKeys::CreateSigner (sigType, blindedPriv));
- uint8_t buf[100], signature[128];
+ std::unique_ptr<Signer> blindedSigner (PrivateKeys::CreateSigner (blindedKey.GetBlindedSigType (), blindedPriv));
+ uint8_t buf[100], signature[64];
memset (buf, 1, 100);
- blindedSigner->Sign (buf, 100, signature);
- std::unique_ptr<Verifier> blindedVerifier (IdentityEx::CreateVerifier (sigType));
- blindedVerifier->SetPublicKey (blindedPub1);
- assert (blindedVerifier->Verify (buf, 100, signature));
+ blindedSigner->Sign (buf, 100, signature);
+ std::unique_ptr<Verifier> blindedVerifier (IdentityEx::CreateVerifier (blindedKey.GetBlindedSigType ()));
+ blindedVerifier->SetPublicKey (blindedPub);
+ assert (blindedVerifier->Verify (buf, 100, signature));
}
int main ()
{
- // RedDSA test
+ // EdDSA test
+ BlindTest (SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
+ // RedDSA test
BlindTest (SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519);
- // P256 test
- BlindTest (SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
- // P384 test
- BlindTest (SIGNING_KEY_TYPE_ECDSA_SHA384_P384);
}
|
[-]
[+]
|
Added |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/test-eddsa.cpp
^
|
@@ -0,0 +1,68 @@
+#include <cassert>
+#include <inttypes.h>
+#include <string.h>
+
+#include "Signature.h"
+
+// TEST 1024 from RFC-8032
+
+int main ()
+{
+ uint8_t key[32], pub[32], msg[1024], sig[64];
+ BIGNUM * input = BN_new();
+ BN_hex2bn(&input, "f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5");
+ BN_bn2bin(input, key);
+ BN_hex2bn(&input,
+ "08b8b2b733424243760fe426a4b54908632110a66c2f6591eabd3345e3e4eb98"
+ "fa6e264bf09efe12ee50f8f54e9f77b1e355f6c50544e23fb1433ddf73be84d8"
+ "79de7c0046dc4996d9e773f4bc9efe5738829adb26c81b37c93a1b270b20329d"
+ "658675fc6ea534e0810a4432826bf58c941efb65d57a338bbd2e26640f89ffbc"
+ "1a858efcb8550ee3a5e1998bd177e93a7363c344fe6b199ee5d02e82d522c4fe"
+ "ba15452f80288a821a579116ec6dad2b3b310da903401aa62100ab5d1a36553e"
+ "06203b33890cc9b832f79ef80560ccb9a39ce767967ed628c6ad573cb116dbef"
+ "efd75499da96bd68a8a97b928a8bbc103b6621fcde2beca1231d206be6cd9ec7"
+ "aff6f6c94fcd7204ed3455c68c83f4a41da4af2b74ef5c53f1d8ac70bdcb7ed1"
+ "85ce81bd84359d44254d95629e9855a94a7c1958d1f8ada5d0532ed8a5aa3fb2"
+ "d17ba70eb6248e594e1a2297acbbb39d502f1a8c6eb6f1ce22b3de1a1f40cc24"
+ "554119a831a9aad6079cad88425de6bde1a9187ebb6092cf67bf2b13fd65f270"
+ "88d78b7e883c8759d2c4f5c65adb7553878ad575f9fad878e80a0c9ba63bcbcc"
+ "2732e69485bbc9c90bfbd62481d9089beccf80cfe2df16a2cf65bd92dd597b07"
+ "07e0917af48bbb75fed413d238f5555a7a569d80c3414a8d0859dc65a46128ba"
+ "b27af87a71314f318c782b23ebfe808b82b0ce26401d2e22f04d83d1255dc51a"
+ "ddd3b75a2b1ae0784504df543af8969be3ea7082ff7fc9888c144da2af58429e"
+ "c96031dbcad3dad9af0dcbaaaf268cb8fcffead94f3c7ca495e056a9b47acdb7"
+ "51fb73e666c6c655ade8297297d07ad1ba5e43f1bca32301651339e22904cc8c"
+ "42f58c30c04aafdb038dda0847dd988dcda6f3bfd15c4b4c4525004aa06eeff8"
+ "ca61783aacec57fb3d1f92b0fe2fd1a85f6724517b65e614ad6808d6f6ee34df"
+ "f7310fdc82aebfd904b01e1dc54b2927094b2db68d6f903b68401adebf5a7e08"
+ "d78ff4ef5d63653a65040cf9bfd4aca7984a74d37145986780fc0b16ac451649"
+ "de6188a7dbdf191f64b5fc5e2ab47b57f7f7276cd419c17a3ca8e1b939ae49e4"
+ "88acba6b965610b5480109c8b17b80e1b7b750dfc7598d5d5011fd2dcc5600a3"
+ "2ef5b52a1ecc820e308aa342721aac0943bf6686b64b2579376504ccc493d97e"
+ "6aed3fb0f9cd71a43dd497f01f17c0e2cb3797aa2a2f256656168e6c496afc5f"
+ "b93246f6b1116398a346f1a641f3b041e989f7914f90cc2c7fff357876e506b5"
+ "0d334ba77c225bc307ba537152f3f1610e4eafe595f6d9d90d11faa933a15ef1"
+ "369546868a7f3a45a96768d40fd9d03412c091c6315cf4fde7cb68606937380d"
+ "b2eaaa707b4c4185c32eddcdd306705e4dc1ffc872eeee475a64dfac86aba41c"
+ "0618983f8741c5ef68d3a101e8a3b8cac60c905c15fc910840b94c00a0b9d0"
+ );
+ BN_bn2bin(input, msg);
+ BN_hex2bn(&input,
+ "0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350"
+ "aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03");
+ BN_bn2bin(input, sig);
+ BN_hex2bn(&input,
+ "278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e");
+ BN_bn2bin(input, pub);
+
+ uint8_t s[64];
+ i2p::crypto::EDDSA25519Signer signer (key);
+ signer.Sign (msg, 1023, s);
+#if OPENSSL_EDDSA
+ assert(memcmp (s, sig, 64) == 0);
+#endif
+
+ i2p::crypto::EDDSA25519Verifier verifier;
+ verifier.SetPublicKey (pub);
+ assert(verifier.Verify (msg, 1023, s));
+}
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/test-elligator.cpp
^
|
@@ -4,19 +4,19 @@
#include "Elligator.h"
-const uint8_t key[32] =
+const uint8_t key[32] =
{
0x33, 0x95, 0x19, 0x64, 0x00, 0x3c, 0x94, 0x08, 0x78, 0x06, 0x3c, 0xcf, 0xd0, 0x34, 0x8a, 0xf4,
0x21, 0x50, 0xca, 0x16, 0xd2, 0x64, 0x6f, 0x2c, 0x58, 0x56, 0xe8, 0x33, 0x83, 0x77, 0xd8, 0x80
};
-const uint8_t encoded_key[32] =
+const uint8_t encoded_key[32] =
{
0x28, 0x20, 0xb6, 0xb2, 0x41, 0xe0, 0xf6, 0x8a, 0x6c, 0x4a, 0x7f, 0xee, 0x3d, 0x97, 0x82, 0x28,
0xef, 0x3a, 0xe4, 0x55, 0x33, 0xcd, 0x41, 0x0a, 0xa9, 0x1a, 0x41, 0x53, 0x31, 0xd8, 0x61, 0x2d
};
-const uint8_t encoded_key_high_y[32] =
+const uint8_t encoded_key_high_y[32] =
{
0x3c, 0xfb, 0x87, 0xc4, 0x6c, 0x0b, 0x45, 0x75, 0xca, 0x81, 0x75, 0xe0, 0xed, 0x1c, 0x0a, 0xe9,
0xda, 0xe7, 0x9d, 0xb7, 0x8d, 0xf8, 0x69, 0x97, 0xc4, 0x84, 0x7b, 0x9f, 0x20, 0xb2, 0x77, 0x18
@@ -28,7 +28,7 @@
0x14, 0x50, 0x95, 0x89, 0x28, 0x84, 0x57, 0x99, 0x5a, 0x2b, 0x4c, 0xa3, 0x49, 0x0a, 0xa2, 0x07
};
-const uint8_t key1[32] =
+const uint8_t key1[32] =
{
0x1e, 0x8a, 0xff, 0xfe, 0xd6, 0xbf, 0x53, 0xfe, 0x27, 0x1a, 0xd5, 0x72, 0x47, 0x32, 0x62, 0xde,
0xd8, 0xfa, 0xec, 0x68, 0xe5, 0xe6, 0x7e, 0xf4, 0x5e, 0xbb, 0x82, 0xee, 0xba, 0x52, 0x60, 0x4f
@@ -40,7 +40,7 @@
0xd9, 0x03, 0x65, 0xf2, 0x4a, 0x38, 0xaa, 0x7a, 0xef, 0x1b, 0x97, 0xe2, 0x39, 0x54, 0x10, 0x1b
};
-const uint8_t key2[32] =
+const uint8_t key2[32] =
{
0x79, 0x4f, 0x05, 0xba, 0x3e, 0x3a, 0x72, 0x95, 0x80, 0x22, 0x46, 0x8c, 0x88, 0x98, 0x1e, 0x0b,
0xe5, 0x78, 0x2b, 0xe1, 0xe1, 0x14, 0x5c, 0xe2, 0xc3, 0xc6, 0xfd, 0xe1, 0x6d, 0xed, 0x53, 0x63
@@ -52,7 +52,7 @@
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f
};
-const uint8_t key3[32] =
+const uint8_t key3[32] =
{
0x9c, 0xdb, 0x52, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/test-http-merge_chunked.cpp
^
|
@@ -1,5 +1,5 @@
#include <cassert>
-#include "../HTTP.h"
+#include "HTTP.h"
using namespace i2p::http;
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/test-http-req.cpp
^
|
@@ -1,5 +1,5 @@
#include <cassert>
-#include "../HTTP.h"
+#include "HTTP.h"
using namespace i2p::http;
@@ -22,13 +22,13 @@
assert(req->version == "HTTP/1.0");
assert(req->method == "GET");
assert(req->uri == "/");
- assert(req->headers.size() == 3);
- assert(req->headers.count("Host") == 1);
- assert(req->headers.count("Accept") == 1);
- assert(req->headers.count("User-Agent") == 1);
- assert(req->headers.find("Host")->second == "inr.i2p");
- assert(req->headers.find("Accept")->second == "*/*");
- assert(req->headers.find("User-Agent")->second == "curl/7.26.0");
+ assert(req->GetNumHeaders () == 3);
+ assert(req->GetNumHeaders("Host") == 1);
+ assert(req->GetNumHeaders("Accept") == 1);
+ assert(req->GetNumHeaders("User-Agent") == 1);
+ assert(req->GetHeader("Host") == "inr.i2p");
+ assert(req->GetHeader("Accept") == "*/*");
+ assert(req->GetHeader("User-Agent") == "curl/7.26.0");
delete req;
/* test: parsing request without body */
@@ -41,7 +41,7 @@
assert(req->version == "HTTP/1.0");
assert(req->method == "GET");
assert(req->uri == "/");
- assert(req->headers.size() == 0);
+ assert(req->GetNumHeaders () == 0);
delete req;
/* test: parsing request without body */
@@ -74,13 +74,13 @@
assert((ret = req->parse(buf, len)) == len); /* no host header */
assert(req->method == "GET");
assert(req->uri == "http://inr.i2p");
- assert(req->headers.size() == 3);
- assert(req->headers.count("Host") == 1);
- assert(req->headers.count("Accept") == 1);
- assert(req->headers.count("Accept-Encoding") == 1);
- assert(req->headers["Host"] == "stats.i2p");
- assert(req->headers["Accept"] == "*/*");
- assert(req->headers["Accept-Encoding"] == "");
+ assert(req->GetNumHeaders () == 3);
+ assert(req->GetNumHeaders("Host") == 1);
+ assert(req->GetNumHeaders("Accept") == 1);
+ assert(req->GetNumHeaders("Accept-Encoding") == 1);
+ assert(req->GetHeader("Host") == "stats.i2p");
+ assert(req->GetHeader("Accept") == "*/*");
+ assert(req->GetHeader("Accept-Encoding") == "");
delete req;
return 0;
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/test-http-res.cpp
^
|
@@ -1,5 +1,5 @@
#include <cassert>
-#include "../HTTP.h"
+#include "HTTP.h"
using namespace i2p::http;
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/test-http-url.cpp
^
|
@@ -1,5 +1,5 @@
#include <cassert>
-#include "../HTTP.h"
+#include "HTTP.h"
using namespace i2p::http;
@@ -15,6 +15,7 @@
assert(url->host == "127.0.0.1");
assert(url->port == 7070);
assert(url->path == "/asdasd");
+ assert(url->hasquery == true);
assert(url->query == "12345");
assert(url->to_string() == "https://127.0.0.1:7070/asdasd?12345");
delete url;
@@ -27,6 +28,7 @@
assert(url->host == "site.com");
assert(url->port == 8080);
assert(url->path == "/asdasd");
+ assert(url->hasquery == true);
assert(url->query == "123456");
delete url;
@@ -38,6 +40,7 @@
assert(url->host == "site.com");
assert(url->port == 0);
assert(url->path == "/asdasd");
+ assert(url->hasquery == true);
assert(url->query == "name=value");
delete url;
@@ -49,6 +52,7 @@
assert(url->host == "site.com");
assert(url->port == 0);
assert(url->path == "/asdasd");
+ assert(url->hasquery == true);
assert(url->query == "name=value1&name=value2");
delete url;
@@ -60,6 +64,7 @@
assert(url->host == "site.com");
assert(url->port == 0);
assert(url->path == "/asdasd");
+ assert(url->hasquery == true);
assert(url->query == "name1=value1&name2&name3=value2");
assert(url->parse_query(params));
assert(params.size() == 3);
@@ -79,6 +84,7 @@
assert(url->host == "site.com");
assert(url->port == 800);
assert(url->path == "/asdasd");
+ assert(url->hasquery == true);
assert(url->query == "");
delete url;
@@ -90,6 +96,7 @@
assert(url->host == "site.com");
assert(url->port == 17);
assert(url->path == "");
+ assert(url->hasquery == false);
assert(url->query == "");
delete url;
@@ -101,6 +108,7 @@
assert(url->host == "site.com");
assert(url->port == 0);
assert(url->path == "");
+ assert(url->hasquery == false);
assert(url->query == "");
delete url;
@@ -112,6 +120,7 @@
assert(url->host == "site.com");
assert(url->port == 84);
assert(url->path == "/asdasd/@17");
+ assert(url->hasquery == false);
assert(url->query == "");
assert(url->frag == "frag");
delete url;
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/test-http-url_decode.cpp
^
|
@@ -1,5 +1,5 @@
#include <cassert>
-#include "../HTTP.h"
+#include "HTTP.h"
using namespace i2p::http;
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd-2.50.2+git3.tar.gz/upstream/tests/test-x25519.cpp
^
|
@@ -4,21 +4,21 @@
#include "Ed25519.h"
-const uint8_t k[32] =
+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] =
+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] =
+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,
@@ -36,4 +36,3 @@
assert(memcmp (buf, p, 32) == 0);
#endif
}
-
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd.conf
^
|
@@ -1,23 +1,60 @@
+## Configuration file for a typical i2pd user
+## See https://i2pd.readthedocs.io/en/latest/user-guide/configuration/
+## for more options you can use in this file.
+
+## Lines that begin with "## " try to explain what's going on. Lines
+## that begin with just "#" are disabled commands: you can enable them
+## by removing the "#" symbol.
+
+## Tunnels config file
+## Default: ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf
+# tunconf = /var/lib/i2pd/tunnels.conf
+
+## Tunnels config files path
+## Use that path to store separated tunnels in different config files.
+## Default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d
+# tunnelsdir = /var/lib/i2pd/tunnels.d
+
+## Path to certificates used for verifying .su3, families
+## Default: ~/.i2pd/certificates or /var/lib/i2pd/certificates
+# certsdir = /var/lib/i2pd/certificates
+
+## Where to write pidfile (default: /run/i2pd.pid, not used in Windows)
+# pidfile = /run/i2pd.pid
+
+## Logging configuration section
+## By default logs go to stdout with level 'info' and higher
+## For Windows OS by default logs go to file with level 'warn' and higher
+##
## Logs destination (valid values: stdout, file, syslog)
## * stdout - print log entries to stdout
## * file - log entries to a file
## * syslog - use syslog, see man 3 syslog
log = syslog
# log = file
-## Log messages above this level (debug, info, *warn, error, none)
+## Path to logfile (default: autodetect)
+# logfile = /var/log/i2pd/i2pd.log
+## Log messages above this level (debug, info, *warn, error, critical, none)
+## If you set it to none, logging will be disabled
+# loglevel = warn
loglevel = none
+## Write full CLF-formatted date and time to log (default: write only time)
+# logclftime = true
+
+## Daemon mode. Router will go to background after start. Ignored on Windows
+## (default: true)
+# daemon = true
## Specify a family, router belongs to (default - none)
family = sailfishos
## Network interface to bind to
+## Updates address4/6 options if they are not set
# ifname =
+## You can specify different interfaces for IPv4 and IPv6
# ifname4 =
# ifname6 =
-## External IPv4 or IPv6 address to listen for connections
-# host = 1.2.3.4
-
## Local address to bind transport sockets to
## Overrides host option if:
## For ipv4: if ipv4 = true and nat = false
@@ -25,92 +62,235 @@
# address4 =
# address6 =
+## External IPv4 or IPv6 address to listen for connections
+## By default i2pd sets IP automatically
+## Sets published NTCP2v4/SSUv4 address to 'host' value if nat = true
+## Sets published NTCP2v6/SSUv6 address to 'host' value if ipv4 = false
+# host = 1.2.3.4
+
## Port to listen for connections
## By default i2pd picks random port. You MUST pick a random number too,
## don't just uncomment this
# port = 4567
-## Enable communication through ipv4
+## Enable communication through ipv4 (default: true)
ipv4 = true
-## Enable communication through ipv6
+## Enable communication through ipv6 (default: false)
ipv6 = false
-## Enable SSU transport (default = true)
-# ssu = true
-
## Bandwidth configuration
-## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec, X - unlimited/floodfill
-bandwidth = L
-## Max % of bandwidth limit for transit. 0-100. 100 by default
-share = 20
+## L limit bandwidth to 32 KB/sec, O - to 256 KB/sec, P - to 2048 KB/sec,
+## X - unlimited
+## Default is L (regular node) and X if floodfill mode enabled.
+## If you want to share more bandwidth without floodfill mode, uncomment
+## that line and adjust value to your possibilities. Value can be set to
+## integer in kilobytes, it will apply that limit and flag will be used
+## from next upper limit (example: if you set 4096 flag will be X, but real
+## limit will be 4096 KB/s). Same can be done when floodfill mode is used,
+## but keep in mind that low values may be negatively evaluated by Java
+## router algorithms.
+# bandwidth = L
+## Max % of bandwidth limit for transit. 0-100 (default: 100)
+# share = 100
+share = 25
## Router will not accept transit tunnels, disabling transit traffic completely
-## (default = false)
+## (default: false)
# notransit = true
+## Router will be floodfill (default: false)
+## Note: that mode uses much more network connections and CPU!
+# floodfill = true
+
+[ntcp2]
+## Enable NTCP2 transport (default: true)
+# enabled = true
+## Publish address in RouterInfo (default: true)
+# published = true
+## Port for incoming connections (default is global port option value)
+# port = 4567
+
+[ssu2]
+## Enable SSU2 transport (default: true)
+# enabled = true
+## Publish address in RouterInfo (default: true)
+# published = true
+## Port for incoming connections (default is global port option value)
+# port = 4567
+
[http]
-enabled = true
-address = 127.0.0.1
-port = 7070
+## Web Console settings
+## Enable the Web Console (default: true)
+# enabled = true
+## Address and port service will listen on (default: 127.0.0.1:7070)
+# address = 127.0.0.1
+# port = 7070
+## Path to web console (default: /)
# webroot = /
+## Enable Web Console authentication (default: false)
+## You should not use Web Console via public networks without additional encryption.
+## HTTP authentication is not encryption layer!
+# auth = true
+# user = i2pd
+# pass = changeme
auth = true
user = jolla
pass = ahoisailors!
+## Select webconsole language
+## Currently supported english (default), afrikaans, armenian, chinese, czech, french,
+## german, italian, polish, portuguese, russian, spanish, turkish, turkmen, ukrainian
+## and uzbek languages
# lang = english
[httpproxy]
-enabled = true
-address = 127.0.0.1
-port = 4444
+## Enable the HTTP proxy (default: true)
+# enabled = true
+## Address and port service will listen on (default: 127.0.0.1:4444)
+# address = 127.0.0.1
+# port = 4444
+## Optional keys file for proxy local destination (default: http-proxy-keys.dat)
+# keys = http-proxy-keys.dat
+## Enable address helper for adding .i2p domains with "jump URLs" (default: true)
+## You should disable this feature if your i2pd HTTP Proxy is public,
+## because anyone could spoof the short domain via addresshelper and forward other users to phishing links
+# addresshelper = true
+addresshelper = true
+## Address of a proxy server inside I2P, which is used to visit regular Internet
+# outproxy = http://false.i2p
+## httpproxy section also accepts I2CP parameters, like "inbound.length" etc.
[socksproxy]
-enabled = true
-address = 127.0.0.1
-port = 4447
+## Enable the SOCKS proxy (default: true)
+# enabled = true
+## Address and port service will listen on (default: 127.0.0.1:4447)
+# address = 127.0.0.1
+# port = 4447
+## Optional keys file for proxy local destination (default: socks-proxy-keys.dat)
+# keys = socks-proxy-keys.dat
+## Socks outproxy. Example below is set to use Tor for all connections except i2p
+## Enable using of SOCKS outproxy (works only with SOCKS4, default: false)
+# outproxy.enabled = false
+## Address and port of outproxy
+# outproxy = 127.0.0.1
+# outproxyport = 9050
+## socksproxy section also accepts I2CP parameters, like "inbound.length" etc.
[sam]
+## Enable the SAM bridge (default: true)
+# enabled = false
enabled = false
+## Address and ports service will listen on (default: 127.0.0.1:7656, udp: 7655)
# address = 127.0.0.1
# port = 7656
+# portudp = 7655
[bob]
-enabled = false
+## Enable the BOB command channel (default: false)
+# enabled = false
+## Address and port service will listen on (default: 127.0.0.1:2827)
# address = 127.0.0.1
# port = 2827
[i2cp]
-enabled = false
+## Enable the I2CP protocol (default: false)
+# enabled = false
+## Address and port service will listen on (default: 127.0.0.1:7654)
# address = 127.0.0.1
# port = 7654
[i2pcontrol]
-enabled = false
+## Enable the I2PControl protocol (default: false)
+# enabled = false
+## Address and port service will listen on (default: 127.0.0.1:7650)
# address = 127.0.0.1
# port = 7650
+## Authentication password (default: itoopie)
# password = itoopie
+[precomputation]
+## Enable or disable elgamal precomputation table
+## By default, enabled on i386 hosts
+# elgamal = true
+
[upnp]
+## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID)
+# enabled = false
enabled = false
+## Name i2pd appears in UPnP forwardings list (default: I2Pd)
# name = I2Pd
[meshnets]
-yggdrasil = false
+## Enable connectivity over the Yggdrasil network (default: false)
+# yggdrasil = false
+## You can bind address from your Yggdrasil subnet 300::/64
+## The address must first be added to the network interface
# yggaddress =
[reseed]
+## Options for bootstrapping into I2P network, aka reseeding
+## Enable reseed data verification (default: true)
verify = true
+## URLs to request reseed data from, separated by comma
+## Default: "mainline" I2P Network reseeds
+# urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/
+## Reseed URLs through the Yggdrasil, separated by comma
+# yggurls = http://[324:71e:281a:9ed3::ace]:7070/
+## Path to local reseed data file (.su3) for manual reseeding
+# file = /path/to/i2pseeds.su3
+## or HTTPS URL to reseed from
+# file = https://legit-website.com/i2pseeds.su3
+## Path to local ZIP file or HTTPS URL to reseed from
+# zipfile = /path/to/netDb.zip
+## If you run i2pd behind a proxy server, set proxy server for reseeding here
+## Should be http://address:port or socks://address:port
+# proxy = http://127.0.0.1:8118
+## Minimum number of known routers, below which i2pd triggers reseeding (default: 25)
+# threshold = 25
threshold = 15
+[addressbook]
+## AddressBook subscription URL for initial setup
+## Default: reg.i2p at "mainline" I2P Network
+# defaulturl = http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt
+## Optional subscriptions URLs, separated by comma
+# subscriptions = http://reg.i2p/hosts.txt,http://identiguy.i2p/hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt,http://rus.i2p/hosts.txt
+
[limits]
+## Maximum active transit sessions (default: 5000)
+## This value is doubled if floodfill mode is enabled!
+# transittunnels = 5000
transittunnels = 1250
+## Limit number of open file descriptors (0 - use system limit)
+# openfiles = 0
+## Maximum size of corefile in Kb (0 - use system limit)
+# coresize = 0
[trust]
+## Enable explicit trust options. (default: false)
# enabled = true
-# family = sailfishos
+## Make direct I2P connections only to routers in specified Family.
+# family = MyFamily
+## Make direct I2P connections only to routers specified here. Comma separated list of base64 identities.
# routers =
+## Should we hide our router from other routers? (default: false)
# hidden = true
-[persist]
-profiles = true
-addressbook = true
+[exploratory]
+## Exploratory tunnels settings with default values
+# inbound.length = 2
+# inbound.quantity = 3
+# outbound.length = 2
+# outbound.quantity = 3
+[persist]
+## Save peer profiles on disk (default: true)
+# profiles = true
+## Save full addresses on disk (default: true)
+# addressbook = true
+
+[cpuext]
+## Use CPU AES-NI instructions set when work with cryptography when available (default: true)
+# aesni = true
+## Force usage of CPU instructions set, even if they not found (default: false)
+## DO NOT TOUCH that option if you really don't know what are you doing!
+# force = false
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd.service
^
|
@@ -1,7 +1,7 @@
[Unit]
Description=I2P Router
Documentation=https://i2pd.readthedocs.io/en/latest/
-Documentation=https://github.com/nephros/i2pd/blob/main/README.md
+Documentation=https://github.com/nephros/i2pd/blob/master/README.md
After=network.target
After=local-fs.target
After=home.mount
@@ -17,7 +17,8 @@
ExecStart=/usr/bin/i2pd --datadir /home/.system/var/lib/i2pd --conf=/home/.system/var/lib/i2pd/i2pd.conf --tunconf=/home/.system/var/lib/i2pd/tunnels.conf --tunnelsdir=/home/.system/var/lib/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --daemon --service
ExecReload=/bin/sh -c "kill -HUP $MAINPID"
PIDFile=/run/i2pd/i2pd.pid
-
+### Uncomment, if auto restart needed
+#Restart=on-failure
# we log to stdout:
StandardOutput=journal+console
@@ -32,5 +33,10 @@
#KillSignal=SIGINT
#TimeoutStopSec=10m
+# If you have problems with hanging i2pd, you can try increase this
+LimitNOFILE=8192
+# To enable write of coredump uncomment this
+#LimitCORE=infinity
+
[Install]
WantedBy=multi-user.target
|
[-]
[+]
|
Changed |
_service:tar_git:i2pd.yaml
^
|
@@ -1,6 +1,6 @@
Name: i2pd
Summary: End-to-End encrypted and anonymous Internet daemon
-Version: 2.43.0
+Version: 2.50.2
Release: 1
Group: Applications/Internet
License: BSD-3-Clause
@@ -36,6 +36,7 @@
%if "%{?vendor}" == "chum"
PackageName: I2Pd
Type: console-application
+ DeveloperName: Purple I2P
PackagerName: nephros
Categories:
- Network
@@ -64,8 +65,8 @@
RequiresPostUn:
- systemd
PkgBR:
- - gcc-c++
- cmake
+ - gcc-c++
- boost-devel >= 1.49
- systemd
# for the "family" stuff, need openssl binary
@@ -76,7 +77,9 @@
PkgConfigBR:
- libssl
- zlib
+ - atomic_ops
Configure: cmake
+Builder: none
ConfigOptions:
- -DCMAKE_BUILD_TYPE=Release
# -DWITH_AESNI=%ifarch %ix86
@@ -86,7 +89,6 @@
# -DWITH_UPNP=OFF
# -DWITH_ADDRSANITIZER=ON
# -DWITH_THREADSANITIZER=ON
-Builder: none
NoIconCache: true
SubPackages:
@@ -117,7 +119,7 @@
%if "%{?vendor}" == "chum"
PackageName: I2Pd Settings UI
Type: desktop-application
- PackagerName: nephros
+ DeveloperLogin: nephros
Categories:
- Network
- P2P
|