From d33aeb4bb203aacfa05e6691a76f478c24725b25 Mon Sep 17 00:00:00 2001
From: orignal <i2porignal@yandex.ru>
Date: Thu, 21 Jul 2022 19:38:18 -0400
Subject: [PATCH] set unreachable if firewalled. Store router's hash of
 introducer instead session

---
 libi2pd/RouterContext.cpp |  6 ++++++
 libi2pd/RouterContext.h   |  1 +
 libi2pd/SSU2.cpp          | 44 ++++++++++++++++++++++++++++-----------
 libi2pd/SSU2.h            |  2 +-
 4 files changed, 40 insertions(+), 13 deletions(-)

diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp
index c9e4972c..1d5afc06 100644
--- a/libi2pd/RouterContext.cpp
+++ b/libi2pd/RouterContext.cpp
@@ -589,6 +589,12 @@ namespace i2p
 		}
 	}
 
+	void RouterContext::SetUnreachableSSU2 (bool v4, bool v6)
+	{
+		if (IsSSU2Only ())
+			SetUnreachable (v4, v6);
+	}	
+		
 	void RouterContext::SetUnreachable (bool v4, bool v6)
 	{
 		if (v4 || (v6 && !SupportsV4 ()))
diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h
index 6d575912..ad3514bf 100644
--- a/libi2pd/RouterContext.h
+++ b/libi2pd/RouterContext.h
@@ -127,6 +127,7 @@ namespace garlic
 			void RemoveSSU2Introducer (const i2p::data::IdentHash& h, 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);
diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp
index 52a38244..2a6058bc 100644
--- a/libi2pd/SSU2.cpp
+++ b/libi2pd/SSU2.cpp
@@ -761,25 +761,29 @@ namespace transport
 	void SSU2Server::UpdateIntroducers (bool v4)
 	{
 		uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
-		std::list<std::shared_ptr<SSU2Session>> newList;
+		std::list<i2p::data::IdentHash> newList;
 		auto& introducers = v4 ? m_Introducers : m_IntroducersV6;
 		std::set<i2p::data::IdentHash> excluded;
 		for (const auto& it : introducers)
 		{
-			if (it->IsEstablished ())
+			std::shared_ptr<SSU2Session> session;
+			auto it1 = m_SessionsByRouterHash.find (it);
+			if (it1 != m_SessionsByRouterHash.end ()) 
+				session = it1->second;
+			if (session && session->IsEstablished ())
 			{
-				if (ts < it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION)
-					it->SendKeepAlive ();
-				if (ts < it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
+				if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION)
+					session->SendKeepAlive ();
+				if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
 				{	
 					newList.push_back (it);
-					excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ());
+					excluded.insert (it);
 				}	
 				else
-					i2p::context.RemoveSSU2Introducer (it->GetRemoteIdentity ()->GetIdentHash (), it->GetAddress ()->IsV4 ());
+					session = nullptr;
 			}	
-			else
-				i2p::context.RemoveSSU2Introducer (it->GetRemoteIdentity ()->GetIdentHash (), it->GetAddress ()->IsV4 ());	
+			if (!session)
+				i2p::context.RemoveSSU2Introducer (it, v4);	
 		}	
 		if (newList.size () < SSU2_MAX_NUM_INTRODUCERS)
 		{
@@ -789,7 +793,11 @@ namespace transport
 				// bump creation time for previous introducers if no new sessions found
 				LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing");
 				for (auto& it : introducers)
-					it->SetCreationTime (it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION);
+				{	
+					auto it1 = m_SessionsByRouterHash.find (it);
+					if (it1 != m_SessionsByRouterHash.end ())
+						it1->second->SetCreationTime (it1->second->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION);
+				}	
 				// try again
 				excluded.clear ();
 				sessions = FindIntroducers (SSU2_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded);
@@ -802,9 +810,11 @@ namespace transport
 				introducer.iKey = it->GetRemoteIdentity ()->GetIdentHash ();
 				introducer.iExp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION;
 				excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ());
-				if (i2p::context.AddSSU2Introducer (introducer, it->GetAddress ()->IsV4 ()))
+				if (i2p::context.AddSSU2Introducer (introducer, v4))
 				{
-					newList.push_back (it);
+					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;
 				}	
 			}	
@@ -895,6 +905,11 @@ namespace transport
 					m_Introducers.clear ();
 					return;
 				}
+				// we are firewalled
+				auto addr = i2p::context.GetRouterInfo ().GetSSU2V4Address ();
+				if (addr && addr->ssu && addr->ssu->introducers.empty ())
+					i2p::context.SetUnreachableSSU2 (true, false); // v4
+				
 				UpdateIntroducers (true);
 				ScheduleIntroducersUpdateTimer ();
 			}
@@ -912,6 +927,11 @@ namespace transport
 					m_IntroducersV6.clear ();
 					return;
 				}
+				// we are firewalled
+				auto addr = i2p::context.GetRouterInfo ().GetSSU2V6Address ();
+				if (addr && addr->ssu && addr->ssu->introducers.empty ())
+					i2p::context.SetUnreachableSSU2 (false, true); // v6
+				
 				UpdateIntroducers (false);
 				ScheduleIntroducersUpdateTimerV6 ();
 			}	
diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h
index 5e0bba6b..b705f222 100644
--- a/libi2pd/SSU2.h
+++ b/libi2pd/SSU2.h
@@ -120,7 +120,7 @@ namespace transport
 			std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSU2Session> > m_PendingOutgoingSessions;
 			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<std::shared_ptr<SSU2Session> > m_Introducers, m_IntroducersV6; // introducers we are connected to
+			std::list<i2p::data::IdentHash> m_Introducers, m_IntroducersV6; // introducers we are connected to
 			i2p::util::MemoryPoolMt<Packet> m_PacketsPool;
 			boost::asio::deadline_timer m_TerminationTimer, m_ResendTimer,
 				m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6;