Compare commits

...

24 commits

Author SHA1 Message Date
Pratik B.
3a8e30320d
Merge 17399da399 into 43939cedf4 2024-10-28 14:07:21 +02:00
orignal
43939cedf4 random tunnel reject when medium congestion
Some checks are pending
Build Debian packages / ${{ matrix.dist }} (bookworm) (push) Waiting to run
Build Debian packages / ${{ matrix.dist }} (bullseye) (push) Waiting to run
Build Debian packages / ${{ matrix.dist }} (buster) (push) Waiting to run
Build on FreeBSD / with UPnP (push) Waiting to run
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (no) (push) Waiting to run
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Waiting to run
Build on Windows / XP (push) Waiting to run
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (no) (push) Waiting to run
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Waiting to run
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (OFF) (push) Waiting to run
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (ON) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (amd64, linux/amd64) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (arm64, linux/arm64) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (armv7, linux/arm/v7) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (i386, linux/386) (push) Waiting to run
Build containers / Pushing merged manifest (push) Blocked by required conditions
2024-10-27 22:19:06 -04:00
orignal
4c66608caf random tunnel reject when medium congestion 2024-10-27 21:58:19 -04:00
orignal
ec4fe9a1e6 set congesion cap G if symmetric NAT and ipv4 in only transport 2024-10-27 18:17:28 -04:00
orignal
79e8ccbb5b don't handle PeerTest 1 with same nonce twice
Some checks are pending
Build Debian packages / ${{ matrix.dist }} (bookworm) (push) Waiting to run
Build Debian packages / ${{ matrix.dist }} (bullseye) (push) Waiting to run
Build Debian packages / ${{ matrix.dist }} (buster) (push) Waiting to run
Build on FreeBSD / with UPnP (push) Waiting to run
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (no) (push) Waiting to run
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Waiting to run
Build on Windows / XP (push) Waiting to run
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (no) (push) Waiting to run
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Waiting to run
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (OFF) (push) Waiting to run
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (ON) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (amd64, linux/amd64) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (arm64, linux/arm64) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (armv7, linux/arm/v7) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (i386, linux/386) (push) Waiting to run
Build containers / Pushing merged manifest (push) Blocked by required conditions
2024-10-27 12:24:22 -04:00
orignal
608056dcd2 don't handle RelayRequest and RelayIntro with same nonce twice 2024-10-27 11:55:10 -04:00
orignal
7461b640e3 reduce CPU usage
Some checks are pending
Build Debian packages / ${{ matrix.dist }} (bookworm) (push) Waiting to run
Build Debian packages / ${{ matrix.dist }} (bullseye) (push) Waiting to run
Build Debian packages / ${{ matrix.dist }} (buster) (push) Waiting to run
Build on FreeBSD / with UPnP (push) Waiting to run
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (no) (push) Waiting to run
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Waiting to run
Build on Windows / XP (push) Waiting to run
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (ON) (push) Waiting to run
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (no) (push) Waiting to run
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Waiting to run
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (OFF) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (amd64, linux/amd64) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (arm64, linux/arm64) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (armv7, linux/arm/v7) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (i386, linux/386) (push) Waiting to run
Build containers / Pushing merged manifest (push) Blocked by required conditions
2024-10-26 19:26:25 -04:00
orignal
743126b2ad better hole punch expiration intervals 2024-10-26 19:05:08 -04:00
orignal
f611136ea7 resend relay reponnse if remote router >= 0.9.64
Some checks are pending
Build Debian packages / ${{ matrix.dist }} (bookworm) (push) Waiting to run
Build Debian packages / ${{ matrix.dist }} (bullseye) (push) Waiting to run
Build Debian packages / ${{ matrix.dist }} (buster) (push) Waiting to run
Build on FreeBSD / with UPnP (push) Waiting to run
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (no) (push) Waiting to run
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Waiting to run
Build on Windows / XP (push) Waiting to run
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (no) (push) Waiting to run
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Waiting to run
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (OFF) (push) Waiting to run
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (ON) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (amd64, linux/amd64) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (arm64, linux/arm64) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (armv7, linux/arm/v7) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (i386, linux/386) (push) Waiting to run
Build containers / Pushing merged manifest (push) Blocked by required conditions
2024-10-26 15:30:48 -04:00
orignal
87ae9c4b74 call main thread as i2pd-daemon
Some checks are pending
Build Debian packages / ${{ matrix.dist }} (bookworm) (push) Waiting to run
Build Debian packages / ${{ matrix.dist }} (bullseye) (push) Waiting to run
Build Debian packages / ${{ matrix.dist }} (buster) (push) Waiting to run
Build on FreeBSD / with UPnP (push) Waiting to run
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (no) (push) Waiting to run
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Waiting to run
Build on Windows / XP (push) Waiting to run
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (no) (push) Waiting to run
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Waiting to run
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (OFF) (push) Waiting to run
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (ON) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (amd64, linux/amd64) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (arm64, linux/arm64) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (armv7, linux/arm/v7) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (i386, linux/386) (push) Waiting to run
Build containers / Pushing merged manifest (push) Blocked by required conditions
2024-10-25 18:40:51 -04:00
orignal
d3630fb2b2 assign name to main thread
Some checks are pending
Build Debian packages / ${{ matrix.dist }} (bookworm) (push) Waiting to run
Build Debian packages / ${{ matrix.dist }} (bullseye) (push) Waiting to run
Build Debian packages / ${{ matrix.dist }} (buster) (push) Waiting to run
Build on FreeBSD / with UPnP (push) Waiting to run
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (no) (push) Waiting to run
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Waiting to run
Build on Windows / ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Waiting to run
Build on Windows / CMake ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Waiting to run
Build on Windows / XP (push) Waiting to run
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (no) (push) Waiting to run
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Waiting to run
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (OFF) (push) Waiting to run
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (ON) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (amd64, linux/amd64) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (arm64, linux/arm64) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (armv7, linux/arm/v7) (push) Waiting to run
Build containers / Building container for ${{ matrix.platform }} (i386, linux/386) (push) Waiting to run
Build containers / Pushing merged manifest (push) Blocked by required conditions
2024-10-25 13:25:33 -04:00
orignal
500afe745f use min hole punch interval for connection attempts 2024-10-24 18:49:11 -04:00
orignal
26901e2945 try recently connected SSU2 address if no other transports found 2024-10-23 20:39:00 -04:00
orignal
64bde69967
Merge pull request #2108 from SystemFailureNet/openssl
Please disable LibreSSL workaround when LibreSSL version >= 4.0.0
2024-10-21 21:38:50 -04:00
orignal
ddf30784ec connected recently mutex 2024-10-21 21:22:16 -04:00
orignal
ea14b00d63 save router's endpoint to profile and try to use it next time without requesting introducers 2024-10-21 20:58:09 -04:00
orignal
a24e0eb2dc don't delete unreachable routers if no transports 2024-10-20 16:12:35 -04:00
orignal
0cb677a2c0 don't send peer test msg 6 if remote endpoint is unknown 2024-10-19 09:18:31 -04:00
orignal
e6cbc842bf request new leaseset if all leases are about to expire 2024-10-19 08:45:25 -04:00
orignal
f087654f25 fixed warnings 2024-10-18 20:02:41 -04:00
orignal
10335b90c5 fixed warnings 2024-10-18 19:57:35 -04:00
orignal
8a234f70e6 send a packet to new remote lease in advance if current is about to expire 2024-10-18 15:59:37 -04:00
SystemFailure
f98a310235 Revert LibreSSL workaround when LibreSSL version >= 4.0.0 2024-10-18 13:17:47 +00:00
imdef
17399da399 Added example docker-compose.yml 2024-09-25 16:55:29 +00:00
19 changed files with 324 additions and 139 deletions

