diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 33eff029..b191cbf1 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -169,6 +169,46 @@ namespace client return false; } + bool LeaseSetDestination::Reconfigure(std::map params) + { + + auto itr = params.find("i2cp.dontPublishLeaseSet"); + if (itr != params.end()) + { + m_IsPublic = itr->second != "true"; + } + + int inLen, outLen, inQuant, outQuant, numTags, minLatency, maxLatency; + std::map intOpts = { + {I2CP_PARAM_INBOUND_TUNNEL_LENGTH, inLen}, + {I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, outLen}, + {I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, inQuant}, + {I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, outQuant}, + {I2CP_PARAM_TAGS_TO_SEND, numTags}, + {I2CP_PARAM_MIN_TUNNEL_LATENCY, minLatency}, + {I2CP_PARAM_MAX_TUNNEL_LATENCY, maxLatency} + }; + + auto pool = GetTunnelPool(); + inLen = pool->GetNumInboundHops(); + outLen = pool->GetNumOutboundHops(); + inQuant = pool->GetNumInboundTunnels(); + outQuant = pool->GetNumOutboundTunnels(); + minLatency = 0; + maxLatency = 0; + + for (auto & opt : intOpts) + { + itr = params.find(opt.first); + if(itr != params.end()) + { + opt.second = std::stoi(itr->second); + } + } + pool->RequireLatency(minLatency, maxLatency); + return pool->Reconfigure(inLen, outLen, inQuant, outQuant); + } + std::shared_ptr LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident) { std::shared_ptr remoteLS; diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 6f37e768..3f261bc9 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -96,6 +96,10 @@ namespace client virtual bool Start (); virtual bool Stop (); + + /** i2cp reconfigure */ + virtual bool Reconfigure(std::map i2cpOpts); + bool IsRunning () const { return m_IsRunning; }; boost::asio::io_service& GetService () { return m_Service; }; std::shared_ptr GetTunnelPool () { return m_Pool; }; diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index e2c12b83..73abc1a7 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -670,10 +670,13 @@ namespace tunnel { if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) { - tunnel->SetIsRecreated (); auto pool = tunnel->GetTunnelPool (); - if (pool) + // let it die if the tunnel pool has been reconfigured and this is old + if (pool && tunnel->GetTunnelConfig()->GetNumHops() == pool->GetNumOutboundHops()) + { + tunnel->SetIsRecreated (); pool->RecreateOutboundTunnel (tunnel); + } } if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) tunnel->SetState (eTunnelStateExpiring); @@ -721,10 +724,13 @@ namespace tunnel { if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) { - tunnel->SetIsRecreated (); auto pool = tunnel->GetTunnelPool (); - if (pool) + // let it die if the tunnel pool was reconfigured and has different number of hops + if (pool && tunnel->GetTunnelConfig()->GetNumHops() == pool->GetNumInboundHops()) + { + tunnel->SetIsRecreated (); pool->RecreateInboundTunnel (tunnel); + } } if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 52736fa0..4f740a09 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -69,6 +69,18 @@ namespace tunnel m_Tests.clear (); } + bool TunnelPool::Reconfigure(int inHops, int outHops, int inQuant, int outQuant) { + if( inHops >= 0 && outHops >= 0 && inQuant > 0 && outQuant > 0) + { + m_NumInboundHops = inHops; + m_NumOutboundHops = outHops; + m_NumInboundTunnels = inQuant; + m_NumOutboundTunnels = outQuant; + return true; + } + return false; + } + void TunnelPool::TunnelCreated (std::shared_ptr createdTunnel) { if (!m_IsActive) return; @@ -479,11 +491,17 @@ namespace tunnel outboundTunnel = tunnels.GetNextOutboundTunnel (); LogPrint (eLogDebug, "Tunnels: Re-creating destination inbound tunnel..."); std::shared_ptr config; - if (m_NumInboundHops > 0) config = std::make_shared(tunnel->GetPeers ()); - auto newTunnel = tunnels.CreateInboundTunnel (config, outboundTunnel); - newTunnel->SetTunnelPool (shared_from_this()); - if (newTunnel->IsEstablished ()) // zero hops - TunnelCreated (newTunnel); + if (m_NumInboundHops > 0 && tunnel->GetPeers().size()) + { + config = std::make_shared(tunnel->GetPeers ()); + } + if (m_NumInboundHops == 0 || config) + { + auto newTunnel = tunnels.CreateInboundTunnel (config, outboundTunnel); + newTunnel->SetTunnelPool (shared_from_this()); + if (newTunnel->IsEstablished ()) // zero hops + TunnelCreated (newTunnel); + } } void TunnelPool::CreateOutboundTunnel () @@ -521,12 +539,17 @@ namespace tunnel { LogPrint (eLogDebug, "Tunnels: Re-creating destination outbound tunnel..."); std::shared_ptr config; - if (m_NumOutboundHops > 0) + if (m_NumOutboundHops > 0 && tunnel->GetPeers().size()) + { config = std::make_shared(tunnel->GetPeers (), inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ()); - auto newTunnel = tunnels.CreateOutboundTunnel (config); - newTunnel->SetTunnelPool (shared_from_this ()); - if (newTunnel->IsEstablished ()) // zero hops - TunnelCreated (newTunnel); + } + if(m_NumOutboundHops == 0 || config) + { + auto newTunnel = tunnels.CreateOutboundTunnel (config); + newTunnel->SetTunnelPool (shared_from_this ()); + if (newTunnel->IsEstablished ()) // zero hops + TunnelCreated (newTunnel); + } } else LogPrint (eLogDebug, "Tunnels: Can't re-create outbound tunnel, no inbound tunnels found"); diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index 07c3024e..fc46930c 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -78,7 +78,12 @@ namespace tunnel int GetNumInboundTunnels () const { return m_NumInboundTunnels; }; int GetNumOutboundTunnels () const { return m_NumOutboundTunnels; }; + int GetNumInboundHops() const { return m_NumInboundHops; }; + int GetNumOutboundHops() const { return m_NumOutboundHops; }; + /** i2cp reconfigure */ + bool Reconfigure(int inboundHops, int outboundHops, int inboundQuant, int outboundQuant); + void SetCustomPeerSelector(ITunnelPeerSelector * selector); void UnsetCustomPeerSelector(); bool HasCustomPeerSelector(); diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 371456ee..361d9f94 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -416,9 +416,60 @@ namespace client void I2CPSession::ReconfigureSessionMessageHandler (const uint8_t * buf, size_t len) { - // TODO: implement actual reconfiguration - SendSessionStatusMessage (2); // updated - } + uint8_t status = 3; // rejected + if(len > sizeof(uint16_t)) + { + uint16_t sessionID = bufbe16toh(buf); + if(sessionID == m_SessionID) + { + buf += sizeof(uint16_t); + const uint8_t * body = buf; + i2p::data::IdentityEx ident; + if(ident.FromBuffer(buf, len - sizeof(uint16_t))) + { + if (ident == *m_Destination->GetIdentity()) + { + size_t identsz = ident.GetFullLen(); + buf += identsz; + uint16_t optssize = bufbe16toh(buf); + if (optssize <= len - sizeof(uint16_t) - sizeof(uint64_t) - identsz - ident.GetSignatureLen() - sizeof(uint16_t)) + { + buf += sizeof(uint16_t); + std::map opts; + ExtractMapping(buf, optssize, opts); + buf += optssize; + //uint64_t date = bufbe64toh(buf); + buf += sizeof(uint64_t); + const uint8_t * sig = buf; + if(ident.Verify(body, len - sizeof(uint16_t) - ident.GetSignatureLen(), sig)) + { + if(m_Destination->Reconfigure(opts)) + { + LogPrint(eLogInfo, "I2CP: reconfigured destination"); + status = 2; // updated + } + else + LogPrint(eLogWarning, "I2CP: failed to reconfigure destination"); + } + else + LogPrint(eLogError, "I2CP: invalid reconfigure message signature"); + } + else + LogPrint(eLogError, "I2CP: mapping size missmatch"); + } + else + LogPrint(eLogError, "I2CP: destination missmatch"); + } + else + LogPrint(eLogError, "I2CP: malfromed destination"); + } + else + LogPrint(eLogError, "I2CP: session missmatch"); + } + else + LogPrint(eLogError, "I2CP: short message"); + SendSessionStatusMessage (status); + } void I2CPSession::SendSessionStatusMessage (uint8_t status) {