From e10ca637da74b6d0db7470ec8c52c74fff604f2c Mon Sep 17 00:00:00 2001
From: orignal <i2porignal@yandex.ru>
Date: Fri, 22 Apr 2022 15:03:49 -0400
Subject: [PATCH] handle RelayIntro

---
 libi2pd/SSU2.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++----
 libi2pd/SSU2.h   |  4 +++-
 2 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp
index fbec0a5b..d33592c1 100644
--- a/libi2pd/SSU2.cpp
+++ b/libi2pd/SSU2.cpp
@@ -853,6 +853,8 @@ namespace transport
 					}	
 				break;	
 				case eSSU2BlkRelayTag:
+					LogPrint (eLogDebug, "SSU2: RelayTag");
+					m_RelayTag = bufbe32toh (buf + offset);
 				break;	
 				case eSSU2BlkNewToken:
 				{
@@ -1026,8 +1028,8 @@ namespace transport
 		s.Insert (session->GetRemoteIdentity ()->GetIdentHash (), 32); // chash
 		s.Insert (buf + 1, 14); // nonce, relay tag, timestamp, ver, asz
 		uint8_t asz = buf[14];
-		s.Insert (buf + 15, asz + 2); // Alice IP, Alice Port
-		if (!s.Verify (GetRemoteIdentity (), buf + 17 + asz))
+		s.Insert (buf + 15, asz); // Alice Port, Alice IP
+		if (!s.Verify (GetRemoteIdentity (), buf + 15 + asz))
 		{
 			LogPrint (eLogWarning, "SSU2: RelayRequest signature verification failed");
 			return; // TODO: send relay response
@@ -1039,6 +1041,29 @@ namespace transport
 		payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MTU - payloadSize);
 		session->SendData (payload, payloadSize);
 	}	
+
+	void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len)
+	{
+		// we are Charlie
+		SignedData s;
+		s.Insert ((const uint8_t *)"RelayRequestData", 16); // prologue
+		s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
+		s.Insert (i2p::context.GetIdentHash (), 32); // chash
+		s.Insert (buf + 33, 14); // nonce, relay tag, timestamp, ver, asz
+		uint8_t asz = buf[46];
+		s.Insert (buf + 47, asz); // Alice Port, Alice IP 
+		if (!s.Verify (GetRemoteIdentity (), buf + 47 + asz))
+		{
+			LogPrint (eLogWarning, "SSU2: RelayIntro signature verification failed");
+			return; // TODO: send relay response
+		}	
+
+		// TODO: send RelayResponse to Bob
+		
+		boost::asio::ip::udp::endpoint ep;
+		if (ExtractEndpoint (buf + 47, asz, ep))
+			m_Server.SendHolePunch (ep);
+	}	
 		
 	bool SSU2Session::ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep)
 	{
@@ -1580,7 +1605,10 @@ namespace transport
 			m_SocketV6.send_to (bufs, to, 0, ec);
 		else	
 			m_SocketV4.send_to (bufs, to, 0, ec);
-		i2p::transport::transports.UpdateSentBytes (headerLen + payloadLen);
+		if (!ec)	
+			i2p::transport::transports.UpdateSentBytes (headerLen + payloadLen);
+		else
+			LogPrint (eLogError, "SSU2: Send exception: ", ec.message (), " to ", to);
 	}	
 		
 	void SSU2Server::Send (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, 
@@ -1597,9 +1625,25 @@ namespace transport
 			m_SocketV6.send_to (bufs, to, 0, ec);
 		else	
 			m_SocketV4.send_to (bufs, to, 0, ec);
-		i2p::transport::transports.UpdateSentBytes (headerLen + headerXLen + payloadLen);
+		
+		if (!ec)
+			i2p::transport::transports.UpdateSentBytes (headerLen + headerXLen + payloadLen);
+		else	
+			LogPrint (eLogError, "SSU2: Send exception: ", ec.message (), " to ", to);
 	}	
 
+	void SSU2Server::SendHolePunch (const boost::asio::ip::udp::endpoint& to)
+	{
+		boost::system::error_code ec;
+		if (to.address ().is_v6 ())
+			m_SocketV6.send_to (boost::asio::buffer ((uint8_t *)nullptr, 0), to, 0, ec);
+		else	
+			m_SocketV4.send_to (boost::asio::buffer ((uint8_t *)nullptr, 0), to, 0, ec);
+
+		if (ec)
+			LogPrint (eLogError, "SSU2: Send exception: ", ec.message (), " to ", to);
+	}	
+		
 	bool SSU2Server::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
 		std::shared_ptr<const i2p::data::RouterInfo::Address> address)
 	{
diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h
index b70b1ebe..1bd930f6 100644
--- a/libi2pd/SSU2.h
+++ b/libi2pd/SSU2.h
@@ -186,6 +186,7 @@ namespace transport
 			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);
 			
 			size_t CreateAddressBlock (const boost::asio::ip::udp::endpoint& ep, uint8_t * buf, size_t len);
 			size_t CreateAckBlock (uint8_t * buf, size_t len);
@@ -257,7 +258,8 @@ namespace transport
 				const boost::asio::ip::udp::endpoint& to);
 			void 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);
-
+			void SendHolePunch (const boost::asio::ip::udp::endpoint& to);
+			
 			bool CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
 				std::shared_ptr<const i2p::data::RouterInfo::Address> address);