View file

@ -0,0 +1,13 @@
services:
i2pd:
container_name: i2pd2
image: purplei2p/i2pd
#optional
entrypoint: ["./entrypoint.sh", "--loglevel error"]
ports:
- 127.0.0.1:7656:7656
- 127.0.0.1:7070:7070
- 127.0.0.1:4444:4444
volumes:
- /path/to/i2pd/data:/home/i2pd/data # make sure data directory and it's contents are owned by 100:65533
- /path/to/i2pd/i2pd_certificates:/i2pd_certificates # make sure i2pd_certificates is owned by root:root and 755 permissions on the directory

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, The PurpleI2P Project * Copyright (c) 2013-2024, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -25,6 +25,7 @@
#include "RouterContext.h" #include "RouterContext.h"
#include "ClientContext.h" #include "ClientContext.h"
#include "Transports.h" #include "Transports.h"
#include "util.h"
void handle_signal(int sig) void handle_signal(int sig)
{ {
@ -220,6 +221,7 @@ namespace i2p
void DaemonLinux::run () void DaemonLinux::run ()
{ {
i2p::util::SetThreadName ("i2pd-daemon");
while (running) while (running)
{ {
std::this_thread::sleep_for (std::chrono::seconds(1)); std::this_thread::sleep_for (std::chrono::seconds(1));

View file

@ -997,7 +997,7 @@ namespace crypto
} }
else else
{ {
#if defined(LIBRESSL_VERSION_NUMBER) #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x4000000fL
std::vector<uint8_t> m(msgLen + 16); std::vector<uint8_t> m(msgLen + 16);
if (msg == buf) if (msg == buf)
{ {

View file

@ -142,14 +142,14 @@ namespace client
void CancelDestinationRequestWithEncryptedLeaseSet (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, bool notify = true); void CancelDestinationRequestWithEncryptedLeaseSet (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, bool notify = true);
// implements GarlicDestination // implements GarlicDestination
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet (); std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () override;
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const { return m_Pool; } std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const override { return m_Pool; }
// override GarlicDestination // override GarlicDestination
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag) override;
void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag); void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag) override;
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg); void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg) override;
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg); void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg) override;
void SetLeaseSetUpdated (bool post) override; void SetLeaseSetUpdated (bool post) override;
bool IsPublic () const { return m_IsPublic; }; bool IsPublic () const { return m_IsPublic; };
@ -158,8 +158,8 @@ namespace client
protected: protected:
// implements GarlicDestination // implements GarlicDestination
void HandleI2NPMessage (const uint8_t * buf, size_t len); void HandleI2NPMessage (const uint8_t * buf, size_t len) override;
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID); bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) override;
void SetLeaseSet (std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet); void SetLeaseSet (std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet);
int GetLeaseSetType () const { return m_LeaseSetType; }; int GetLeaseSetType () const { return m_LeaseSetType; };

View file

@ -396,8 +396,26 @@ namespace i2p
return false; return false;
} }
uint8_t retCode = 0; uint8_t retCode = 0;
// decide if we should accept tunnel
bool accept = i2p::context.AcceptsTunnels ();
if (accept)
{
auto congestionLevel = i2p::context.GetCongestionLevel (false);
if (congestionLevel >= CONGESTION_LEVEL_MEDIUM)
{
if (congestionLevel < CONGESTION_LEVEL_FULL)
{
// random reject depending on congestion level
int level = i2p::tunnel::tunnels.GetRng ()() % (CONGESTION_LEVEL_FULL - CONGESTION_LEVEL_MEDIUM) + CONGESTION_LEVEL_MEDIUM;
if (congestionLevel > level)
accept = false;
}
else
accept = false;
}
}
// replace record to reply // replace record to reply
if (i2p::context.AcceptsTunnels () && i2p::context.GetCongestionLevel (false) < CONGESTION_LEVEL_FULL) if (accept)
{ {
auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),

View file

@ -638,6 +638,7 @@ namespace data
if (checkForExpiration && uptime > i2p::transport::SSU2_TO_INTRODUCER_SESSION_DURATION) // 1 hour if (checkForExpiration && uptime > i2p::transport::SSU2_TO_INTRODUCER_SESSION_DURATION) // 1 hour
expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL : expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL :
NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total; NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total;
bool isOffline = checkForExpiration && i2p::transport::transports.GetNumPeers () < NETDB_MIN_TRANSPORTS; // enough routers and uptime, but no tranports
std::list<std::pair<std::string, std::shared_ptr<RouterInfo::Buffer> > > saveToDisk; std::list<std::pair<std::string, std::shared_ptr<RouterInfo::Buffer> > > saveToDisk;
std::list<std::string> removeFromDisk; std::list<std::string> removeFromDisk;
@ -672,7 +673,7 @@ namespace data
if (r->GetProfile ()->IsUnreachable ()) if (r->GetProfile ()->IsUnreachable ())
r->SetUnreachable (true); r->SetUnreachable (true);
// make router reachable back if too few routers or floodfills // make router reachable back if too few routers or floodfills
if (r->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate || if (r->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate || isOffline ||
(r->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS))) (r->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
r->SetUnreachable (false); r->SetUnreachable (false);
if (!r->IsUnreachable ()) if (!r->IsUnreachable ())

View file

@ -39,6 +39,7 @@ namespace data
{ {
const int NETDB_MIN_ROUTERS = 90; const int NETDB_MIN_ROUTERS = 90;
const int NETDB_MIN_FLOODFILLS = 5; const int NETDB_MIN_FLOODFILLS = 5;
const int NETDB_MIN_TRANSPORTS = 10 ; // otherwise assume offline
const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1200; const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1200;
const int NETDB_NUM_ROUTERS_THRESHOLD = 4*NETDB_NUM_FLOODFILLS_THRESHOLD; const int NETDB_NUM_ROUTERS_THRESHOLD = 4*NETDB_NUM_FLOODFILLS_THRESHOLD;
const int NETDB_TUNNEL_CREATION_RATE_THRESHOLD = 10; // in % const int NETDB_TUNNEL_CREATION_RATE_THRESHOLD = 10; // in %

View file

@ -11,6 +11,7 @@
#include <memory> #include <memory>
#include <future> #include <future>
#include <boost/asio.hpp>
#include "Identity.h" #include "Identity.h"
namespace i2p namespace i2p
@ -68,6 +69,11 @@ namespace data
bool IsUseful() const; bool IsUseful() const;
bool IsDuplicated () const { return m_IsDuplicated; }; bool IsDuplicated () const { return m_IsDuplicated; };
const boost::asio::ip::udp::endpoint& GetLastEndpoint () const { return m_LastEndpoint; }
void SetLastEndpoint (const boost::asio::ip::udp::endpoint& ep) { m_LastEndpoint = ep; }
bool HasLastEndpoint (bool v4) const { return !m_LastEndpoint.address ().is_unspecified () && m_LastEndpoint.port () &&
((v4 && m_LastEndpoint.address ().is_v4 ()) || (!v4 && m_LastEndpoint.address ().is_v6 ())); }
private: private:
void UpdateTime (); void UpdateTime ();
@ -90,6 +96,8 @@ namespace data
uint32_t m_NumTimesRejected; uint32_t m_NumTimesRejected;
bool m_HasConnected; // successful trusted(incoming or NTCP2) connection bool m_HasConnected; // successful trusted(incoming or NTCP2) connection
bool m_IsDuplicated; bool m_IsDuplicated;
// connectivity
boost::asio::ip::udp::endpoint m_LastEndpoint; // SSU2 for non-published addresses
}; };
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash); std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);

