/ libi2pd_client / I2PTunnel.cpp
I2PTunnel.cpp
  1  /*
  2  * Copyright (c) 2013-2025, The PurpleI2P Project
  3  *
  4  * This file is part of Purple i2pd project and licensed under BSD3
  5  *
  6  * See full license text in LICENSE file at top of project tree
  7  */
  8  
  9  #include <cassert>
 10  #include <boost/algorithm/string.hpp>
 11  #include "Base.h"
 12  #include "Log.h"
 13  #include "Destination.h"
 14  #include "ClientContext.h"
 15  #include "I2PTunnel.h"
 16  #include "util.h"
 17  
 18  namespace i2p
 19  {
 20  namespace client
 21  {
 22  
 23  	/** set standard socket options */
 24  	static void I2PTunnelSetSocketOptions (std::shared_ptr<boost::asio::ip::tcp::socket> socket)
 25  	{
 26  		if (socket && socket->is_open())
 27  		{
 28  			boost::asio::socket_base::receive_buffer_size option(I2P_TUNNEL_CONNECTION_BUFFER_SIZE);
 29  			socket->set_option(option);
 30  		}
 31  	}
 32  
 33  	I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
 34  		std::shared_ptr<const i2p::data::LeaseSet> leaseSet, uint16_t port):
 35  		I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()),
 36  		m_IsReceiving (false)
 37  	{
 38  		m_Stream = GetOwner()->GetLocalDestination ()->CreateStream (leaseSet, port);
 39  	}
 40  
 41  	I2PTunnelConnection::I2PTunnelConnection (I2PService * owner,
 42  		std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<i2p::stream::Stream> stream):
 43  		I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream),
 44  		m_RemoteEndpoint (socket->remote_endpoint ()), m_IsReceiving (false)
 45  	{
 46  	}
 47  
 48  	I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
 49  		const boost::asio::ip::tcp::endpoint& target,std::shared_ptr<boost::asio::ssl::context> sslCtx):
 50  		I2PServiceHandler(owner), m_Stream (stream), m_RemoteEndpoint (target), m_IsReceiving (false)
 51  	{
 52  		m_Socket = std::make_shared<boost::asio::ip::tcp::socket> (owner->GetService ());
 53  		if (sslCtx)
 54  			m_SSL = std::make_shared<boost::asio::ssl::stream<boost::asio::ip::tcp::socket&> > (*m_Socket, *sslCtx);
 55  	}
 56  
 57  	I2PTunnelConnection::~I2PTunnelConnection ()
 58  	{
 59  	}
 60  
 61  	void I2PTunnelConnection::I2PConnect (const uint8_t * msg, size_t len)
 62  	{
 63  		if (m_Stream)
 64  		{
 65  			if (msg)
 66  				m_Stream->Send (msg, len); // connect and send
 67  			else
 68  				m_Stream->Send (m_Buffer, 0); // connect
 69  		}
 70  		StreamReceive ();
 71  		Receive ();
 72  	}
 73  
 74  	boost::asio::ip::address GetLoopbackAddressFor(const i2p::data::IdentHash & addr)
 75  	{
 76  		boost::asio::ip::address_v4::bytes_type bytes;
 77  		const uint8_t * ident = addr;
 78  		bytes[0] = 127;
 79  		memcpy (bytes.data ()+1, ident, 3);
 80  		boost::asio::ip::address ourIP = boost::asio::ip::address_v4 (bytes);
 81  		return ourIP;
 82  	}
 83  
 84  	boost::asio::ip::address GetLoopbackAddress6For(const i2p::data::IdentHash & addr)
 85  	{
 86  		boost::asio::ip::address_v6::bytes_type bytes;
 87  		const uint8_t * ident = addr;
 88  		bytes[0] = 0xfd;
 89  		memcpy (bytes.data ()+1, ident, 15);
 90  		boost::asio::ip::address ourIP = boost::asio::ip::address_v6 (bytes);
 91  		return ourIP;
 92  	}
 93  		
 94  #ifdef __linux__
 95  	static void MapToLoopback(std::shared_ptr<boost::asio::ip::tcp::socket> sock, const i2p::data::IdentHash & addr, bool isV4)
 96  	{
 97  		if (sock)
 98  		{
 99  			// bind to 127.x.x.x address for ipv4
100  			// where x.x.x are first three bytes from ident
101  			// bind to fdxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx address for ipv6
102  			// where xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx are first 15 bytes from ident
103  			auto ourIP = isV4 ? GetLoopbackAddressFor(addr) : GetLoopbackAddress6For(addr);
104  			boost::system::error_code ec;
105  			sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0), ec);
106  			if (ec)
107  				LogPrint (eLogError, "I2PTunnel: Can't bind ourIP to ", ourIP.to_string (), ": ", ec.message ());
108  		}
109  	}
110  #endif
111  
112  	void I2PTunnelConnection::Connect (bool isUniqueLocal)
113  	{
114  		if (m_Socket)
115  		{
116  			I2PTunnelSetSocketOptions (m_Socket);
117  #ifdef __linux__
118  			if (isUniqueLocal && m_RemoteEndpoint.address ().is_loopback ())
119  			{	
120  				auto ident = m_Stream->GetRemoteIdentity()->GetIdentHash();
121  				if (m_RemoteEndpoint.address ().is_v4 ())
122  				{
123  					m_Socket->open (boost::asio::ip::tcp::v4 ());
124  					MapToLoopback(m_Socket, ident, true);
125  				}
126  				else if (m_RemoteEndpoint.address ().is_v6 ())
127  				{
128  					m_Socket->open (boost::asio::ip::tcp::v6 ());
129  					MapToLoopback(m_Socket, ident, false);
130  				}	
131  			}
132  #endif
133  			m_Socket->async_connect (m_RemoteEndpoint, std::bind (&I2PTunnelConnection::HandleConnect,
134  				shared_from_this (), std::placeholders::_1));
135  		}
136  	}
137  
138  	void I2PTunnelConnection::Connect (const boost::asio::ip::address& localAddress)
139  	{
140  		if (m_Socket)
141  		{
142  			if (m_RemoteEndpoint.address().is_v6 ())
143  				m_Socket->open (boost::asio::ip::tcp::v6 ());
144  			else
145  				m_Socket->open (boost::asio::ip::tcp::v4 ());
146  			boost::system::error_code ec;
147  			m_Socket->bind (boost::asio::ip::tcp::endpoint (localAddress, 0), ec);
148  			if (ec)
149  				LogPrint (eLogError, "I2PTunnel: Can't bind to ", localAddress.to_string (), ": ", ec.message ());
150  		}
151  		Connect (false);
152  	}
153  
154  	void I2PTunnelConnection::Terminate ()
155  	{
156  		if (Kill()) return;
157  		if (m_SSL) m_SSL = nullptr;
158  		if (m_Stream)
159  		{
160  			m_Stream->Close ();
161  			m_Stream.reset ();
162  		}
163  		boost::system::error_code ec;
164  		m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); // avoid RST
165  		m_Socket->close ();
166  
167  		Done(shared_from_this ());
168  	}
169  
170  	void I2PTunnelConnection::Receive ()
171  	{
172  		if (m_IsReceiving) return; // already receiving
173  		size_t bufSize = I2P_TUNNEL_CONNECTION_BUFFER_SIZE;
174  		size_t unsentSize = m_Stream ? m_Stream->GetSendBufferSize () : 0;
175  		if (unsentSize)
176  		{	
177  			if (unsentSize >= I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE) return; // buffer is full
178  			if (unsentSize > I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE - I2P_TUNNEL_CONNECTION_BUFFER_SIZE)
179  				bufSize = I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE - unsentSize;
180  		}	
181  		m_IsReceiving = true;
182  		if (m_SSL)
183  			m_SSL->async_read_some (boost::asio::buffer(m_Buffer, bufSize),
184  				std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (),
185  				std::placeholders::_1, std::placeholders::_2));
186  		else
187  			m_Socket->async_read_some (boost::asio::buffer(m_Buffer, bufSize),
188  				std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (),
189  				std::placeholders::_1, std::placeholders::_2));
190  	}
191  
192  	void I2PTunnelConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
193  	{
194  		m_IsReceiving = false;
195  		if (ecode)
196  		{
197  			if (ecode != boost::asio::error::operation_aborted)
198  			{
199  				LogPrint (eLogError, "I2PTunnel: Read error: ", ecode.message ());
200  				Terminate ();
201  			}
202  		}
203  		else
204  		{	
205  			if (bytes_transferred < I2P_TUNNEL_CONNECTION_BUFFER_SIZE && !m_SSL)
206  			{
207  				boost::system::error_code ec;
208  				size_t moreBytes = m_Socket->available(ec);
209  				if (!ec && moreBytes && m_Stream)
210  				{
211  					// read more data from socket before sending to stream
212  					if (bytes_transferred + moreBytes > I2P_TUNNEL_CONNECTION_BUFFER_SIZE)
213  						moreBytes = I2P_TUNNEL_CONNECTION_BUFFER_SIZE - bytes_transferred;
214  					if (m_Stream->GetSendBufferSize () < I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE)
215  					{	
216  						size_t remaining = I2P_TUNNEL_CONNECTION_STREAM_MAX_SEND_BUFFER_SIZE - m_Stream->GetSendBufferSize ();
217  						if (remaining < moreBytes) moreBytes = remaining;
218  					}		
219  					else
220  						moreBytes = 0;
221  				}	
222  				if (moreBytes)
223  				{
224  					moreBytes = boost::asio::read (*m_Socket, boost::asio::buffer(m_Buffer + bytes_transferred, moreBytes), boost::asio::transfer_all (), ec);
225  					if (!ec) bytes_transferred += moreBytes;
226  				}	
227  			}	
228  			WriteToStream (m_Buffer, bytes_transferred);
229  			Receive (); // try to receive more while being sent to stream
230  		}	
231  	}
232  
233  	void I2PTunnelConnection::WriteToStream (const uint8_t * buf, size_t len)
234  	{
235  		if (m_Stream)
236  		{
237  			m_Stream->AsyncSend (buf, len,
238  				[s = shared_from_this ()](const boost::system::error_code& ecode)
239  				{
240  					if (!ecode)
241  						s->Receive ();
242  					else
243  						s->Terminate ();
244  				});
245  			}
246  	}
247  
248  	void I2PTunnelConnection::HandleWrite (const boost::system::error_code& ecode)
249  	{
250  		if (ecode)
251  		{
252  			LogPrint (eLogError, "I2PTunnel: Write error: ", ecode.message ());
253  			if (ecode != boost::asio::error::operation_aborted)
254  				Terminate ();
255  		}
256  		else
257  			StreamReceive ();
258  	}
259  
260  	void I2PTunnelConnection::StreamReceive ()
261  	{
262  		if (m_Stream)
263  		{
264  			if (m_Stream->GetStatus () == i2p::stream::eStreamStatusNew ||
265  				m_Stream->GetStatus () == i2p::stream::eStreamStatusOpen) // regular
266  			{
267  				m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_STREAM_BUFFER_SIZE),
268  					std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (),
269  					std::placeholders::_1, std::placeholders::_2),
270  					I2P_TUNNEL_CONNECTION_MAX_IDLE);
271  			}
272  			else // closed by peer
273  			{
274  				// get remaining data
275  				auto len = m_Stream->ReadSome (m_StreamBuffer, I2P_TUNNEL_CONNECTION_STREAM_BUFFER_SIZE);
276  				if (len > 0) // still some data
277  					Write (m_StreamBuffer, len);
278  				else // no more data
279  					Terminate ();
280  			}
281  		}
282  	}
283  
284  	void I2PTunnelConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
285  	{
286  		if (ecode)
287  		{
288  			if (ecode != boost::asio::error::operation_aborted)
289  			{
290  				LogPrint (eLogError, "I2PTunnel: Stream read error: ", ecode.message ());
291  				if (bytes_transferred > 0)
292  					Write (m_StreamBuffer, bytes_transferred); // postpone termination
293  				else if (ecode == boost::asio::error::timed_out && m_Stream && m_Stream->IsOpen ())
294  					StreamReceive ();
295  				else
296  					Terminate ();
297  			}
298  			else
299  				Terminate ();
300  		}
301  		else
302  			Write (m_StreamBuffer, bytes_transferred);
303  	}
304  
305  	void I2PTunnelConnection::Write (const uint8_t * buf, size_t len)
306  	{
307  		if (m_SSL)
308  			boost::asio::async_write (*m_SSL, boost::asio::buffer (buf, len), boost::asio::transfer_all (),
309  				std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
310  		else
311  			boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (),
312  				std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
313  	}
314  
315  	void I2PTunnelConnection::HandleConnect (const boost::system::error_code& ecode)
316  	{
317  		if (ecode)
318  		{
319  			LogPrint (eLogError, "I2PTunnel: Connect error: ", ecode.message ());
320  			Terminate ();
321  		}
322  		else
323  		{
324  			LogPrint (eLogDebug, "I2PTunnel: Connected");
325  			if (m_SSL)
326  				m_SSL->async_handshake (boost::asio::ssl::stream_base::client,
327  					std::bind (&I2PTunnelConnection::HandleHandshake, shared_from_this (), std::placeholders::_1));
328  			else
329  				Established ();
330  		}
331  	}
332  
333  	void I2PTunnelConnection::HandleHandshake (const boost::system::error_code& ecode)
334  	{
335  		if (ecode)
336  		{
337  			LogPrint (eLogError, "I2PTunnel: Handshake error: ", ecode.message ());
338  			Terminate ();
339  		}
340  		else
341  		{
342  			LogPrint (eLogDebug, "I2PTunnel: SSL connected");
343  			Established ();
344  		}
345  	}
346  
347  	void I2PTunnelConnection::Established ()
348  	{
349  		StreamReceive ();
350  		Receive ();
351  	}
352  
353  	void I2PClientTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len)
354  	{
355  		if (m_HeaderSent)
356  			I2PTunnelConnection::Write (buf, len);
357  		else
358  		{
359  			m_InHeader.clear ();
360  			m_InHeader.write ((const char *)buf, len);
361  			std::string line;
362  			bool endOfHeader = false;
363  			while (!endOfHeader)
364  			{
365  				std::getline(m_InHeader, line);
366  				if (!m_InHeader.fail ())
367  				{
368  					if (line == "\r") endOfHeader = true;
369  					else
370  					{
371  						if (!m_ConnectionSent && !line.compare(0, 10, "Connection"))
372  						{
373  							/* close connection, if not Connection: (U|u)pgrade (for websocket) */
374  							auto x = line.find("pgrade");
375  							if (x != std::string::npos && std::tolower(line[x - 1]) == 'u')
376  								m_OutHeader << line << "\r\n";
377  							else
378  								m_OutHeader << "Connection: close\r\n";
379  
380  							m_ConnectionSent = true;
381  						}
382  						else if (!m_ProxyConnectionSent && !line.compare(0, 16, "Proxy-Connection"))
383  						{
384  							m_OutHeader << "Proxy-Connection: close\r\n";
385  							m_ProxyConnectionSent = true;
386  						}
387  						else
388  						m_OutHeader << line << "\n";
389  					}
390  				}
391  				else
392  				{
393  					// insert incomplete line back
394  					m_InHeader.clear ();
395  					m_InHeader << line;
396  					break;
397  				}
398  			}
399  
400  			if (endOfHeader)
401  			{
402  				if (!m_ConnectionSent) m_OutHeader << "Connection: close\r\n";
403  				if (!m_ProxyConnectionSent) m_OutHeader << "Proxy-Connection: close\r\n";
404  				m_OutHeader << "\r\n"; // end of header
405  				m_OutHeader << m_InHeader.str ().substr (m_InHeader.tellg ()); // data right after header
406  				m_InHeader.str ("");
407  				m_HeaderSent = true;
408  				I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
409  			}
410  			else if (m_OutHeader.tellp () < I2P_TUNNEL_HTTP_MAX_HEADER_SIZE)
411  				StreamReceive (); // read more header
412  			else
413  			{
414  				LogPrint (eLogError, "I2PTunnel: HTTP header exceeds max size ", I2P_TUNNEL_HTTP_MAX_HEADER_SIZE);
415  				Terminate ();
416  			}
417  		}
418  	}
419  
420  	I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
421  		const boost::asio::ip::tcp::endpoint& target, const std::string& host, const std::string& XI2P,
422  	    std::shared_ptr<boost::asio::ssl::context> sslCtx):
423  		I2PTunnelConnection (owner, stream, target, sslCtx), m_Host (host), m_XI2P (XI2P),
424  		m_HeaderSent (false), m_ResponseHeaderSent (false)
425  	{
426  		if (sslCtx)
427  			SSL_set_tlsext_host_name(GetSSL ()->native_handle(), host.c_str ());
428  	}
429  
430  	void I2PServerTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len)
431  	{
432  		if (m_HeaderSent)
433  			I2PTunnelConnection::Write (buf, len);
434  		else
435  		{
436  			m_InHeader.clear ();
437  			m_InHeader.write ((const char *)buf, len);
438  			std::string line;
439  			bool endOfHeader = false, connection = false;
440  			while (!endOfHeader)
441  			{
442  				std::getline(m_InHeader, line);
443  				if (m_InHeader.fail ()) break;
444  				if (!m_InHeader.eof ())
445  				{
446  					if (line == "\r") endOfHeader = true;
447  					else
448  					{
449  						// strip up some headers
450  						static constexpr std::array<std::string_view, 2> excluded // list of excluded headers
451  						{
452  							"Keep-Alive:", "X-I2P"
453  						};
454  						bool matched = false;
455  						for (const auto& it: excluded)
456  							if (boost::iequals (line.substr (0, it.length ()), it))
457  							{
458  								matched = true;
459  								break;
460  							}
461  						if (matched) continue;
462  
463  						// replace some headers
464  						if (!m_Host.empty () && boost::iequals (line.substr (0, 5), "Host:"))
465  							m_OutHeader << "Host: " << m_Host << "\r\n"; // override host
466  						else if (boost::iequals (line.substr (0, 11), "Connection:"))
467  						{
468  							auto x = line.find("pgrade");
469  							if (x != std::string::npos && x && std::tolower(line[x - 1]) != 'u') // upgrade or Upgrade
470  								m_OutHeader << line << "\n";
471  							else
472  								m_OutHeader << "Connection: close\r\n";
473  							connection = true;
474  						}
475  						else // forward as is
476  							m_OutHeader << line << "\n";
477  					}
478  				}
479  				else
480  				{
481  					// insert incomplete line back
482  					m_InHeader.clear ();
483  					m_InHeader << line;
484  					break;
485  				}
486  			}
487  
488  			if (endOfHeader)
489  			{
490  				// add Connection if not presented
491  				if (!connection)
492  					m_OutHeader << "Connection: close\r\n";
493  				// add X-I2P fields
494  				m_OutHeader << m_XI2P;
495  				// end of header
496  				m_OutHeader << "\r\n"; 
497  				
498  				m_OutHeader << m_InHeader.str ().substr (m_InHeader.tellg ()); // data right after header
499  				m_InHeader.str ("");
500  				m_HeaderSent = true;
501  				I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
502  			}
503  			else if (m_OutHeader.tellp () < I2P_TUNNEL_HTTP_MAX_HEADER_SIZE)
504  				StreamReceive (); // read more header
505  			else
506  			{
507  				LogPrint (eLogError, "I2PTunnel: HTTP header exceeds max size ", I2P_TUNNEL_HTTP_MAX_HEADER_SIZE);
508  				Terminate ();
509  			}
510  		}
511  	}
512  
513  	void I2PServerTunnelConnectionHTTP::WriteToStream (const uint8_t * buf, size_t len)
514  	{
515  		if (m_ResponseHeaderSent)
516  			I2PTunnelConnection::WriteToStream (buf, len);
517  		else
518  		{
519  			m_InHeader.clear ();
520  			if (m_InHeader.str ().empty ()) m_OutHeader.str (""); // start of response
521  			m_InHeader.write ((const char *)buf, len);
522  			std::string line;
523  			bool endOfHeader = false;
524  			while (!endOfHeader)
525  			{
526  				std::getline(m_InHeader, line);
527  				if (m_InHeader.fail ()) break;
528  				if (!m_InHeader.eof ())
529  				{
530  					if (line == "\r") endOfHeader = true;
531  					else
532  					{
533  						static constexpr std::array<std::string_view, 5> excluded // list of excluded headers
534  						{
535  							"Server:", "Date:", "X-Runtime:", "X-Powered-By:", "Proxy"
536  						};
537  						bool matched = false;
538  						for (const auto& it: excluded)
539  							if (!line.compare(0, it.length (), it))
540  							{
541  								matched = true;
542  								break;
543  							}
544  						if (!matched)
545  							m_OutHeader << line << "\n";
546  					}
547  				}
548  				else
549  				{
550  					// insert incomplete line back
551  					m_InHeader.clear ();
552  					m_InHeader << line;
553  					break;
554  				}
555  			}
556  
557  			if (endOfHeader)
558  			{
559  				m_OutHeader << "\r\n"; // end of header
560  				m_OutHeader << m_InHeader.str ().substr (m_InHeader.tellg ()); // data right after header
561  				m_InHeader.str ("");
562  				m_ResponseHeaderSent = true;
563  				I2PTunnelConnection::WriteToStream ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
564  				m_OutHeader.str ("");
565  			}
566  			else
567  				Receive ();
568  		}
569  	}
570  
571  	I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
572  		const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass,
573  	    std::shared_ptr<boost::asio::ssl::context> sslCtx):
574  		I2PTunnelConnection (owner, stream, target, sslCtx), m_From (stream->GetRemoteIdentity ()),
575  		m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass)
576  	{
577  	}
578  
579  	void I2PTunnelConnectionIRC::Write (const uint8_t * buf, size_t len)
580  	{
581  		m_OutPacket.str ("");
582  		if (m_NeedsWebIrc)
583  		{
584  			m_NeedsWebIrc = false;
585  			m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ())
586  				<< " " << GetSocket ()->local_endpoint ().address () << std::endl;
587  		}
588  
589  		m_InPacket.clear ();
590  		m_InPacket.write ((const char *)buf, len);
591  
592  		while (!m_InPacket.eof () && !m_InPacket.fail ())
593  		{
594  			std::string line;
595  			std::getline (m_InPacket, line);
596  			if (line.length () == 0 && m_InPacket.eof ())
597  				m_InPacket.str ("");
598  			auto pos = line.find ("USER");
599  			if (!pos) // start of line
600  			{
601  				pos = line.find (" ");
602  				pos++;
603  				pos = line.find (" ", pos);
604  				pos++;
605  				auto nextpos = line.find (" ", pos);
606  				m_OutPacket << line.substr (0, pos);
607  				m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ());
608  				m_OutPacket << line.substr (nextpos) << '\n';
609  			}
610  			else
611  				m_OutPacket << line << '\n';
612  		}
613  		I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ());
614  	}
615  
616  
617  	/* This handler tries to establish a connection with the desired server and dies if it fails to do so */
618  	class I2PClientTunnelHandler: public I2PServiceHandler, public std::enable_shared_from_this<I2PClientTunnelHandler>
619  	{
620  		public:
621  			I2PClientTunnelHandler (I2PClientTunnel * parent, std::shared_ptr<const Address> address,
622  				uint16_t destinationPort, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
623  				I2PServiceHandler(parent), m_Address(address),
624  				m_DestinationPort (destinationPort), m_Socket(socket) {};
625  			void Handle();
626  			void Terminate();
627  		private:
628  			void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
629  			std::shared_ptr<const Address> m_Address;
630  			uint16_t m_DestinationPort;
631  			std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
632  	};
633  
634  	void I2PClientTunnelHandler::Handle()
635  	{
636  		GetOwner()->CreateStream (
637  			std::bind (&I2PClientTunnelHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1),
638  			m_Address, m_DestinationPort);
639  	}
640  
641  	void I2PClientTunnelHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
642  	{
643  		if (stream)
644  		{
645  			if (Kill()) return;
646  			LogPrint (eLogDebug, "I2PTunnel: New connection");
647  			auto connection = std::make_shared<I2PTunnelConnection>(GetOwner(), m_Socket, stream);
648  			GetOwner()->AddHandler (connection);
649  			connection->I2PConnect ();
650  			Done(shared_from_this());
651  		}
652  		else
653  		{
654  			LogPrint (eLogError, "I2PTunnel: Client Tunnel Issue when creating the stream, check the previous warnings for more info.");
655  			Terminate();
656  		}
657  	}
658  
659  	void I2PClientTunnelHandler::Terminate()
660  	{
661  		if (Kill()) return;
662  		if (m_Socket)
663  		{
664  			m_Socket->close();
665  			m_Socket = nullptr;
666  		}
667  		Done(shared_from_this());
668  	}
669  
670  	I2PClientTunnel::I2PClientTunnel (const std::string& name, const std::string& destination,
671  		const std::string& address, uint16_t port, std::shared_ptr<ClientDestination> localDestination, uint16_t destinationPort):
672  		TCPIPAcceptor (address, port, localDestination), m_Name (name), m_Destination (destination),
673  		m_DestinationPort (destinationPort), m_KeepAliveInterval (0)
674  	{
675  	}
676  
677  	void I2PClientTunnel::Start ()
678  	{
679  		TCPIPAcceptor::Start ();
680  		GetAddress ();
681  		if (m_KeepAliveInterval)
682  			ScheduleKeepAliveTimer ();
683  	}
684  
685  	void I2PClientTunnel::Stop ()
686  	{
687  		TCPIPAcceptor::Stop();
688  		m_Address = nullptr;
689  		if (m_KeepAliveTimer) m_KeepAliveTimer->cancel ();
690  	}
691  
692  	void I2PClientTunnel::SetKeepAliveInterval (uint32_t keepAliveInterval)
693  	{
694  		m_KeepAliveInterval = keepAliveInterval;
695  		if (m_KeepAliveInterval)
696  			m_KeepAliveTimer.reset (new boost::asio::deadline_timer (GetLocalDestination ()->GetService ()));
697  	}
698  
699  	/* HACK: maybe we should create a caching IdentHash provider in AddressBook */
700  	std::shared_ptr<const Address> I2PClientTunnel::GetAddress ()
701  	{
702  		if (!m_Address)
703  		{
704  			m_Address = i2p::client::context.GetAddressBook ().GetAddress (m_Destination);
705  			if (!m_Address)
706  				LogPrint (eLogWarning, "I2PTunnel: Remote destination ", m_Destination, " not found");
707  		}
708  		return m_Address;
709  	}
710  
711  	std::shared_ptr<I2PServiceHandler> I2PClientTunnel::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
712  	{
713  		auto address = GetAddress ();
714  		if (address)
715  			return std::make_shared<I2PClientTunnelHandler>(this, address, m_DestinationPort, socket);
716  		else
717  			return nullptr;
718  	}
719  
720  	void I2PClientTunnel::ScheduleKeepAliveTimer ()
721  	{
722  		if (m_KeepAliveTimer)
723  		{
724  			m_KeepAliveTimer->expires_from_now (boost::posix_time::seconds (m_KeepAliveInterval));
725  			m_KeepAliveTimer->async_wait (std::bind (&I2PClientTunnel::HandleKeepAliveTimer,
726  				this, std::placeholders::_1));
727  		}
728  	}
729  
730  	void I2PClientTunnel::HandleKeepAliveTimer (const boost::system::error_code& ecode)
731  	{
732  		if (ecode != boost::asio::error::operation_aborted)
733  		{
734  			if (m_Address && m_Address->IsValid ())
735  			{
736  				if (m_Address->IsIdentHash ())
737  					GetLocalDestination ()->SendPing (m_Address->identHash);
738  				else
739  					GetLocalDestination ()->SendPing (m_Address->blindedPublicKey);
740  			}
741  			ScheduleKeepAliveTimer ();
742  		}
743  	}
744  
745  	I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address,
746  		uint16_t port, std::shared_ptr<ClientDestination> localDestination, uint16_t inport, bool gzip):
747  		I2PService (localDestination), m_IsUniqueLocal(true), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false)
748  	{
749  		m_PortDestination = localDestination->GetStreamingDestination (inport);
750  		if (!m_PortDestination) // default destination
751  			m_PortDestination = localDestination->CreateStreamingDestination (inport, gzip);
752  	}
753  
754  	void I2PServerTunnel::Start ()
755  	{
756  		m_Endpoint.port (m_Port);
757  		boost::system::error_code ec;
758  		auto addr = boost::asio::ip::make_address (m_Address, ec);
759  		if (!ec)
760  			m_Endpoint.address (addr);
761  		else
762  			Resolve (nullptr);
763  		Accept ();
764  	}
765  
766  	void I2PServerTunnel::Stop ()
767  	{
768  		if (m_PortDestination)
769  			m_PortDestination->ResetAcceptor ();
770  		auto localDestination = GetLocalDestination ();
771  		if (localDestination)
772  			localDestination->StopAcceptingStreams ();
773  		if (m_Resolver)	
774  			m_Resolver->cancel ();
775  		
776  		ClearHandlers ();
777  	}
778  
779  	bool I2PServerTunnel::Resolve (std::shared_ptr<i2p::stream::Stream> stream)
780  	{
781  		if (m_Resolver) return false; // already resolving
782  		m_Resolver = std::make_shared<boost::asio::ip::tcp::resolver>(GetService ());
783  		m_Resolver->async_resolve (m_Address, "",
784  			std::bind (&I2PServerTunnel::HandleResolve, this,
785  				std::placeholders::_1, std::placeholders::_2, stream));
786  		return true;
787  	}	
788  		
789  	void I2PServerTunnel::HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::results_type endpoints,
790  		std::shared_ptr<i2p::stream::Stream> stream)
791  	{
792  		m_Resolver = nullptr;
793  		if (!ecode)
794  		{
795  			bool found = false;
796  			boost::asio::ip::tcp::endpoint ep;
797  			if (m_LocalAddress)
798  			{
799  				for (const auto& it: endpoints)
800  				{
801  					ep = it;
802  					if (!ep.address ().is_unspecified ())
803  					{
804  						if (ep.address ().is_v4 ())
805  						{
806  							if (m_LocalAddress->is_v4 ()) found = true;
807  						}
808  						else if (ep.address ().is_v6 ())
809  						{
810  							if (i2p::util::net::IsYggdrasilAddress (ep.address ()))
811  							{
812  								if (i2p::util::net::IsYggdrasilAddress (*m_LocalAddress))
813  									found = true;
814  							}
815  							else if (m_LocalAddress->is_v6 ())
816  								found = true;
817  						}
818  					}
819  					if (found) break;
820  				}
821  			}
822  			else
823  			{
824  				found = true;
825  				ep = *endpoints.begin (); // first available
826  			}
827  			if (!found)
828  			{
829  				LogPrint (eLogError, "I2PTunnel: Unable to resolve ", m_Address, " to compatible address");
830  				return;
831  			}
832  
833  			auto addr = ep.address ();
834  			LogPrint (eLogInfo, "I2PTunnel: Server tunnel ", (*endpoints.begin ()).host_name (), " has been resolved to ", addr);
835  			m_Endpoint.address (addr);
836  			if (stream)
837  				Connect (stream);
838  		}
839  		else
840  			LogPrint (eLogError, "I2PTunnel: Unable to resolve server tunnel address ", m_Address, ": ", ecode.message ());
841  	}
842  
843  	void I2PServerTunnel::SetAccessList (const std::set<i2p::data::IdentHash>& accessList)
844  	{
845  		m_AccessList = accessList;
846  		m_IsAccessList = true;
847  	}
848  
849  	void I2PServerTunnel::SetLocalAddress (const std::string& localAddress)
850  	{
851  		boost::system::error_code ec;
852  		auto addr = boost::asio::ip::make_address(localAddress, ec);
853  		if (!ec)
854  			m_LocalAddress.reset (new boost::asio::ip::address (addr));
855  		else
856  			LogPrint (eLogError, "I2PTunnel: Can't set local address ", localAddress);
857  	}
858  
859  	void I2PServerTunnel::SetSSL (bool ssl)
860  	{
861  		if (ssl)
862  		{
863  			m_SSLCtx = std::make_shared<boost::asio::ssl::context> (boost::asio::ssl::context::sslv23);
864  			m_SSLCtx->set_verify_mode(boost::asio::ssl::context::verify_none);
865  		}
866  		else
867  			m_SSLCtx = nullptr;
868  	}
869  
870  	void I2PServerTunnel::Accept ()
871  	{
872  		if (m_PortDestination)
873  			m_PortDestination->SetAcceptor (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
874  
875  		auto localDestination = GetLocalDestination ();
876  		if (localDestination)
877  		{
878  			if (!localDestination->IsAcceptingStreams ()) // set it as default if not set yet
879  				localDestination->AcceptStreams (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
880  		}
881  		else
882  			LogPrint (eLogError, "I2PTunnel: Local destination not set for server tunnel");
883  	}
884  
885  	void I2PServerTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
886  	{
887  		if (stream)
888  		{
889  			if (m_IsAccessList)
890  			{
891  				if (!m_AccessList.count (stream->GetRemoteIdentity ()->GetIdentHash ()))
892  				{
893  					LogPrint (eLogWarning, "I2PTunnel: Address ", stream->GetRemoteIdentity ()->GetIdentHash ().ToBase32 (), " is not in white list. Incoming connection dropped");
894  					stream->Close ();
895  					return;
896  				}
897  			}
898  			if (!m_Endpoint.address ().is_unspecified ())
899  				Connect (stream);
900  			else if (!Resolve (stream))
901  			{
902  				LogPrint (eLogWarning, "I2PTunnel: Address ", m_Address, " can't be resolved. Incoming connection dropped");
903  				stream->Close ();
904  				return;
905  			}	
906  		}
907  	}
908  
909  	void I2PServerTunnel::Connect (std::shared_ptr<i2p::stream::Stream> stream)
910  	{
911  		// new connection
912  		auto conn = CreateI2PConnection (stream);
913  		AddHandler (conn);
914  		if (m_LocalAddress)
915  			conn->Connect (*m_LocalAddress);
916  		else
917  			conn->Connect (m_IsUniqueLocal);
918  	}	
919  		
920  	std::shared_ptr<I2PTunnelConnection> I2PServerTunnel::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
921  	{
922  		return std::make_shared<I2PTunnelConnection> (this, stream, GetEndpoint (), m_SSLCtx);
923  
924  	}
925  
926  	I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& name, const std::string& address,
927  		uint16_t port, std::shared_ptr<ClientDestination> localDestination,
928  		const std::string& host, uint16_t inport, bool gzip, bool i2pheaders):
929  		I2PServerTunnel (name, address, port, localDestination, inport, gzip),
930  		m_Host (host), m_I2PHeaders (i2pheaders)
931  	{
932  	}
933  
934  	std::shared_ptr<I2PTunnelConnection> I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
935  	{
936  		if (m_I2PHeaders && (m_XI2P.empty () || stream->GetRemoteIdentity () != m_From.lock ()))
937  		{
938  			auto from = stream->GetRemoteIdentity ();
939  			m_From = from;
940  			std::stringstream ss;
941  			ss << X_I2P_DEST_B32 << ": " << context.GetAddressBook ().ToAddress(from->GetIdentHash ()) << "\r\n";
942  			ss << X_I2P_DEST_HASH << ": " << from->GetIdentHash ().ToBase64 () << "\r\n";
943  			ss << X_I2P_DEST_B64 << ": " << from->ToBase64 () << "\r\n";
944  			m_XI2P = ss.str ();
945  		}	
946  		return std::make_shared<I2PServerTunnelConnectionHTTP> (this, stream, GetEndpoint (), m_Host, m_XI2P, GetSSLCtx ());
947  	}
948  
949  	I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address,
950  		uint16_t port, std::shared_ptr<ClientDestination> localDestination,
951  		const std::string& webircpass, uint16_t inport, bool gzip):
952  		I2PServerTunnel (name, address, port, localDestination, inport, gzip),
953  		m_WebircPass (webircpass)
954  	{
955  	}
956  
957  	std::shared_ptr<I2PTunnelConnection> I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
958  	{
959  		return std::make_shared<I2PTunnelConnectionIRC> (this, stream, GetEndpoint (), m_WebircPass, GetSSLCtx ());
960  	}
961  }
962  }
963