View file

@ -1489,7 +1489,7 @@ namespace i2p
void RouterContext::UpdateCongestion () void RouterContext::UpdateCongestion ()
{ {
auto c = i2p::data::RouterInfo::eLowCongestion; auto c = i2p::data::RouterInfo::eLowCongestion;
if (!AcceptsTunnels () || !m_ShareRatio) if (!AcceptsTunnels () || !m_ShareRatio || (m_Error == eRouterErrorSymmetricNAT && !SupportsV6 () && !SupportsMesh ()))
c = i2p::data::RouterInfo::eRejectAll; c = i2p::data::RouterInfo::eRejectAll;
else else
{ {

View file

@ -146,7 +146,6 @@ namespace garlic
void SetNetID (int netID) { m_NetID = netID; }; void SetNetID (int netID) { m_NetID = netID; };
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data); bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data);
bool DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data); bool DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data);
void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag);
void UpdatePort (int port); // called from Daemon void UpdatePort (int port); // called from Daemon
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU2 or Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU2 or Daemon
@ -186,24 +185,24 @@ namespace garlic
void UpdateTimestamp (uint64_t ts); // in seconds, called from NetDb before publishing void UpdateTimestamp (uint64_t ts); // in seconds, called from NetDb before publishing
// implements LocalDestination // implements LocalDestination
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); }; std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const override{ return m_Keys.GetPublic (); };
bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const; bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const override;
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; void SetLeaseSetUpdated (bool post) override {};
void SetLeaseSetUpdated () {};
// implements GarlicDestination // implements GarlicDestination
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () { return nullptr; }; std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () override { return nullptr; };
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const; std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const override;
// override GarlicDestination // override GarlicDestination
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg); void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg) override;
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg); void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg) override;
void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag) override;
protected: protected:
// implements GarlicDestination // implements GarlicDestination
void HandleI2NPMessage (const uint8_t * buf, size_t len); void HandleI2NPMessage (const uint8_t * buf, size_t len) override;
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID); bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) override;
private: private:
@ -216,6 +215,7 @@ namespace garlic
void UpdateSSU2Keys (); void UpdateSSU2Keys ();
bool Load (); bool Load ();
void SaveKeys (); void SaveKeys ();
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
uint16_t SelectRandomPort () const; uint16_t SelectRandomPort () const;
void PublishNTCP2Address (std::shared_ptr<i2p::data::RouterInfo::Address> address, int port, bool publish) const; void PublishNTCP2Address (std::shared_ptr<i2p::data::RouterInfo::Address> address, int port, bool publish) const;

View file

@ -216,15 +216,16 @@ namespace transport
return ep.port (); return ep.port ();
} }
bool SSU2Server::IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep) bool SSU2Server::IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max)
{ {
if (!ep.port () || ep.address ().is_unspecified ()) return false; if (!ep.port () || ep.address ().is_unspecified ()) return false;
std::lock_guard<std::mutex> l(m_ConnectedRecentlyMutex);
auto it = m_ConnectedRecently.find (ep); auto it = m_ConnectedRecently.find (ep);
if (it != m_ConnectedRecently.end ()) if (it != m_ConnectedRecently.end ())
{ {
if (i2p::util::GetSecondsSinceEpoch () <= it->second + SSU2_HOLE_PUNCH_EXPIRATION) if (i2p::util::GetSecondsSinceEpoch () <= it->second + (max ? SSU2_MAX_HOLE_PUNCH_EXPIRATION : SSU2_MIN_HOLE_PUNCH_EXPIRATION))
return true; return true;
else else if (max)
m_ConnectedRecently.erase (it); m_ConnectedRecently.erase (it);
} }
return false; return false;
@ -233,7 +234,8 @@ namespace transport
void SSU2Server::AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts) void SSU2Server::AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts)
{ {
if (!ep.port () || ep.address ().is_unspecified () || if (!ep.port () || ep.address ().is_unspecified () ||
i2p::util::GetSecondsSinceEpoch () > ts + SSU2_HOLE_PUNCH_EXPIRATION) return; i2p::util::GetSecondsSinceEpoch () > ts + SSU2_MAX_HOLE_PUNCH_EXPIRATION) return;
std::lock_guard<std::mutex> l(m_ConnectedRecentlyMutex);
auto [it, added] = m_ConnectedRecently.try_emplace (ep, ts); auto [it, added] = m_ConnectedRecently.try_emplace (ep, ts);
if (!added && ts > it->second) if (!added && ts > it->second)
it->second = ts; // renew timestamp of existing endpoint it->second = ts; // renew timestamp of existing endpoint
@ -475,7 +477,7 @@ namespace transport
HandleReceivedPackets (std::move (receivedPackets)); HandleReceivedPackets (std::move (receivedPackets));
} }
void SSU2Server::AddSession (std::shared_ptr<SSU2Session> session) bool SSU2Server::AddSession (std::shared_ptr<SSU2Session> session)
{ {
if (session) if (session)
{ {
@ -483,8 +485,10 @@ namespace transport
{ {
if (session->GetState () != eSSU2SessionStatePeerTest) if (session->GetState () != eSSU2SessionStatePeerTest)
AddSessionByRouterHash (session); AddSessionByRouterHash (session);
return true;
} }
} }
return false;
} }
void SSU2Server::RemoveSession (uint64_t connID) void SSU2Server::RemoveSession (uint64_t connID)
@ -833,6 +837,29 @@ namespace transport
} }
} }
bool SSU2Server::CheckPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep, bool peerTest)
{
auto s = FindPendingOutgoingSession (ep);
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]() { s->SendPeerTest (); });
}
return true;
}
return false;
}
bool SSU2Server::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool SSU2Server::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest) std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest)
{ {
@ -852,34 +879,28 @@ namespace transport
if (isValidEndpoint) if (isValidEndpoint)
{ {
if (i2p::transport::transports.IsInReservedRange(address->host)) return false; if (i2p::transport::transports.IsInReservedRange(address->host)) return false;
auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (address->host, address->port)); if (CheckPendingOutgoingSession (boost::asio::ip::udp::endpoint (address->host, address->port), peerTest)) return false;
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]() { s->SendPeerTest (); });
}
return false;
}
} }
auto session = std::make_shared<SSU2Session> (*this, router, address); auto session = std::make_shared<SSU2Session> (*this, router, address);
if (!isValidEndpoint && router->GetProfile ()->HasLastEndpoint (address->IsV4 ()))
{
// router doesn't publish endpoint, but we connected before and hole punch might be alive
auto ep = router->GetProfile ()->GetLastEndpoint ();
if (IsConnectedRecently (ep, false))
{
if (CheckPendingOutgoingSession (ep, peerTest)) return false;
session->SetRemoteEndpoint (ep);
isValidEndpoint = true;
}
}
if (peerTest) if (peerTest)
session->SetOnEstablished ([session]() {session->SendPeerTest (); }); session->SetOnEstablished ([session]() {session->SendPeerTest (); });
if (address->UsesIntroducer ()) if (isValidEndpoint) // we know endpoint
GetService ().post (std::bind (&SSU2Server::ConnectThroughIntroducer, this, session));
else if (isValidEndpoint) // we can't connect without endpoint
GetService ().post ([session]() { session->Connect (); }); GetService ().post ([session]() { session->Connect (); });
else if (address->UsesIntroducer ()) // we don't know endpoint yet
GetService ().post (std::bind (&SSU2Server::ConnectThroughIntroducer, this, session));
else else
return false; return false;
} }
@ -1129,7 +1150,7 @@ namespace transport
for (auto it = m_ConnectedRecently.begin (); it != m_ConnectedRecently.end (); ) for (auto it = m_ConnectedRecently.begin (); it != m_ConnectedRecently.end (); )
{ {
if (ts > it->second + SSU2_HOLE_PUNCH_EXPIRATION) if (ts > it->second + SSU2_MAX_HOLE_PUNCH_EXPIRATION)
it = m_ConnectedRecently.erase (it); it = m_ConnectedRecently.erase (it);
else else
it++; it++;

View file

@ -42,7 +42,8 @@ namespace transport
const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds
const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds
const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds
const int SSU2_HOLE_PUNCH_EXPIRATION = 150; // in seconds const int SSU2_MIN_HOLE_PUNCH_EXPIRATION = 30; // in seconds
const int SSU2_MAX_HOLE_PUNCH_EXPIRATION = 160; // in seconds
const size_t SSU2_MAX_NUM_PACKETS_PER_BATCH = 64; const size_t SSU2_MAX_NUM_PACKETS_PER_BATCH = 64;
class SSU2Server: private i2p::util::RunnableServiceWithWork class SSU2Server: private i2p::util::RunnableServiceWithWork
@ -77,14 +78,14 @@ namespace transport
bool UsesProxy () const { return m_IsThroughProxy; }; bool UsesProxy () const { return m_IsThroughProxy; };
bool IsSupported (const boost::asio::ip::address& addr) const; bool IsSupported (const boost::asio::ip::address& addr) const;
uint16_t GetPort (bool v4) const; uint16_t GetPort (bool v4) const;
bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep); bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max = true);
void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts); void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts);
std::mt19937& GetRng () { return m_Rng; } std::mt19937& GetRng () { return m_Rng; }
bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; } bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; }
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
void AdjustTimeOffset (int64_t offset, std::shared_ptr<const i2p::data::IdentityEx> from); void AdjustTimeOffset (int64_t offset, std::shared_ptr<const i2p::data::IdentityEx> from);
void AddSession (std::shared_ptr<SSU2Session> session); bool AddSession (std::shared_ptr<SSU2Session> session);
void RemoveSession (uint64_t connID); void RemoveSession (uint64_t connID);
void RequestRemoveSession (uint64_t connID); void RequestRemoveSession (uint64_t connID);
void AddSessionByRouterHash (std::shared_ptr<SSU2Session> session); void AddSessionByRouterHash (std::shared_ptr<SSU2Session> session);
@ -147,6 +148,7 @@ namespace transport
void ScheduleResend (bool more); void ScheduleResend (bool more);
void HandleResendTimer (const boost::system::error_code& ecode); void HandleResendTimer (const boost::system::error_code& ecode);
bool CheckPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep, bool peerTest);
void ConnectThroughIntroducer (std::shared_ptr<SSU2Session> session); void ConnectThroughIntroducer (std::shared_ptr<SSU2Session> session);
std::vector<std::shared_ptr<SSU2Session> > FindIntroducers (int maxNumIntroducers, std::vector<std::shared_ptr<SSU2Session> > FindIntroducers (int maxNumIntroducers,
bool v4, const std::unordered_set<i2p::data::IdentHash>& excluded); bool v4, const std::unordered_set<i2p::data::IdentHash>& excluded);
@ -193,6 +195,7 @@ namespace transport
std::shared_ptr<const i2p::data::IdentityEx> m_PendingTimeOffsetFrom; std::shared_ptr<const i2p::data::IdentityEx> m_PendingTimeOffsetFrom;
std::mt19937 m_Rng; std::mt19937 m_Rng;
std::map<boost::asio::ip::udp::endpoint, uint64_t> m_ConnectedRecently; // endpoint -> last activity time in seconds std::map<boost::asio::ip::udp::endpoint, uint64_t> m_ConnectedRecently; // endpoint -> last activity time in seconds
mutable std::mutex m_ConnectedRecentlyMutex;
std::unordered_map<uint32_t, std::pair <std::weak_ptr<SSU2PeerTestSession>, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp) std::unordered_map<uint32_t, std::pair <std::weak_ptr<SSU2PeerTestSession>, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp)
std::list<Packet *> m_ReceivedPacketsQueue; std::list<Packet *> m_ReceivedPacketsQueue;
mutable std::mutex m_ReceivedPacketsQueueMutex; mutable std::mutex m_ReceivedPacketsQueueMutex;

View file

@ -83,7 +83,7 @@ namespace transport
std::shared_ptr<const i2p::data::RouterInfo::Address> addr, bool noise): std::shared_ptr<const i2p::data::RouterInfo::Address> addr, bool noise):
TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT), TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT),
m_Server (server), m_Address (addr), m_RemoteTransports (0), m_RemotePeerTestTransports (0), m_Server (server), m_Address (addr), m_RemoteTransports (0), m_RemotePeerTestTransports (0),
m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), m_RemoteVersion (0), m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown),
m_SendPacketNum (0), m_ReceivePacketNum (0), m_LastDatetimeSentPacketNum (0), m_SendPacketNum (0), m_ReceivePacketNum (0), m_LastDatetimeSentPacketNum (0),
m_IsDataReceived (false), m_RTT (SSU2_UNKNOWN_RTT), m_IsDataReceived (false), m_RTT (SSU2_UNKNOWN_RTT),
m_MsgLocalExpirationTimeout (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX), m_MsgLocalExpirationTimeout (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX),
@ -103,6 +103,7 @@ namespace transport
InitNoiseXKState1 (*m_NoiseState, m_Address->s); InitNoiseXKState1 (*m_NoiseState, m_Address->s);
m_RemoteEndpoint = boost::asio::ip::udp::endpoint (m_Address->host, m_Address->port); m_RemoteEndpoint = boost::asio::ip::udp::endpoint (m_Address->host, m_Address->port);
m_RemoteTransports = in_RemoteRouter->GetCompatibleTransports (false); m_RemoteTransports = in_RemoteRouter->GetCompatibleTransports (false);
m_RemoteVersion = in_RemoteRouter->GetVersion ();
if (in_RemoteRouter->IsSSU2PeerTesting (true)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V4; if (in_RemoteRouter->IsSSU2PeerTesting (true)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V4;
if (in_RemoteRouter->IsSSU2PeerTesting (false)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V6; if (in_RemoteRouter->IsSSU2PeerTesting (false)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V6;
RAND_bytes ((uint8_t *)&m_DestConnID, 8); RAND_bytes ((uint8_t *)&m_DestConnID, 8);
@ -226,6 +227,13 @@ namespace transport
if (m_Server.AddPendingOutgoingSession (shared_from_this ())) if (m_Server.AddPendingOutgoingSession (shared_from_this ()))
{ {
m_Server.RemoveSession (GetConnID ()); m_Server.RemoveSession (GetConnID ());
// update endpoint in profile because we know it now
auto identity = GetRemoteIdentity ();
if (identity)
{
auto profile = i2p::data::GetRouterProfile (identity->GetIdentHash ());
if (profile) profile->SetLastEndpoint (m_RemoteEndpoint);
}
// connect // connect
LogPrint (eLogDebug, "SSU2: Connecting after introduction to ", GetIdentHashBase64()); LogPrint (eLogDebug, "SSU2: Connecting after introduction to ", GetIdentHashBase64());
Connect (); Connect ();
@ -1169,6 +1177,8 @@ namespace transport
" and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ())); " and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
return false; return false;
} }
if (!m_Address->published)
ri->GetProfile ()->SetLastEndpoint (m_RemoteEndpoint);
SetRemoteIdentity (ri->GetRouterIdentity ()); SetRemoteIdentity (ri->GetRouterIdentity ());
AdjustMaxPayloadSize (); AdjustMaxPayloadSize ();
m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now
@ -1176,6 +1186,7 @@ namespace transport
m_RemotePeerTestTransports = 0; m_RemotePeerTestTransports = 0;
if (ri->IsSSU2PeerTesting (true)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V4; if (ri->IsSSU2PeerTesting (true)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V4;
if (ri->IsSSU2PeerTesting (false)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V6; if (ri->IsSSU2PeerTesting (false)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V6;
m_RemoteVersion = ri->GetVersion ();
// handle other blocks // handle other blocks
HandlePayload (decryptedPayload.data () + riSize + 3, decryptedPayload.size () - riSize - 3); HandlePayload (decryptedPayload.data () + riSize + 3, decryptedPayload.size () - riSize - 3);
@ -1920,25 +1931,28 @@ namespace transport
return; return;
} }
auto mts = i2p::util::GetMillisecondsSinceEpoch (); auto mts = i2p::util::GetMillisecondsSinceEpoch ();
session->m_RelaySessions.emplace (bufbe32toh (buf + 1), // nonce uint32_t nonce = bufbe32toh (buf + 1);
std::make_pair (shared_from_this (), mts/1000) ); if (session->m_RelaySessions.emplace (nonce, std::make_pair (shared_from_this (), mts/1000)).second)
{
// send relay intro to Charlie
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); // Alice's RI
if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr;
if (!r) LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found");
// send relay intro to Charlie auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); // Alice's RI packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0;
if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; if (!packet->payloadSize && r)
if (!r) LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found"); session->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
packet->payloadSize += CreateRelayIntroBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, buf + 1, len -1);
auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); if (packet->payloadSize < m_MaxPayloadSize)
packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
if (!packet->payloadSize && r) uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize);
session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); packet->sendTime = mts;
packet->payloadSize += CreateRelayIntroBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, buf + 1, len -1); // Charlie always responds with RelayResponse
if (packet->payloadSize < m_MaxPayloadSize) session->m_SentPackets.emplace (packetNum, packet);
packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); }
uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize); else
packet->sendTime = mts; LogPrint (eLogInfo, "SSU2: Relay request nonce ", nonce, " already exists. Ignore");
// Charlie always responds with RelayResponse
session->m_SentPackets.emplace (packetNum, packet);
} }
void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len, int attempts) void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len, int attempts)
@ -2024,15 +2038,22 @@ namespace transport
{ {
// send HolePunch // send HolePunch
auto holePunchSession = std::make_shared<SSU2HolePunchSession>(m_Server, nonce, ep, addr); auto holePunchSession = std::make_shared<SSU2HolePunchSession>(m_Server, nonce, ep, addr);
m_Server.AddSession (holePunchSession); if (m_Server.AddSession (holePunchSession))
holePunchSession->SendHolePunch (packet->payload, packet->payloadSize); // relay response block holePunchSession->SendHolePunch (packet->payload, packet->payloadSize); // relay response block
else
{
LogPrint (eLogInfo, "SSU2: Relay intro nonce ", nonce, " already exists. Ignore");
return;
}
} }
packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 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);
// sometimes Bob doesn't ack this RelayResponse if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION)
// TODO: uncomment line below once the problem is resolved {
//packet->sendTime = mts; // sometimes Bob doesn't ack this RelayResponse in older versions
//m_SentPackets.emplace (packetNum, packet); packet->sendTime = i2p::util::GetMillisecondsSinceEpoch ();
m_SentPackets.emplace (packetNum, packet);
}
} }
void SSU2Session::HandleRelayResponse (const uint8_t * buf, size_t len) void SSU2Session::HandleRelayResponse (const uint8_t * buf, size_t len)
@ -2067,11 +2088,13 @@ namespace transport
memcpy (payload + 3, buf, len); // forward to Alice as is memcpy (payload + 3, buf, len); // forward to Alice as is
packet->payloadSize = len + 3; packet->payloadSize = len + 3;
packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
/*uint32_t packetNum = */it->second.first->SendData (packet->payload, packet->payloadSize); uint32_t packetNum = it->second.first->SendData (packet->payload, packet->payloadSize);
// sometimes Alice doesn't ack this RelayResponse if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION)
// TODO: uncomment line below once the problem is resolved {
//packet->sendTime = i2p::util::GetMillisecondsSinceEpoch (); // sometimes Alice doesn't ack this RelayResponse in older versions
//it->second.first->m_SentPackets.emplace (packetNum, packet); packet->sendTime = i2p::util::GetMillisecondsSinceEpoch ();
it->second.first->m_SentPackets.emplace (packetNum, packet);
}
} }
else else
{ {
@ -2139,29 +2162,33 @@ namespace transport
GetRemoteIdentity ()->GetIdentHash ()); GetRemoteIdentity ()->GetIdentHash ());
if (session) // session with Charlie if (session) // session with Charlie
{ {
m_Server.AddPeerTest (nonce, shared_from_this (), ts/1000); if (m_Server.AddPeerTest (nonce, shared_from_this (), ts/1000))
auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
// Alice's RouterInfo
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ());
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 (packet->payloadSize + len + 48 > m_MaxPayloadSize)
{ {
// doesn't fit one message, send RouterInfo in separate message auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
// Alice's RouterInfo
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ());
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 (packet->payloadSize + len + 48 > m_MaxPayloadSize)
{
// doesn't fit one message, send RouterInfo in separate message
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
packet->payloadSize += CreatePeerTestBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, 2,
eSSU2PeerTestCodeAccept, GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset);
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); uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED);
packet->sendTime = ts; packet->sendTime = ts;
session->m_SentPackets.emplace (packetNum, packet); session->m_SentPackets.emplace (packetNum, packet);
packet = m_Server.GetSentPacketsPool ().AcquireShared (); // new packet
} }
// PeerTest to Charlie else
packet->payloadSize += CreatePeerTestBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, 2, LogPrint (eLogInfo, "SSU2: Peer test 1 nonce ", nonce, " already exists. Ignored");
eSSU2PeerTestCodeAccept, GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset);
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 else
{ {
@ -2303,11 +2330,11 @@ namespace transport
{ {
session->SetRemoteIdentity (r->GetIdentity ()); session->SetRemoteIdentity (r->GetIdentity ());
auto addr = r->GetSSU2Address (m_Address->IsV4 ()); auto addr = r->GetSSU2Address (m_Address->IsV4 ());
if (addr) if (addr && addr->IsPeerTesting ())
{ {
if (session->GetMsgNumReceived () >= 5) if (session->GetMsgNumReceived () >= 5)
{ {
// msg 5 already received // msg 5 already received and we know remote endpoint
if (session->GetMsgNumReceived () == 5) if (session->GetMsgNumReceived () == 5)
{ {
if (!session->IsConnectedRecently ()) if (!session->IsConnectedRecently ())
@ -2324,7 +2351,11 @@ namespace transport
if (GetTestingState ()) if (GetTestingState ())
{ {
// schedule msg 6 with delay // schedule msg 6 with delay
session->SendPeerTest (6, buf + offset, len - offset, addr, true); if (!addr->host.is_unspecified () && addr->port)
{
session->SetRemoteEndpoint (boost::asio::ip::udp::endpoint (addr->host, addr->port));
session->SendPeerTest (6, buf + offset, len - offset, addr, true);
}
SetTestingState (false); SetTestingState (false);
if (GetRouterStatus () != eRouterStatusFirewalled && addr->IsPeerTesting ()) if (GetRouterStatus () != eRouterStatusFirewalled && addr->IsPeerTesting ())
{ {
@ -2342,7 +2373,7 @@ namespace transport
} }
else else
{ {
LogPrint (eLogWarning, "SSU2: Peer test 4 address not found"); LogPrint (eLogWarning, "SSU2: Peer test 4 address not found or not supported");
session->Done (); session->Done ();
} }
} }
@ -3024,7 +3055,7 @@ namespace transport
{ {
if (ts > it->second.second + SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT) if (ts > it->second.second + SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT)
{ {
LogPrint (eLogWarning, "SSU2: Relay nonce ", it->first, " was not responded in ", SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT, " seconds, deleted"); LogPrint (eLogInfo, "SSU2: Relay nonce ", it->first, " was not responded in ", SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT, " seconds, deleted");
it = m_RelaySessions.erase (it); it = m_RelaySessions.erase (it);
} }
else else

View file

@ -15,6 +15,7 @@
#include <set> #include <set>
#include <list> #include <list>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "version.h"
#include "Crypto.h" #include "Crypto.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "RouterContext.h" #include "RouterContext.h"
@ -55,6 +56,7 @@ namespace transport
const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send
const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64; const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64;
const int SSU2_SEND_DATETIME_NUM_PACKETS = 256; const int SSU2_SEND_DATETIME_NUM_PACKETS = 256;
const int SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION = MAKE_VERSION_NUMBER(0, 9, 64); // 0.9.64
// flags // flags
const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01; const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01;
@ -368,6 +370,7 @@ namespace transport
std::shared_ptr<const i2p::data::RouterInfo::Address> m_Address; std::shared_ptr<const i2p::data::RouterInfo::Address> m_Address;
boost::asio::ip::udp::endpoint m_RemoteEndpoint; boost::asio::ip::udp::endpoint m_RemoteEndpoint;
i2p::data::RouterInfo::CompatibleTransports m_RemoteTransports, m_RemotePeerTestTransports; i2p::data::RouterInfo::CompatibleTransports m_RemoteTransports, m_RemotePeerTestTransports;
int m_RemoteVersion;
uint64_t m_DestConnID, m_SourceConnID; uint64_t m_DestConnID, m_SourceConnID;
SSU2SessionState m_State; SSU2SessionState m_State;
uint8_t m_KeyDataSend[64], m_KeyDataReceive[64]; uint8_t m_KeyDataSend[64], m_KeyDataReceive[64];

View file

@ -73,14 +73,14 @@ namespace stream
m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed
m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false),
m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false),
m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_LocalDestination (local), m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_LocalDestination (local),
m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service),
m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port),
m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0),
m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO),
m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT),
m_Jitter (0), m_MinPacingTime (0), m_Jitter (0), m_MinPacingTime (0),
m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_RemoteLeaseChangeTime (0),
m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed
m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU)
{ {
@ -101,13 +101,13 @@ namespace stream
m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed
m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false),
m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false),
m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_LocalDestination (local), m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_LocalDestination (local),
m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service),
m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT),
m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0),
m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()),
m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0),
m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_RemoteLeaseChangeTime (0),
m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed
m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU)
{ {
@ -256,6 +256,7 @@ namespace stream
if (receivedSeqn <= m_PreviousReceivedSequenceNumber || receivedSeqn == m_LastReceivedSequenceNumber) if (receivedSeqn <= m_PreviousReceivedSequenceNumber || receivedSeqn == m_LastReceivedSequenceNumber)
{ {
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel); m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel);
CancelRemoteLeaseChange ();
UpdateCurrentRemoteLease (); UpdateCurrentRemoteLease ();
} }
m_PreviousReceivedSequenceNumber = receivedSeqn; m_PreviousReceivedSequenceNumber = receivedSeqn;
@ -1104,6 +1105,7 @@ namespace stream
{ {
if (!m_RemoteLeaseSet) if (!m_RemoteLeaseSet)
{ {
CancelRemoteLeaseChange ();
UpdateCurrentRemoteLease (); UpdateCurrentRemoteLease ();
if (!m_RemoteLeaseSet) if (!m_RemoteLeaseSet)
{ {
@ -1127,9 +1129,30 @@ namespace stream
} }
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
if (!m_CurrentRemoteLease || !m_CurrentRemoteLease->endDate || // excluded from LeaseSet if (!m_CurrentRemoteLease || !m_CurrentRemoteLease->endDate) // excluded from LeaseSet
ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD) {
CancelRemoteLeaseChange ();
UpdateCurrentRemoteLease (true); UpdateCurrentRemoteLease (true);
}
if (m_RemoteLeaseChangeTime && m_IsRemoteLeaseChangeInProgress && ts > m_RemoteLeaseChangeTime + INITIAL_RTT)
{
CancelRemoteLeaseChange ();
m_CurrentRemoteLease = m_NextRemoteLease;
HalveWindowSize ();
}
auto currentRemoteLease = m_CurrentRemoteLease;
if (!m_IsRemoteLeaseChangeInProgress && m_RemoteLeaseSet && m_CurrentRemoteLease && ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD)
{
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (false);
if (leases.size ())
{
m_IsRemoteLeaseChangeInProgress = true;
UpdateCurrentRemoteLease (true);
m_NextRemoteLease = m_CurrentRemoteLease;
}
else
UpdateCurrentRemoteLease (true);
}
if (m_CurrentRemoteLease && ts < m_CurrentRemoteLease->endDate + i2p::data::LEASE_ENDDATE_THRESHOLD) if (m_CurrentRemoteLease && ts < m_CurrentRemoteLease->endDate + i2p::data::LEASE_ENDDATE_THRESHOLD)
{ {
bool freshTunnel = false; bool freshTunnel = false;
@ -1166,6 +1189,11 @@ namespace stream
msg msg
}); });
m_NumSentBytes += it->GetLength (); m_NumSentBytes += it->GetLength ();
if (m_IsRemoteLeaseChangeInProgress && !m_RemoteLeaseChangeTime)
{
m_RemoteLeaseChangeTime = ts;
m_CurrentRemoteLease = currentRemoteLease; // change it back before new lease is confirmed
}
} }
m_CurrentOutboundTunnel->SendTunnelDataMsgs (msgs); m_CurrentOutboundTunnel->SendTunnelDataMsgs (msgs);
} }
@ -1209,7 +1237,8 @@ namespace stream
if (m_Status != eStreamStatusTerminated) if (m_Status != eStreamStatusTerminated)
{ {
m_SendTimer.cancel (); m_SendTimer.cancel ();
m_SendTimer.expires_from_now (boost::posix_time::microseconds(SEND_INTERVAL)); m_SendTimer.expires_from_now (boost::posix_time::microseconds(
SEND_INTERVAL + m_LocalDestination.GetRandom () % SEND_INTERVAL_VARIANCE));
m_SendTimer.async_wait (std::bind (&Stream::HandleSendTimer, m_SendTimer.async_wait (std::bind (&Stream::HandleSendTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
@ -1222,8 +1251,17 @@ namespace stream
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
if (m_LastSendTime && ts*1000 > m_LastSendTime*1000 + m_PacingTime) if (m_LastSendTime && ts*1000 > m_LastSendTime*1000 + m_PacingTime)
{ {
m_NumPacketsToSend = ((ts*1000 - m_LastSendTime*1000) + m_PacingTimeRem) / m_PacingTime; if (m_PacingTime)
m_PacingTimeRem = ((ts*1000 - m_LastSendTime*1000) + m_PacingTimeRem) - (m_NumPacketsToSend * m_PacingTime); {
auto numPackets = std::lldiv (m_PacingTimeRem + ts*1000 - m_LastSendTime*1000, m_PacingTime);
m_NumPacketsToSend = numPackets.quot;
m_PacingTimeRem = numPackets.rem;
}
else
{
LogPrint (eLogError, "Streaming: pacing time is zero");
m_NumPacketsToSend = 1; m_PacingTimeRem = 0;
}
m_IsSendTime = true; m_IsSendTime = true;
if (m_WindowIncCounter && m_WindowSize < MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) if (m_WindowIncCounter && m_WindowSize < MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime)
{ {
@ -1366,6 +1404,7 @@ namespace stream
} }
else else
{ {
CancelRemoteLeaseChange ();
UpdateCurrentRemoteLease (); // pick another lease UpdateCurrentRemoteLease (); // pick another lease
LogPrint (eLogWarning, "Streaming: Resend #", m_NumResendAttempts, LogPrint (eLogWarning, "Streaming: Resend #", m_NumResendAttempts,
", another remote lease has been selected for stream with rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID); ", another remote lease has been selected for stream with rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID);
@ -1506,22 +1545,9 @@ namespace stream
LogPrint (eLogWarning, "Streaming: Remote LeaseSet not found"); LogPrint (eLogWarning, "Streaming: Remote LeaseSet not found");
m_CurrentRemoteLease = nullptr; m_CurrentRemoteLease = nullptr;
} }
if (isLeaseChanged) if (isLeaseChanged && !m_IsRemoteLeaseChangeInProgress)
{ {
// drop window to initial upon RemoteLease change HalveWindowSize ();
m_RTO = INITIAL_RTO;
if (m_WindowSize > INITIAL_WINDOW_SIZE)
{
m_WindowDropTargetSize = std::max (m_WindowSize/2, (float)INITIAL_WINDOW_SIZE);
m_IsWinDropped = true;
}
else
m_WindowSize = INITIAL_WINDOW_SIZE;
m_LastWindowDropSize = 0;
m_WindowIncCounter = 0;
m_IsFirstRttSample = true;
m_IsFirstACK = true;
UpdatePacingTime ();
} }
} }
@ -1560,6 +1586,29 @@ namespace stream
UpdatePacingTime (); UpdatePacingTime ();
} }
void Stream::HalveWindowSize ()
{
m_RTO = INITIAL_RTO;
if (m_WindowSize > INITIAL_WINDOW_SIZE)
{
m_WindowDropTargetSize = std::max (m_WindowSize/2, (float)INITIAL_WINDOW_SIZE);
m_IsWinDropped = true;
}
else
m_WindowSize = INITIAL_WINDOW_SIZE;
m_LastWindowDropSize = 0;
m_WindowIncCounter = 0;
m_IsFirstRttSample = true;
m_IsFirstACK = true;
UpdatePacingTime ();
}
void Stream::CancelRemoteLeaseChange ()
{
m_RemoteLeaseChangeTime = 0;
m_IsRemoteLeaseChangeInProgress = false;
}
StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort, bool gzip): StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort, bool gzip):
m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip),
m_PendingIncomingTimer (m_Owner->GetService ()), m_PendingIncomingTimer (m_Owner->GetService ()),

View file

@ -69,7 +69,8 @@ namespace stream
const int PENDING_INCOMING_TIMEOUT = 10; // in seconds const int PENDING_INCOMING_TIMEOUT = 10; // in seconds
const int MAX_RECEIVE_TIMEOUT = 20; // in seconds const int MAX_RECEIVE_TIMEOUT = 20; // in seconds
const uint16_t DELAY_CHOKING = 60000; // in milliseconds const uint16_t DELAY_CHOKING = 60000; // in milliseconds
const uint64_t SEND_INTERVAL = 1000; // in microseconds const uint64_t SEND_INTERVAL = 10000; // in microseconds
const uint64_t SEND_INTERVAL_VARIANCE = 2000; // in microseconds
const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL = 7500; // in milliseconds const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL = 7500; // in milliseconds
const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL_VARIANCE = 3200; // in milliseconds const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL_VARIANCE = 3200; // in milliseconds
const bool LOSS_BASED_CONTROL_ENABLED = 1; // 0/1 const bool LOSS_BASED_CONTROL_ENABLED = 1; // 0/1
@ -248,6 +249,8 @@ namespace stream
void UpdatePacingTime (); void UpdatePacingTime ();
void ProcessWindowDrop (); void ProcessWindowDrop ();
void HalveWindowSize ();
void CancelRemoteLeaseChange ();
private: private:
@ -268,12 +271,14 @@ namespace stream
bool m_IsWinDropped; bool m_IsWinDropped;
bool m_IsTimeOutResend; bool m_IsTimeOutResend;
bool m_IsImmediateAckRequested; bool m_IsImmediateAckRequested;
bool m_IsRemoteLeaseChangeInProgress;
StreamingDestination& m_LocalDestination; StreamingDestination& m_LocalDestination;
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity; std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
std::shared_ptr<const i2p::crypto::Verifier> m_TransientVerifier; // in case of offline key std::shared_ptr<const i2p::crypto::Verifier> m_TransientVerifier; // in case of offline key
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet; std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession; std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease; std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease;
std::shared_ptr<const i2p::data::Lease> m_NextRemoteLease;
std::shared_ptr<i2p::tunnel::OutboundTunnel> m_CurrentOutboundTunnel; std::shared_ptr<i2p::tunnel::OutboundTunnel> m_CurrentOutboundTunnel;
std::queue<Packet *> m_ReceiveQueue; std::queue<Packet *> m_ReceiveQueue;
std::set<Packet *, PacketCmp> m_SavedPackets; std::set<Packet *, PacketCmp> m_SavedPackets;
@ -289,7 +294,7 @@ namespace stream
int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample;
double m_Jitter; double m_Jitter;
uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, // microseconds uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, // microseconds
m_LastSendTime; // miliseconds m_LastSendTime, m_RemoteLeaseChangeTime; // miliseconds
uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed
int m_NumResendAttempts, m_NumPacketsToSend; int m_NumResendAttempts, m_NumPacketsToSend;
size_t m_MTU; size_t m_MTU;

View file

@ -672,6 +672,31 @@ namespace transport
if (transport & compatibleTransports) if (transport & compatibleTransports)
peer->priority.push_back (transport); peer->priority.push_back (transport);
} }
if (peer->priority.empty ())
{
// try recently connected SSU2 if any
auto supportedTransports = context.GetRouterInfo ().GetCompatibleTransports (false) &
peer->router->GetCompatibleTransports (false);
if (supportedTransports & (i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6))
{
auto ep = peer->router->GetProfile ()->GetLastEndpoint ();
if (!ep.address ().is_unspecified () && ep.port ())
{
if (ep.address ().is_v4 ())
{
if ((supportedTransports & i2p::data::RouterInfo::eSSU2V4) &&
m_SSU2Server->IsConnectedRecently (ep, false))
peer->priority.push_back (i2p::data::RouterInfo::eSSU2V4);
}
else if (ep.address ().is_v6 ())
{
if ((supportedTransports & i2p::data::RouterInfo::eSSU2V6) &&
m_SSU2Server->IsConnectedRecently (ep))
peer->priority.push_back (i2p::data::RouterInfo::eSSU2V6);
}
}
}
}
} }
void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident) void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)

View file

@ -350,7 +350,8 @@ namespace tunnel
Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr), m_MaxNumTransitTunnels (DEFAULT_MAX_NUM_TRANSIT_TUNNELS), 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_TotalNumSuccesiveTunnelCreations (0), m_TotalNumFailedTunnelCreations (0), // for normal average
m_TunnelCreationSuccessRate (TCSR_START_VALUE), m_TunnelCreationAttemptsNum(0) m_TunnelCreationSuccessRate (TCSR_START_VALUE), m_TunnelCreationAttemptsNum(0),
m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL)
{ {
} }

View file

@ -18,6 +18,7 @@
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <memory> #include <memory>
#include <random>
#include "util.h" #include "util.h"
#include "Queue.h" #include "Queue.h"
#include "Crypto.h" #include "Crypto.h"
@ -244,6 +245,8 @@ namespace tunnel
uint32_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; }; uint32_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; };
int GetCongestionLevel() const { return m_MaxNumTransitTunnels ? CONGESTION_LEVEL_FULL * m_TransitTunnels.size() / m_MaxNumTransitTunnels : CONGESTION_LEVEL_FULL; } int GetCongestionLevel() const { return m_MaxNumTransitTunnels ? CONGESTION_LEVEL_FULL * m_TransitTunnels.size() / m_MaxNumTransitTunnels : CONGESTION_LEVEL_FULL; }
std::mt19937& GetRng () { return m_Rng; };
private: private:
template<class TTunnel> template<class TTunnel>
@ -307,6 +310,7 @@ namespace tunnel
int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations; int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations;
double m_TunnelCreationSuccessRate; double m_TunnelCreationSuccessRate;
int m_TunnelCreationAttemptsNum; int m_TunnelCreationAttemptsNum;
std::mt19937 m_Rng;
public: public: