1 /*
2 * Copyright (c) 2013-2021, 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 
10 #include <openssl/rand.h>
11 #include <openssl/sha.h>
12 #include <openssl/hmac.h>
13 #include <stdlib.h>
14 #include <vector>
15 #include "Log.h"
16 #include "I2PEndian.h"
17 #include "Crypto.h"
18 #include "Siphash.h"
19 #include "RouterContext.h"
20 #include "Transports.h"
21 #include "NetDb.hpp"
22 #include "NTCP2.h"
23 #include "HTTP.h"
24 #include "util.h"
25 
26 #ifdef __linux__
27 	#include <linux/in6.h>
28 #endif
29 
30 namespace i2p
31 {
32 namespace transport
33 {
NTCP2Establisher()34 	NTCP2Establisher::NTCP2Establisher ():
35 		m_SessionConfirmedBuffer (nullptr)
36 	{
37 	}
38 
~NTCP2Establisher()39 	NTCP2Establisher::~NTCP2Establisher ()
40 	{
41 		delete[] m_SessionConfirmedBuffer;
42 	}
43 
KeyDerivationFunction1(const uint8_t * pub,i2p::crypto::X25519Keys & priv,const uint8_t * rs,const uint8_t * epub)44 	void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub)
45 	{
46 		i2p::crypto::InitNoiseXKState (*this, rs);
47 		// h = SHA256(h || epub)
48 		MixHash (epub, 32);
49 		// x25519 between pub and priv
50 		uint8_t inputKeyMaterial[32];
51 		priv.Agree (pub, inputKeyMaterial);
52 		MixKey (inputKeyMaterial);
53 	}
54 
KDF1Alice()55 	void NTCP2Establisher::KDF1Alice ()
56 	{
57 		KeyDerivationFunction1 (m_RemoteStaticKey, *m_EphemeralKeys, m_RemoteStaticKey, GetPub ());
58 	}
59 
KDF1Bob()60 	void NTCP2Establisher::KDF1Bob ()
61 	{
62 		KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetStaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ());
63 	}
64 
KeyDerivationFunction2(const uint8_t * sessionRequest,size_t sessionRequestLen,const uint8_t * epub)65 	void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub)
66 	{
67 		MixHash (sessionRequest + 32, 32); // encrypted payload
68 
69 		int paddingLength =  sessionRequestLen - 64;
70 		if (paddingLength > 0)
71 			MixHash (sessionRequest + 64, paddingLength);
72 		MixHash (epub, 32);
73 
74 		// x25519 between remote pub and ephemaral priv
75 		uint8_t inputKeyMaterial[32];
76 		m_EphemeralKeys->Agree (GetRemotePub (), inputKeyMaterial);
77 
78 		MixKey (inputKeyMaterial);
79 	}
80 
KDF2Alice()81 	void NTCP2Establisher::KDF2Alice ()
82 	{
83 		KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetRemotePub ());
84 	}
85 
KDF2Bob()86 	void NTCP2Establisher::KDF2Bob ()
87 	{
88 		KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetPub ());
89 	}
90 
KDF3Alice()91 	void NTCP2Establisher::KDF3Alice ()
92 	{
93 		uint8_t inputKeyMaterial[32];
94 		i2p::context.GetStaticKeys ().Agree (GetRemotePub (), inputKeyMaterial);
95 		MixKey (inputKeyMaterial);
96 	}
97 
KDF3Bob()98 	void NTCP2Establisher::KDF3Bob ()
99 	{
100 		uint8_t inputKeyMaterial[32];
101 		m_EphemeralKeys->Agree (m_RemoteStaticKey, inputKeyMaterial);
102 		MixKey (inputKeyMaterial);
103 	}
104 
CreateEphemeralKey()105 	void NTCP2Establisher::CreateEphemeralKey ()
106 	{
107 		m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
108 	}
109 
CreateSessionRequestMessage()110 	void NTCP2Establisher::CreateSessionRequestMessage ()
111 	{
112 		// create buffer and fill padding
113 		auto paddingLength = rand () % (NTCP2_SESSION_REQUEST_MAX_SIZE - 64); // message length doesn't exceed 287 bytes
114 		m_SessionRequestBufferLen = paddingLength + 64;
115 		RAND_bytes (m_SessionRequestBuffer + 64, paddingLength);
116 		// encrypt X
117 		i2p::crypto::CBCEncryption encryption;
118 		encryption.SetKey (m_RemoteIdentHash);
119 		encryption.SetIV (m_IV);
120 		encryption.Encrypt (GetPub (), 32, m_SessionRequestBuffer); // X
121 		encryption.GetIV (m_IV); // save IV for SessionCreated
122 		// encryption key for next block
123 		KDF1Alice ();
124 		// fill options
125 		uint8_t options[32]; // actual options size is 16 bytes
126 		memset (options, 0, 16);
127 		options[0] = i2p::context.GetNetID (); // network ID
128 		options[1] = 2; // ver
129 		htobe16buf (options + 2, paddingLength); // padLen
130 		// m3p2Len
131 		auto bufLen = i2p::context.GetRouterInfo ().GetBufferLen ();
132 		m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options
133 		htobe16buf (options + 4,  m3p2Len);
134 		// fill m3p2 payload (RouterInfo block)
135 		m_SessionConfirmedBuffer = new uint8_t[m3p2Len + 48]; // m3p1 is 48 bytes
136 		uint8_t * m3p2 = m_SessionConfirmedBuffer + 48;
137 		m3p2[0] = eNTCP2BlkRouterInfo; // block
138 		htobe16buf (m3p2 + 1, bufLen + 1); // flag + RI
139 		m3p2[3] = 0; // flag
140 		memcpy (m3p2 + 4, i2p::context.GetRouterInfo ().GetBuffer (), bufLen); // TODO: own RI should be protected by mutex
141 		// 2 bytes reserved
142 		htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA
143 		// 4 bytes reserved
144 		// sign and encrypt options, use m_H as AD
145 		uint8_t nonce[12];
146 		memset (nonce, 0, 12); // set nonce to zero
147 		i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt
148 	}
149 
CreateSessionCreatedMessage()150 	void NTCP2Establisher::CreateSessionCreatedMessage ()
151 	{
152 		auto paddingLen = rand () % (NTCP2_SESSION_CREATED_MAX_SIZE - 64);
153 		m_SessionCreatedBufferLen = paddingLen + 64;
154 		RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen);
155 		// encrypt Y
156 		i2p::crypto::CBCEncryption encryption;
157 		encryption.SetKey (i2p::context.GetIdentHash ());
158 		encryption.SetIV (m_IV);
159 		encryption.Encrypt (GetPub (), 32, m_SessionCreatedBuffer); // Y
160 		// encryption key for next block (m_K)
161 		KDF2Bob ();
162 		uint8_t options[16];
163 		memset (options, 0, 16);
164 		htobe16buf (options + 2, paddingLen); // padLen
165 		htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsB
166 		// sign and encrypt options, use m_H as AD
167 		uint8_t nonce[12];
168 		memset (nonce, 0, 12); // set nonce to zero
169 		i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt
170 
171 	}
172 
CreateSessionConfirmedMessagePart1(const uint8_t * nonce)173 	void NTCP2Establisher::CreateSessionConfirmedMessagePart1 (const uint8_t * nonce)
174 	{
175 		// update AD
176 		MixHash (m_SessionCreatedBuffer + 32, 32);	// encrypted payload
177 		int paddingLength = m_SessionCreatedBufferLen - 64;
178 		if (paddingLength > 0)
179 			MixHash (m_SessionCreatedBuffer + 64, paddingLength);
180 
181 		// part1 48 bytes
182 		i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, GetH (), 32, GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt
183 	}
184 
CreateSessionConfirmedMessagePart2(const uint8_t * nonce)185 	void NTCP2Establisher::CreateSessionConfirmedMessagePart2 (const uint8_t * nonce)
186 	{
187 		// part 2
188 		// update AD again
189 		MixHash (m_SessionConfirmedBuffer, 48);
190 		// encrypt m3p2, it must be filled in SessionRequest
191 		KDF3Alice ();
192 		uint8_t * m3p2 = m_SessionConfirmedBuffer + 48;
193 		i2p::crypto::AEADChaCha20Poly1305 (m3p2, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2, m3p2Len, true); // encrypt
194 		// update h again
195 		MixHash (m3p2, m3p2Len); //h = SHA256(h || ciphertext)
196 	}
197 
ProcessSessionRequestMessage(uint16_t & paddingLen)198 	bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen)
199 	{
200 		// decrypt X
201 		i2p::crypto::CBCDecryption decryption;
202 		decryption.SetKey (i2p::context.GetIdentHash ());
203 		decryption.SetIV (i2p::context.GetNTCP2IV ());
204 		decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ());
205 		decryption.GetIV (m_IV); // save IV for SessionCreated
206 		// decryption key for next block
207 		KDF1Bob ();
208 		// verify MAC and decrypt options block (32 bytes), use m_H as AD
209 		uint8_t nonce[12], options[16];
210 		memset (nonce, 0, 12); // set nonce to zero
211 		if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, GetH (), 32, GetK (), nonce, options, 16, false)) // decrypt
212 		{
213 			// options
214 			if (options[0] && options[0] != i2p::context.GetNetID ())
215 			{
216 				LogPrint (eLogWarning, "NTCP2: SessionRequest networkID ", (int)options[0], " mismatch. Expected ", i2p::context.GetNetID ());
217 				return false;
218 			}
219 			if (options[1] == 2) // ver is always 2
220 			{
221 				paddingLen = bufbe16toh (options + 2);
222 				m_SessionRequestBufferLen = paddingLen + 64;
223 				m3p2Len = bufbe16toh (options + 4);
224 				if (m3p2Len < 16)
225 				{
226 					LogPrint (eLogWarning, "NTCP2: SessionRequest m3p2len=", m3p2Len, " is too short");
227 					return false;
228 				}
229 				// check timestamp
230 				auto ts = i2p::util::GetSecondsSinceEpoch ();
231 				uint32_t tsA = bufbe32toh (options + 8);
232 				if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW)
233 				{
234 					LogPrint (eLogWarning, "NTCP2: SessionRequest time difference ", (int)(ts - tsA), " exceeds clock skew");
235 					return false;
236 				}
237 			}
238 			else
239 			{
240 				LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]);
241 				return false;
242 			}
243 		}
244 		else
245 		{
246 			LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed ");
247 			return false;
248 		}
249 		return true;
250 	}
251 
ProcessSessionCreatedMessage(uint16_t & paddingLen)252 	bool NTCP2Establisher::ProcessSessionCreatedMessage (uint16_t& paddingLen)
253 	{
254 		m_SessionCreatedBufferLen = 64;
255 		// decrypt Y
256 		i2p::crypto::CBCDecryption decryption;
257 		decryption.SetKey (m_RemoteIdentHash);
258 		decryption.SetIV (m_IV);
259 		decryption.Decrypt (m_SessionCreatedBuffer, 32, GetRemotePub ());
260 		// decryption key for next block (m_K)
261 		KDF2Alice ();
262 		// decrypt and verify MAC
263 		uint8_t payload[16];
264 		uint8_t nonce[12];
265 		memset (nonce, 0, 12); // set nonce to zero
266 		if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, GetH (), 32, GetK (), nonce, payload, 16, false)) // decrypt
267 		{
268 			// options
269 			paddingLen = bufbe16toh(payload + 2);
270 			// check timestamp
271 			auto ts = i2p::util::GetSecondsSinceEpoch ();
272 			uint32_t tsB = bufbe32toh (payload + 8);
273 			if (tsB < ts - NTCP2_CLOCK_SKEW || tsB > ts + NTCP2_CLOCK_SKEW)
274 			{
275 				LogPrint (eLogWarning, "NTCP2: SessionCreated time difference ", (int)(ts - tsB), " exceeds clock skew");
276 				return false;
277 			}
278 		}
279 		else
280 		{
281 			LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed ");
282 			return false;
283 		}
284 		return true;
285 	}
286 
ProcessSessionConfirmedMessagePart1(const uint8_t * nonce)287 	bool NTCP2Establisher::ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce)
288 	{
289 		// update AD
290 		MixHash (m_SessionCreatedBuffer + 32, 32);	// encrypted payload
291 		int paddingLength = m_SessionCreatedBufferLen - 64;
292 		if (paddingLength > 0)
293 			MixHash (m_SessionCreatedBuffer + 64, paddingLength);
294 
295 		if (!i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, GetH (), 32, GetK (), nonce, m_RemoteStaticKey, 32, false)) // decrypt S
296 		{
297 			LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
298 			return false;
299 		}
300 		return true;
301 	}
302 
ProcessSessionConfirmedMessagePart2(const uint8_t * nonce,uint8_t * m3p2Buf)303 	bool NTCP2Establisher::ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf)
304 	{
305 		// update AD again
306 		MixHash (m_SessionConfirmedBuffer, 48);
307 
308 		KDF3Bob ();
309 		if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt
310 			// caclulate new h again for KDF data
311 			MixHash (m_SessionConfirmedBuffer + 48, m3p2Len); // h = SHA256(h || ciphertext)
312 		else
313 		{
314 			LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
315 			return false;
316 		}
317 		return true;
318 	}
319 
NTCP2Session(NTCP2Server & server,std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter,std::shared_ptr<const i2p::data::RouterInfo::Address> addr)320 	NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter,
321 	    	std::shared_ptr<const i2p::data::RouterInfo::Address> addr):
322 		TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT),
323 		m_Server (server), m_Socket (m_Server.GetService ()),
324 		m_IsEstablished (false), m_IsTerminated (false),
325 		m_Establisher (new NTCP2Establisher),
326 #if OPENSSL_SIPHASH
327 		m_SendMDCtx(nullptr), m_ReceiveMDCtx (nullptr),
328 #else
329 		m_SendSipKey (nullptr), m_ReceiveSipKey (nullptr),
330 #endif
331 		m_NextReceivedLen (0), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr),
332 		m_NextReceivedBufferSize (0), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0),
333 		m_IsSending (false), m_IsReceiving (false), m_NextPaddingSize (16)
334 	{
335 		if (in_RemoteRouter) // Alice
336 		{
337 			m_Establisher->m_RemoteIdentHash = GetRemoteIdentity ()->GetIdentHash ();
338 			if (addr)
339 			{
340 				memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32);
341 				memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16);
342 				m_RemoteEndpoint = boost::asio::ip::tcp::endpoint (addr->host, addr->port);
343 			}
344 			else
345 				LogPrint (eLogWarning, "NTCP2: Missing NTCP2 address");
346 		}
347 		m_NextRouterInfoResendTime = i2p::util::GetSecondsSinceEpoch () + NTCP2_ROUTERINFO_RESEND_INTERVAL +
348 			rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
349 	}
350 
~NTCP2Session()351 	NTCP2Session::~NTCP2Session ()
352 	{
353 		delete[] m_NextReceivedBuffer;
354 		delete[] m_NextSendBuffer;
355 #if OPENSSL_SIPHASH
356 		if (m_SendMDCtx) EVP_MD_CTX_destroy (m_SendMDCtx);
357 		if (m_ReceiveMDCtx) EVP_MD_CTX_destroy (m_ReceiveMDCtx);
358 #endif
359 	}
360 
Terminate()361 	void NTCP2Session::Terminate ()
362 	{
363 		if (!m_IsTerminated)
364 		{
365 			m_IsTerminated = true;
366 			m_IsEstablished = false;
367 			boost::system::error_code ec;
368 			m_Socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
369 			if (ec)
370 				LogPrint (eLogDebug, "NTCP2: Couldn't shutdown socket: ", ec.message ());
371 			m_Socket.close ();
372 			transports.PeerDisconnected (shared_from_this ());
373 			m_Server.RemoveNTCP2Session (shared_from_this ());
374 			m_SendQueue.clear ();
375 			LogPrint (eLogDebug, "NTCP2: Session terminated");
376 		}
377 	}
378 
TerminateByTimeout()379 	void NTCP2Session::TerminateByTimeout ()
380 	{
381 		SendTerminationAndTerminate (eNTCP2IdleTimeout);
382 	}
383 
Done()384 	void NTCP2Session::Done ()
385 	{
386 		m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ()));
387 	}
388 
Established()389 	void NTCP2Session::Established ()
390 	{
391 		m_IsEstablished = true;
392 		m_Establisher.reset (nullptr);
393 		SetTerminationTimeout (NTCP2_TERMINATION_TIMEOUT);
394 		transports.PeerConnected (shared_from_this ());
395 	}
396 
CreateNonce(uint64_t seqn,uint8_t * nonce)397 	void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce)
398 	{
399 		memset (nonce, 0, 4);
400 		htole64buf (nonce + 4, seqn);
401 	}
402 
CreateNextReceivedBuffer(size_t size)403 	void NTCP2Session::CreateNextReceivedBuffer (size_t size)
404 	{
405 		if (m_NextReceivedBuffer)
406 		{
407 			if (size <= m_NextReceivedBufferSize)
408 				return; // buffer is good, do nothing
409 			else
410 				delete[] m_NextReceivedBuffer;
411 		}
412 		m_NextReceivedBuffer = new uint8_t[size];
413 		m_NextReceivedBufferSize = size;
414 	}
415 
DeleteNextReceiveBuffer(uint64_t ts)416 	void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts)
417 	{
418 		if (m_NextReceivedBuffer && !m_IsReceiving &&
419 		    ts > m_LastActivityTimestamp + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT)
420 		{
421 			delete[] m_NextReceivedBuffer;
422 			m_NextReceivedBuffer = nullptr;
423 			m_NextReceivedBufferSize = 0;
424 		}
425 	}
426 
KeyDerivationFunctionDataPhase()427 	void NTCP2Session::KeyDerivationFunctionDataPhase ()
428 	{
429 		uint8_t k[64];
430 		i2p::crypto::HKDF (m_Establisher->GetCK (), nullptr, 0, "", k); // k_ab, k_ba = HKDF(ck, zerolen)
431 		memcpy (m_Kab, k, 32); memcpy (m_Kba, k + 32, 32);
432 		uint8_t master[32];
433 		i2p::crypto::HKDF (m_Establisher->GetCK (), nullptr, 0, "ask", master, 32); // ask_master = HKDF(ck, zerolen, info="ask")
434 		uint8_t h[39];
435 		memcpy (h, m_Establisher->GetH (), 32);
436 		memcpy (h + 32, "siphash", 7);
437 		i2p::crypto::HKDF (master, h, 39, "", master, 32); // sip_master = HKDF(ask_master, h || "siphash")
438 		i2p::crypto::HKDF (master, nullptr, 0, "", k); // sipkeys_ab, sipkeys_ba = HKDF(sip_master, zerolen)
439 		memcpy (m_Sipkeysab, k, 32); memcpy (m_Sipkeysba, k + 32, 32);
440 	}
441 
442 
SendSessionRequest()443 	void NTCP2Session::SendSessionRequest ()
444 	{
445 		m_Establisher->CreateSessionRequestMessage ();
446 		// send message
447 		boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (),
448 			std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
449 	}
450 
HandleSessionRequestSent(const boost::system::error_code & ecode,std::size_t bytes_transferred)451 	void NTCP2Session::HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
452 	{
453 		(void) bytes_transferred;
454 		if (ecode)
455 		{
456 			LogPrint (eLogWarning, "NTCP2: Couldn't send SessionRequest message: ", ecode.message ());
457 			Terminate ();
458 		}
459 		else
460 		{
461 			// we receive first 64 bytes (32 Y, and 32 ChaCha/Poly frame) first
462 			boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer, 64), boost::asio::transfer_all (),
463 				std::bind(&NTCP2Session::HandleSessionCreatedReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
464 		}
465 	}
466 
HandleSessionRequestReceived(const boost::system::error_code & ecode,std::size_t bytes_transferred)467 	void NTCP2Session::HandleSessionRequestReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
468 	{
469 		(void) bytes_transferred;
470 		if (ecode)
471 		{
472 			LogPrint (eLogWarning, "NTCP2: SessionRequest read error: ", ecode.message ());
473 			Terminate ();
474 		}
475 		else
476 		{
477 			LogPrint (eLogDebug, "NTCP2: SessionRequest received ", bytes_transferred);
478 			uint16_t paddingLen = 0;
479 			if (m_Establisher->ProcessSessionRequestMessage (paddingLen))
480 			{
481 				if (paddingLen > 0)
482 				{
483 					if (paddingLen <= NTCP2_SESSION_REQUEST_MAX_SIZE - 64) // session request is 287 bytes max
484 					{
485 						boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (),
486 							std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
487 					}
488 					else
489 					{
490 						LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen,  " is too long");
491 						Terminate ();
492 					}
493 				}
494 				else
495 					SendSessionCreated ();
496 			}
497 			else
498 				Terminate ();
499 		}
500 	}
501 
HandleSessionRequestPaddingReceived(const boost::system::error_code & ecode,std::size_t bytes_transferred)502 	void NTCP2Session::HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
503 	{
504 		if (ecode)
505 		{
506 			LogPrint (eLogWarning, "NTCP2: SessionRequest padding read error: ", ecode.message ());
507 			Terminate ();
508 		}
509 		else
510 			SendSessionCreated ();
511 	}
512 
SendSessionCreated()513 	void NTCP2Session::SendSessionCreated ()
514 	{
515 		m_Establisher->CreateSessionCreatedMessage ();
516 		// send message
517 		boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (),
518 			std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
519 	}
520 
HandleSessionCreatedReceived(const boost::system::error_code & ecode,std::size_t bytes_transferred)521 	void NTCP2Session::HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
522 	{
523 		if (ecode)
524 		{
525 			LogPrint (eLogWarning, "NTCP2: SessionCreated read error: ", ecode.message ());
526 			Terminate ();
527 		}
528 		else
529 		{
530 			LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred);
531 			uint16_t paddingLen = 0;
532 			if (m_Establisher->ProcessSessionCreatedMessage (paddingLen))
533 			{
534 				if (paddingLen > 0)
535 				{
536 					if (paddingLen <= NTCP2_SESSION_CREATED_MAX_SIZE - 64) // session created is 287 bytes max
537 					{
538 						boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (),
539 							std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
540 					}
541 					else
542 					{
543 						LogPrint (eLogWarning, "NTCP2: SessionCreated padding length ", (int)paddingLen,  " is too long");
544 						Terminate ();
545 					}
546 				}
547 				else
548 					SendSessionConfirmed ();
549 			}
550 			else
551 				Terminate ();
552 		}
553 	}
554 
HandleSessionCreatedPaddingReceived(const boost::system::error_code & ecode,std::size_t bytes_transferred)555 	void NTCP2Session::HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
556 	{
557 		if (ecode)
558 		{
559 			LogPrint (eLogWarning, "NTCP2: SessionCreated padding read error: ", ecode.message ());
560 			Terminate ();
561 		}
562 		else
563 		{
564 			m_Establisher->m_SessionCreatedBufferLen += bytes_transferred;
565 			SendSessionConfirmed ();
566 		}
567 	}
568 
SendSessionConfirmed()569 	void NTCP2Session::SendSessionConfirmed ()
570 	{
571 		uint8_t nonce[12];
572 		CreateNonce (1, nonce); // set nonce to 1
573 		m_Establisher->CreateSessionConfirmedMessagePart1 (nonce);
574 		memset (nonce, 0, 12); // set nonce back to 0
575 		m_Establisher->CreateSessionConfirmedMessagePart2 (nonce);
576 		// send message
577 		boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (),
578 			std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
579 	}
580 
HandleSessionConfirmedSent(const boost::system::error_code & ecode,std::size_t bytes_transferred)581 	void NTCP2Session::HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
582 	{
583 		(void) bytes_transferred;
584 		if (ecode)
585 		{
586 			LogPrint (eLogWarning, "NTCP2: Couldn't send SessionConfirmed message: ", ecode.message ());
587 			Terminate ();
588 		}
589 		else
590 		{
591 			LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent");
592 			KeyDerivationFunctionDataPhase ();
593 			// Alice data phase keys
594 			m_SendKey = m_Kab;
595 			m_ReceiveKey = m_Kba;
596 			SetSipKeys (m_Sipkeysab, m_Sipkeysba);
597 			memcpy (m_ReceiveIV.buf, m_Sipkeysba + 16, 8);
598 			memcpy (m_SendIV.buf, m_Sipkeysab + 16, 8);
599 			Established ();
600 			ReceiveLength ();
601 
602 			// TODO: remove
603 			// m_SendQueue.push_back (CreateDeliveryStatusMsg (1));
604 			// SendQueue ();
605 		}
606 	}
607 
HandleSessionCreatedSent(const boost::system::error_code & ecode,std::size_t bytes_transferred)608 	void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
609 	{
610 		(void) bytes_transferred;
611 		if (ecode)
612 		{
613 			LogPrint (eLogWarning, "NTCP2: Couldn't send SessionCreated message: ", ecode.message ());
614 			Terminate ();
615 		}
616 		else
617 		{
618 			LogPrint (eLogDebug, "NTCP2: SessionCreated sent");
619 			m_Establisher->m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48];
620 			boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (),
621 				std::bind(&NTCP2Session::HandleSessionConfirmedReceived , shared_from_this (), std::placeholders::_1, std::placeholders::_2));
622 		}
623 	}
624 
HandleSessionConfirmedReceived(const boost::system::error_code & ecode,std::size_t bytes_transferred)625 	void NTCP2Session::HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
626 	{
627 		if (ecode)
628 		{
629 			LogPrint (eLogWarning, "NTCP2: SessionConfirmed read error: ", ecode.message ());
630 			Terminate ();
631 		}
632 		else
633 		{
634 			LogPrint (eLogDebug, "NTCP2: SessionConfirmed received");
635 			// part 1
636 			uint8_t nonce[12];
637 			CreateNonce (1, nonce);
638 			if (m_Establisher->ProcessSessionConfirmedMessagePart1 (nonce))
639 			{
640 				// part 2
641 				std::vector<uint8_t> buf(m_Establisher->m3p2Len - 16); // -MAC
642 				memset (nonce, 0, 12); // set nonce to 0 again
643 				if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf.data ()))
644 				{
645 					KeyDerivationFunctionDataPhase ();
646 					// Bob data phase keys
647 					m_SendKey = m_Kba;
648 					m_ReceiveKey = m_Kab;
649 					SetSipKeys (m_Sipkeysba, m_Sipkeysab);
650 					memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8);
651 					memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8);
652 					// payload
653 					// process RI
654 					if (buf[0] != eNTCP2BlkRouterInfo)
655 					{
656 						LogPrint (eLogWarning, "NTCP2: Unexpected block ", (int)buf[0], " in SessionConfirmed");
657 						Terminate ();
658 						return;
659 					}
660 					auto size = bufbe16toh (buf.data () + 1);
661 					if (size > buf.size () - 3)
662 					{
663 						LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed");
664 						Terminate ();
665 						return;
666 					}
667 					// TODO: check flag
668 					i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag
669 					if (ri.IsUnreachable ())
670 					{
671 						LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed");
672 						SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail);
673 						return;
674 					}
675 					if (i2p::util::GetMillisecondsSinceEpoch () > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
676 					{
677 						LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed");
678 						SendTerminationAndTerminate (eNTCP2Message3Error);
679 						return;
680 					}
681 					auto addr = ri.GetNTCP2AddressWithStaticKey (m_Establisher->m_RemoteStaticKey);
682 					if (!addr)
683 					{
684 						LogPrint (eLogError, "NTCP2: No NTCP2 address with static key found in SessionConfirmed");
685 						Terminate ();
686 						return;
687 					}
688 					i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, buf.data () + 3, size)); // TODO: should insert ri and not parse it twice
689 					// TODO: process options
690 
691 					// ready to communicate
692 					auto existing = i2p::data::netdb.FindRouter (ri.GetRouterIdentity ()->GetIdentHash ()); // check if exists already
693 					SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ());
694 					if (m_Server.AddNTCP2Session (shared_from_this (), true))
695 					{
696 						Established ();
697 						ReceiveLength ();
698 					}
699 					else
700 						Terminate ();
701 				}
702 				else
703 					Terminate ();
704 			}
705 			else
706 				Terminate ();
707 		}
708 	}
709 
SetSipKeys(const uint8_t * sendSipKey,const uint8_t * receiveSipKey)710 	void NTCP2Session::SetSipKeys (const uint8_t * sendSipKey, const uint8_t * receiveSipKey)
711 	{
712 #if OPENSSL_SIPHASH
713 		EVP_PKEY * sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, sendSipKey, 16);
714 		m_SendMDCtx = EVP_MD_CTX_create ();
715 		EVP_PKEY_CTX *ctx = nullptr;
716 		EVP_DigestSignInit (m_SendMDCtx, &ctx, nullptr, nullptr, sipKey);
717 		EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr);
718 		EVP_PKEY_free (sipKey);
719 
720 		sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, receiveSipKey, 16);
721 		m_ReceiveMDCtx = EVP_MD_CTX_create ();
722 		ctx = nullptr;
723 		EVP_DigestSignInit (m_ReceiveMDCtx, &ctx, NULL, NULL, sipKey);
724 		EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr);
725 		EVP_PKEY_free (sipKey);
726 #else
727 		m_SendSipKey = sendSipKey;
728 		m_ReceiveSipKey = receiveSipKey;
729 #endif
730 	}
731 
ClientLogin()732 	void NTCP2Session::ClientLogin ()
733 	{
734 		m_Establisher->CreateEphemeralKey ();
735 		SendSessionRequest ();
736 	}
737 
ServerLogin()738 	void NTCP2Session::ServerLogin ()
739 	{
740 		m_Establisher->CreateEphemeralKey ();
741 		boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer, 64), boost::asio::transfer_all (),
742 			std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (),
743 			std::placeholders::_1, std::placeholders::_2));
744 	}
745 
ReceiveLength()746 	void NTCP2Session::ReceiveLength ()
747 	{
748 		if (IsTerminated ()) return;
749 #ifdef __linux__
750 		const int one = 1;
751     	setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
752 #endif
753 		boost::asio::async_read (m_Socket, boost::asio::buffer(&m_NextReceivedLen, 2), boost::asio::transfer_all (),
754 			std::bind(&NTCP2Session::HandleReceivedLength, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
755 	}
756 
HandleReceivedLength(const boost::system::error_code & ecode,std::size_t bytes_transferred)757 	void NTCP2Session::HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred)
758 	{
759 		if (ecode)
760 		{
761 			if (ecode != boost::asio::error::operation_aborted)
762 				LogPrint (eLogWarning, "NTCP2: Receive length read error: ", ecode.message ());
763 			Terminate ();
764 		}
765 		else
766 		{
767 #if OPENSSL_SIPHASH
768 			EVP_DigestSignInit (m_ReceiveMDCtx, nullptr, nullptr, nullptr, nullptr);
769 			EVP_DigestSignUpdate (m_ReceiveMDCtx, m_ReceiveIV.buf, 8);
770 			size_t l = 8;
771 			EVP_DigestSignFinal (m_ReceiveMDCtx, m_ReceiveIV.buf, &l);
772 #else
773 			i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey);
774 #endif
775 			// m_NextReceivedLen comes from the network in BigEndian
776 			m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key);
777 			LogPrint (eLogDebug, "NTCP2: Received length ", m_NextReceivedLen);
778 			if (m_NextReceivedLen >= 16)
779 			{
780 				CreateNextReceivedBuffer (m_NextReceivedLen);
781 				boost::system::error_code ec;
782 				size_t moreBytes = m_Socket.available(ec);
783 				if (!ec && moreBytes >= m_NextReceivedLen)
784 				{
785 					// read and process message immediately if available
786 					moreBytes = boost::asio::read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), ec);
787 					HandleReceived (ec, moreBytes);
788 				}
789 				else
790 					Receive ();
791 			}
792 			else
793 			{
794 				LogPrint (eLogError, "NTCP2: Received length ", m_NextReceivedLen, " is too short");
795 				Terminate ();
796 			}
797 		}
798 	}
799 
Receive()800 	void NTCP2Session::Receive ()
801 	{
802 		if (IsTerminated ()) return;
803 #ifdef __linux__
804 		const int one = 1;
805 		setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
806 #endif
807 		m_IsReceiving = true;
808 		boost::asio::async_read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (),
809 			std::bind(&NTCP2Session::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
810 	}
811 
HandleReceived(const boost::system::error_code & ecode,std::size_t bytes_transferred)812 	void NTCP2Session::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
813 	{
814 		if (ecode)
815 		{
816 			if (ecode != boost::asio::error::operation_aborted)
817 				LogPrint (eLogWarning, "NTCP2: Receive read error: ", ecode.message ());
818 			Terminate ();
819 		}
820 		else
821 		{
822 			m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
823 			m_NumReceivedBytes += bytes_transferred + 2; // + length
824 			i2p::transport::transports.UpdateReceivedBytes (bytes_transferred);
825 			uint8_t nonce[12];
826 			CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++;
827 			if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false))
828 			{
829 				LogPrint (eLogDebug, "NTCP2: Received message decrypted");
830 				ProcessNextFrame (m_NextReceivedBuffer, m_NextReceivedLen-16);
831 				m_IsReceiving = false;
832 				ReceiveLength ();
833 			}
834 			else
835 			{
836 				LogPrint (eLogWarning, "NTCP2: Received AEAD verification failed ");
837 				SendTerminationAndTerminate (eNTCP2DataPhaseAEADFailure);
838 			}
839 		}
840 	}
841 
ProcessNextFrame(const uint8_t * frame,size_t len)842 	void NTCP2Session::ProcessNextFrame (const uint8_t * frame, size_t len)
843 	{
844 		size_t offset = 0;
845 		while (offset < len)
846 		{
847 			uint8_t blk = frame[offset];
848 			offset++;
849 			auto size = bufbe16toh (frame + offset);
850 			offset += 2;
851 			LogPrint (eLogDebug, "NTCP2: Block type ", (int)blk, " of size ", size);
852 			if (size > len)
853 			{
854 				LogPrint (eLogError, "NTCP2: Unexpected block length ", size);
855 				break;
856 			}
857 			switch (blk)
858 			{
859 				case eNTCP2BlkDateTime:
860 					LogPrint (eLogDebug, "NTCP2: Datetime");
861 				break;
862 				case eNTCP2BlkOptions:
863 					LogPrint (eLogDebug, "NTCP2: Options");
864 				break;
865 				case eNTCP2BlkRouterInfo:
866 				{
867 					LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", (int)frame[offset]);
868 					i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, frame + offset, size));
869 					break;
870 				}
871 				case eNTCP2BlkI2NPMessage:
872 				{
873 					LogPrint (eLogDebug, "NTCP2: I2NP");
874 					if (size > I2NP_MAX_MESSAGE_SIZE)
875 					{
876 						LogPrint (eLogError, "NTCP2: I2NP block is too long ", size);
877 						break;
878 					}
879 					auto nextMsg = (frame[offset] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPMessage (size);
880 					nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header
881 					if (nextMsg->len <= nextMsg->maxLen)
882 					{
883 						memcpy (nextMsg->GetNTCP2Header (), frame + offset, size);
884 						nextMsg->FromNTCP2 ();
885 						m_Handler.PutNextMessage (std::move (nextMsg));
886 					}
887 					else
888 						LogPrint (eLogError, "NTCP2: I2NP block is too long for I2NP message");
889 					break;
890 				}
891 				case eNTCP2BlkTermination:
892 					if (size >= 9)
893 					{
894 						LogPrint (eLogDebug, "NTCP2: Rermination. reason=", (int)(frame[offset + 8]));
895 						Terminate ();
896 					}
897 					else
898 						LogPrint (eLogWarning, "NTCP2: Unexpected termination block size ", size);
899 				break;
900 				case eNTCP2BlkPadding:
901 					LogPrint (eLogDebug, "NTCP2: Padding");
902 				break;
903 				default:
904 					LogPrint (eLogWarning, "NTCP2: Unknown block type ", (int)blk);
905 			}
906 			offset += size;
907 		}
908 		m_Handler.Flush ();
909 	}
910 
SetNextSentFrameLength(size_t frameLen,uint8_t * lengthBuf)911 	void NTCP2Session::SetNextSentFrameLength (size_t frameLen, uint8_t * lengthBuf)
912 	{
913 #if OPENSSL_SIPHASH
914 		EVP_DigestSignInit (m_SendMDCtx, nullptr, nullptr, nullptr, nullptr);
915 		EVP_DigestSignUpdate (m_SendMDCtx, m_SendIV.buf, 8);
916 		size_t l = 8;
917 		EVP_DigestSignFinal (m_SendMDCtx, m_SendIV.buf, &l);
918 #else
919 		i2p::crypto::Siphash<8> (m_SendIV.buf, m_SendIV.buf, 8, m_SendSipKey);
920 #endif
921 		// length must be in BigEndian
922 		htobe16buf (lengthBuf, frameLen ^ le16toh (m_SendIV.key));
923 		LogPrint (eLogDebug, "NTCP2: Sent length ", frameLen);
924 	}
925 
SendI2NPMsgs(std::vector<std::shared_ptr<I2NPMessage>> & msgs)926 	void NTCP2Session::SendI2NPMsgs (std::vector<std::shared_ptr<I2NPMessage> >& msgs)
927 	{
928 		if (msgs.empty () || IsTerminated ()) return;
929 
930 		size_t totalLen = 0;
931 		std::vector<std::pair<uint8_t *, size_t> > encryptBufs;
932 		std::vector<boost::asio::const_buffer> bufs;
933 		std::shared_ptr<I2NPMessage> first;
934 		uint8_t * macBuf = nullptr;
935 		for (auto& it: msgs)
936 		{
937 			it->ToNTCP2 ();
938 			auto buf = it->GetNTCP2Header ();
939 			auto len = it->GetNTCP2Length ();
940 			// block header
941 			buf -= 3;
942 			buf[0] = eNTCP2BlkI2NPMessage; // blk
943 			htobe16buf (buf + 1, len); // size
944 			len += 3;
945 			totalLen += len;
946 			encryptBufs.push_back ( {buf, len} );
947 			if (&it == &msgs.front ()) // first message
948 			{
949 				// allocate two bytes for length
950 				buf -= 2; len += 2;
951 				first = it;
952 			}
953 			if (&it == &msgs.back () && it->len + 16 < it->maxLen) // last message
954 			{
955 				// if it's long enough we add padding and MAC to it
956 				// create padding block
957 				auto paddingLen = CreatePaddingBlock (totalLen, buf + len, it->maxLen - it->len - 16);
958 				if (paddingLen)
959 				{
960 					encryptBufs.push_back ( {buf + len, paddingLen} );
961 					len += paddingLen;
962 					totalLen += paddingLen;
963 				}
964 				macBuf = buf + len;
965 				// allocate 16 bytes for MAC
966 				len += 16;
967 			}
968 
969 			bufs.push_back (boost::asio::buffer (buf, len));
970 		}
971 
972 		if (!macBuf) // last block was not enough for MAC
973 		{
974 			// allocate send buffer
975 			m_NextSendBuffer = new uint8_t[287]; // can be any size > 16, we just allocate 287 frequently
976 			// create padding block
977 			auto paddingLen = CreatePaddingBlock (totalLen, m_NextSendBuffer, 287 - 16);
978 			// and padding block to encrypt and send
979 			if (paddingLen)
980 				encryptBufs.push_back ( {m_NextSendBuffer, paddingLen} );
981 			bufs.push_back (boost::asio::buffer (m_NextSendBuffer, paddingLen + 16));
982 			macBuf = m_NextSendBuffer + paddingLen;
983 			totalLen += paddingLen;
984 		}
985 		uint8_t nonce[12];
986 		CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
987 		i2p::crypto::AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers
988 		SetNextSentFrameLength (totalLen + 16, first->GetNTCP2Header () - 5); // frame length right before first block
989 
990 		// send buffers
991 		m_IsSending = true;
992 		boost::asio::async_write (m_Socket, bufs, boost::asio::transfer_all (),
993 			std::bind(&NTCP2Session::HandleI2NPMsgsSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs));
994 	}
995 
HandleI2NPMsgsSent(const boost::system::error_code & ecode,std::size_t bytes_transferred,std::vector<std::shared_ptr<I2NPMessage>> msgs)996 	void NTCP2Session::HandleI2NPMsgsSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs)
997 	{
998 		HandleNextFrameSent (ecode, bytes_transferred);
999 		// msgs get destroyed here
1000 	}
1001 
EncryptAndSendNextBuffer(size_t payloadLen)1002 	void NTCP2Session::EncryptAndSendNextBuffer (size_t payloadLen)
1003 	{
1004 		if (IsTerminated ())
1005 		{
1006 			delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr;
1007 			return;
1008 		}
1009 		// encrypt
1010 		uint8_t nonce[12];
1011 		CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
1012 		i2p::crypto::AEADChaCha20Poly1305Encrypt ({ {m_NextSendBuffer + 2, payloadLen} }, m_SendKey, nonce, m_NextSendBuffer + payloadLen + 2);
1013 		SetNextSentFrameLength (payloadLen + 16, m_NextSendBuffer);
1014 		// send
1015 		m_IsSending = true;
1016 		boost::asio::async_write (m_Socket, boost::asio::buffer (m_NextSendBuffer, payloadLen + 16 + 2), boost::asio::transfer_all (),
1017 			std::bind(&NTCP2Session::HandleNextFrameSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
1018 	}
1019 
HandleNextFrameSent(const boost::system::error_code & ecode,std::size_t bytes_transferred)1020 	void NTCP2Session::HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
1021 	{
1022 		m_IsSending = false;
1023 		delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr;
1024 
1025 		if (ecode)
1026 		{
1027 			if (ecode != boost::asio::error::operation_aborted)
1028 				LogPrint (eLogWarning, "NTCP2: Couldn't send frame ", ecode.message ());
1029 			Terminate ();
1030 		}
1031 		else
1032 		{
1033 			m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
1034 			m_NumSentBytes += bytes_transferred;
1035 			i2p::transport::transports.UpdateSentBytes (bytes_transferred);
1036 			LogPrint (eLogDebug, "NTCP2: Next frame sent ", bytes_transferred);
1037 			if (m_LastActivityTimestamp > m_NextRouterInfoResendTime)
1038 			{
1039 				m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL +
1040 					rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
1041 				SendRouterInfo ();
1042 			}
1043 			else
1044 				SendQueue ();
1045 		}
1046 	}
1047 
SendQueue()1048 	void NTCP2Session::SendQueue ()
1049 	{
1050 		if (!m_SendQueue.empty ())
1051 		{
1052 			std::vector<std::shared_ptr<I2NPMessage> > msgs;
1053 			size_t s = 0;
1054 			while (!m_SendQueue.empty ())
1055 			{
1056 				auto msg = m_SendQueue.front ();
1057 				size_t len = msg->GetNTCP2Length ();
1058 				if (s + len + 3 <= NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) // 3 bytes block header
1059 				{
1060 					msgs.push_back (msg);
1061 					s += (len + 3);
1062 					m_SendQueue.pop_front ();
1063 				}
1064 				else if (len + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE)
1065 				{
1066 					LogPrint (eLogError, "NTCP2: I2NP message of size ", len, " can't be sent. Dropped");
1067 					m_SendQueue.pop_front ();
1068 				}
1069 				else
1070 					break;
1071 			}
1072 			SendI2NPMsgs (msgs);
1073 		}
1074 	}
1075 
CreatePaddingBlock(size_t msgLen,uint8_t * buf,size_t len)1076 	size_t NTCP2Session::CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len)
1077 	{
1078 		if (len < 3) return 0;
1079 		len -= 3;
1080 		if (msgLen < 256) msgLen = 256; // for short message padding should not be always zero
1081 		size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100;
1082 		if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) paddingSize = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3;
1083 		if (paddingSize > len) paddingSize = len;
1084 		if (paddingSize)
1085 		{
1086 			if (m_NextPaddingSize >= 16)
1087 			{
1088 				RAND_bytes ((uint8_t *)m_PaddingSizes, sizeof (m_PaddingSizes));
1089 				m_NextPaddingSize = 0;
1090 			}
1091 			paddingSize = m_PaddingSizes[m_NextPaddingSize++] % paddingSize;
1092 		}
1093 		buf[0] = eNTCP2BlkPadding; // blk
1094 		htobe16buf (buf + 1, paddingSize); // size
1095 		memset (buf + 3, 0, paddingSize);
1096 		return paddingSize + 3;
1097 	}
1098 
SendRouterInfo()1099 	void NTCP2Session::SendRouterInfo ()
1100 	{
1101 		if (!IsEstablished ()) return;
1102 		auto riLen = i2p::context.GetRouterInfo ().GetBufferLen ();
1103 		size_t payloadLen = riLen + 4; // 3 bytes block header + 1 byte RI flag
1104 		m_NextSendBuffer = new uint8_t[payloadLen + 16 + 2 + 64]; // up to 64 bytes padding
1105 		m_NextSendBuffer[2] = eNTCP2BlkRouterInfo;
1106 		htobe16buf (m_NextSendBuffer + 3, riLen + 1); // size
1107 		m_NextSendBuffer[5] = 0; // flag
1108 		memcpy (m_NextSendBuffer + 6, i2p::context.GetRouterInfo ().GetBuffer (), riLen);
1109 		// padding block
1110 		auto paddingSize = CreatePaddingBlock (payloadLen, m_NextSendBuffer + 2 + payloadLen, 64);
1111 		payloadLen += paddingSize;
1112 		// encrypt and send
1113 		EncryptAndSendNextBuffer (payloadLen);
1114 	}
1115 
SendTermination(NTCP2TerminationReason reason)1116 	void NTCP2Session::SendTermination (NTCP2TerminationReason reason)
1117 	{
1118 		if (!m_SendKey ||
1119 #if OPENSSL_SIPHASH
1120 		    !m_SendMDCtx
1121 #else
1122 		    !m_SendSipKey
1123 #endif
1124 		    ) return;
1125 		m_NextSendBuffer = new uint8_t[49]; // 49 = 12 bytes message + 16 bytes MAC + 2 bytes size + up to 19 padding block
1126 		// termination block
1127 		m_NextSendBuffer[2] = eNTCP2BlkTermination;
1128 		m_NextSendBuffer[3] = 0; m_NextSendBuffer[4] = 9; // 9 bytes block size
1129 		htobe64buf (m_NextSendBuffer + 5, m_ReceiveSequenceNumber);
1130 		m_NextSendBuffer[13] = (uint8_t)reason;
1131 		// padding block
1132 		auto paddingSize = CreatePaddingBlock (12, m_NextSendBuffer + 14, 19);
1133 		// encrypt and send
1134 		EncryptAndSendNextBuffer (paddingSize + 12);
1135 	}
1136 
SendTerminationAndTerminate(NTCP2TerminationReason reason)1137 	void NTCP2Session::SendTerminationAndTerminate (NTCP2TerminationReason reason)
1138 	{
1139 		SendTermination (reason);
1140 		m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); // let termination message go
1141 	}
1142 
SendI2NPMessages(const std::vector<std::shared_ptr<I2NPMessage>> & msgs)1143 	void NTCP2Session::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
1144 	{
1145 		m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this (), msgs));
1146 	}
1147 
PostI2NPMessages(std::vector<std::shared_ptr<I2NPMessage>> msgs)1148 	void NTCP2Session::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
1149 	{
1150 		if (m_IsTerminated) return;
1151 		for (auto it: msgs)
1152 			m_SendQueue.push_back (it);
1153 		if (!m_IsSending)
1154 			SendQueue ();
1155 		else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE)
1156 		{
1157 			LogPrint (eLogWarning, "NTCP2: Outgoing messages queue size to ",
1158 			   	GetIdentHashBase64(), " exceeds ",  NTCP2_MAX_OUTGOING_QUEUE_SIZE);
1159 			Terminate ();
1160 		}
1161 	}
1162 
SendLocalRouterInfo()1163 	void NTCP2Session::SendLocalRouterInfo ()
1164 	{
1165 		if (!IsOutgoing ()) // we send it in SessionConfirmed
1166 			m_Server.GetService ().post (std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ()));
1167 	}
1168 
NTCP2Server()1169 	NTCP2Server::NTCP2Server ():
1170 		RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()),
1171 		 m_ProxyType(eNoProxy), m_Resolver(GetService ())
1172 	{
1173 	}
1174 
~NTCP2Server()1175 	NTCP2Server::~NTCP2Server ()
1176 	{
1177 		Stop ();
1178 	}
1179 
Start()1180 	void NTCP2Server::Start ()
1181 	{
1182 		if (!IsRunning ())
1183 		{
1184 			StartIOService ();
1185 			if(UsingProxy())
1186 			{
1187 				LogPrint(eLogInfo, "NTCP2: Using proxy to connect to peers");
1188 				// TODO: resolve proxy until it is resolved
1189 				boost::asio::ip::tcp::resolver::query q(m_ProxyAddress, std::to_string(m_ProxyPort));
1190 				boost::system::error_code e;
1191 				auto itr = m_Resolver.resolve(q, e);
1192 				if(e)
1193 					LogPrint(eLogError, "NTCP2: Failed to resolve proxy ", e.message());
1194 				else
1195 				{
1196 					m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint(*itr));
1197 					if (m_ProxyEndpoint)
1198 						LogPrint(eLogDebug, "NTCP2: m_ProxyEndpoint ", *m_ProxyEndpoint);
1199 				}
1200 			}
1201 			else
1202 				LogPrint(eLogInfo, "NTCP2: Proxy is not used");
1203 			// start acceptors
1204 			auto& addresses = context.GetRouterInfo ().GetAddresses ();
1205 			for (const auto& address: addresses)
1206 			{
1207 				if (!address) continue;
1208 				if (address->IsPublishedNTCP2 () && address->port)
1209 				{
1210 					if (address->IsV4())
1211 					{
1212 						try
1213 						{
1214 							auto ep = m_Address4 ? boost::asio::ip::tcp::endpoint (m_Address4->address(), address->port):
1215 								boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), address->port);
1216 							m_NTCP2Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), ep));
1217 						}
1218 						catch ( std::exception & ex )
1219 						{
1220 							LogPrint(eLogError, "NTCP2: Failed to bind to v4 port ", address->port, ex.what());
1221 							ThrowFatal ("Unable to start IPv4 NTCP2 transport at port ", address->port, ": ", ex.what ());
1222 							continue;
1223 						}
1224 
1225 						LogPrint (eLogInfo, "NTCP2: Start listening v4 TCP port ", address->port);
1226 						auto conn = std::make_shared<NTCP2Session>(*this);
1227 						m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1));
1228 					}
1229 					else if (address->IsV6() && (context.SupportsV6 () || context.SupportsMesh ()))
1230 					{
1231 						m_NTCP2V6Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService ()));
1232 						try
1233 						{
1234 							m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6());
1235 							m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true));
1236 							m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true));
1237 #ifdef __linux__
1238 							if (!m_Address6 && !m_YggdrasilAddress) // only if not binded to address
1239 							{
1240 								// Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others
1241 #if (BOOST_VERSION >= 105500)
1242 								typedef boost::asio::detail::socket_option::integer<BOOST_ASIO_OS_DEF(IPPROTO_IPV6), IPV6_ADDR_PREFERENCES> ipv6PreferAddr;
1243 #else
1244 								typedef boost::asio::detail::socket_option::integer<IPPROTO_IPV6, IPV6_ADDR_PREFERENCES> ipv6PreferAddr;
1245 #endif
1246 								m_NTCP2V6Acceptor->set_option (ipv6PreferAddr(IPV6_PREFER_SRC_PUBLIC | IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_NONCGA));
1247 							}
1248 #endif
1249 							auto ep = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port);
1250 							if (m_Address6 && !context.SupportsMesh ())
1251 								ep = boost::asio::ip::tcp::endpoint (m_Address6->address(), address->port);
1252 							else if (m_YggdrasilAddress && !context.SupportsV6 ())
1253 								ep = boost::asio::ip::tcp::endpoint (m_YggdrasilAddress->address(), address->port);
1254 							m_NTCP2V6Acceptor->bind (ep);
1255 							m_NTCP2V6Acceptor->listen ();
1256 
1257 							LogPrint (eLogInfo, "NTCP2: Start listening v6 TCP port ", address->port);
1258 							auto conn = std::make_shared<NTCP2Session> (*this);
1259 							m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this, conn, std::placeholders::_1));
1260 						}
1261 						catch ( std::exception & ex )
1262 						{
1263 							LogPrint(eLogError, "NTCP2: Failed to bind to v6 port ", address->port, ": ", ex.what());
1264 							ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ());
1265 							continue;
1266 						}
1267 					}
1268 				}
1269 			}
1270 			ScheduleTermination ();
1271 		}
1272 	}
1273 
Stop()1274 	void NTCP2Server::Stop ()
1275 	{
1276 		{
1277 			// we have to copy it because Terminate changes m_NTCP2Sessions
1278 			auto ntcpSessions = m_NTCP2Sessions;
1279 			for (auto& it: ntcpSessions)
1280 				it.second->Terminate ();
1281 			for (auto& it: m_PendingIncomingSessions)
1282 				it->Terminate ();
1283 		}
1284 		m_NTCP2Sessions.clear ();
1285 
1286 		if (IsRunning ())
1287 		{
1288 			m_TerminationTimer.cancel ();
1289 			m_ProxyEndpoint = nullptr;
1290 		}
1291 		StopIOService ();
1292 	}
1293 
AddNTCP2Session(std::shared_ptr<NTCP2Session> session,bool incoming)1294 	bool NTCP2Server::AddNTCP2Session (std::shared_ptr<NTCP2Session> session, bool incoming)
1295 	{
1296 		if (!session) return false;
1297 		if (incoming)
1298 			m_PendingIncomingSessions.remove (session);
1299 		if (!session->GetRemoteIdentity ()) return false;
1300 		auto& ident = session->GetRemoteIdentity ()->GetIdentHash ();
1301 		auto it = m_NTCP2Sessions.find (ident);
1302 		if (it != m_NTCP2Sessions.end ())
1303 		{
1304 			LogPrint (eLogWarning, "NTCP2: Session to ", ident.ToBase64 (), " already exists");
1305 			if (incoming)
1306 				// replace by new session
1307 				it->second->Terminate ();
1308 			else
1309 				return false;
1310 		}
1311 		m_NTCP2Sessions.insert (std::make_pair (ident, session));
1312 		return true;
1313 	}
1314 
RemoveNTCP2Session(std::shared_ptr<NTCP2Session> session)1315 	void NTCP2Server::RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session)
1316 	{
1317 		if (session && session->GetRemoteIdentity ())
1318 			m_NTCP2Sessions.erase (session->GetRemoteIdentity ()->GetIdentHash ());
1319 	}
1320 
FindNTCP2Session(const i2p::data::IdentHash & ident)1321 	std::shared_ptr<NTCP2Session> NTCP2Server::FindNTCP2Session (const i2p::data::IdentHash& ident)
1322 	{
1323 		auto it = m_NTCP2Sessions.find (ident);
1324 		if (it != m_NTCP2Sessions.end ())
1325 			return it->second;
1326 		return nullptr;
1327 	}
1328 
Connect(std::shared_ptr<NTCP2Session> conn)1329 	void NTCP2Server::Connect(std::shared_ptr<NTCP2Session> conn)
1330 	{
1331 		if (!conn || conn->GetRemoteEndpoint ().address ().is_unspecified ())
1332 		{
1333 			LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
1334 			return;
1335 		}
1336 		LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint ());
1337 		GetService ().post([this, conn]()
1338 			{
1339 				if (this->AddNTCP2Session (conn))
1340 				{
1341 					auto timer = std::make_shared<boost::asio::deadline_timer>(GetService ());
1342 					auto timeout = NTCP2_CONNECT_TIMEOUT * 5;
1343 					conn->SetTerminationTimeout(timeout * 2);
1344 					timer->expires_from_now (boost::posix_time::seconds(timeout));
1345 					timer->async_wait ([conn, timeout](const boost::system::error_code& ecode)
1346 					{
1347 						if (ecode != boost::asio::error::operation_aborted)
1348 						{
1349 							LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds");
1350 							conn->Terminate ();
1351 						}
1352 					});
1353 					// bind to local address
1354 					std::shared_ptr<boost::asio::ip::tcp::endpoint> localAddress;
1355 					if (conn->GetRemoteEndpoint ().address ().is_v6 ())
1356 					{
1357 						if (i2p::util::net::IsYggdrasilAddress (conn->GetRemoteEndpoint ().address ()))
1358 							localAddress = m_YggdrasilAddress;
1359 						else
1360 							localAddress = m_Address6;
1361 						conn->GetSocket ().open (boost::asio::ip::tcp::v6 ());
1362 					}
1363 					else
1364 					{
1365 						localAddress = m_Address4;
1366 						conn->GetSocket ().open (boost::asio::ip::tcp::v4 ());
1367 					}
1368 					if (localAddress)
1369 					{
1370 						boost::system::error_code ec;
1371 						conn->GetSocket ().bind (*localAddress, ec);
1372 						if (ec)
1373 							LogPrint (eLogError, "NTCP2: Can't bind to ", localAddress->address ().to_string (), ": ", ec.message ());
1374 					}
1375 					conn->GetSocket ().async_connect (conn->GetRemoteEndpoint (), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer));
1376 				}
1377 				else
1378 					conn->Terminate ();
1379 			});
1380 	}
1381 
HandleConnect(const boost::system::error_code & ecode,std::shared_ptr<NTCP2Session> conn,std::shared_ptr<boost::asio::deadline_timer> timer)1382 	void NTCP2Server::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer)
1383 	{
1384 		timer->cancel ();
1385 		if (ecode)
1386 		{
1387 			LogPrint (eLogInfo, "NTCP2: Connect error ", ecode.message ());
1388 			conn->Terminate ();
1389 		}
1390 		else
1391 		{
1392 			LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetRemoteEndpoint ());
1393 			conn->ClientLogin ();
1394 		}
1395 	}
1396 
HandleAccept(std::shared_ptr<NTCP2Session> conn,const boost::system::error_code & error)1397 	void NTCP2Server::HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error)
1398 	{
1399 		if (!error)
1400 		{
1401 			boost::system::error_code ec;
1402 			auto ep = conn->GetSocket ().remote_endpoint(ec);
1403 			if (!ec)
1404 			{
1405 				LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
1406 				if (conn)
1407 				{
1408 					conn->SetRemoteEndpoint (ep);
1409 					conn->ServerLogin ();
1410 					m_PendingIncomingSessions.push_back (conn);
1411 					conn = nullptr;
1412 				}
1413 			}
1414 			else
1415 				LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
1416 		}
1417 		else
1418 			LogPrint (eLogError, "NTCP2: Accept error ", error.message ());
1419 
1420 		if (error != boost::asio::error::operation_aborted)
1421 		{
1422 			if (!conn) // connection is used, create new one
1423 				conn = std::make_shared<NTCP2Session> (*this);
1424 			else // reuse failed
1425 				conn->Close ();
1426 			m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this,
1427 				conn, std::placeholders::_1));
1428 		}
1429 	}
1430 
HandleAcceptV6(std::shared_ptr<NTCP2Session> conn,const boost::system::error_code & error)1431 	void NTCP2Server::HandleAcceptV6 (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error)
1432 	{
1433 		if (!error)
1434 		{
1435 			boost::system::error_code ec;
1436 			auto ep = conn->GetSocket ().remote_endpoint(ec);
1437 			if (!ec)
1438 			{
1439 				LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
1440 				if (conn)
1441 				{
1442 					conn->SetRemoteEndpoint (ep);
1443 					conn->ServerLogin ();
1444 					m_PendingIncomingSessions.push_back (conn);
1445 				}
1446 			}
1447 			else
1448 				LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
1449 		}
1450 
1451 		if (error != boost::asio::error::operation_aborted)
1452 		{
1453 			conn = std::make_shared<NTCP2Session> (*this);
1454 			m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this,
1455 				conn, std::placeholders::_1));
1456 		}
1457 	}
1458 
ScheduleTermination()1459 	void NTCP2Server::ScheduleTermination ()
1460 	{
1461 		m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP2_TERMINATION_CHECK_TIMEOUT));
1462 		m_TerminationTimer.async_wait (std::bind (&NTCP2Server::HandleTerminationTimer,
1463 			this, std::placeholders::_1));
1464 	}
1465 
HandleTerminationTimer(const boost::system::error_code & ecode)1466 	void NTCP2Server::HandleTerminationTimer (const boost::system::error_code& ecode)
1467 	{
1468 		if (ecode != boost::asio::error::operation_aborted)
1469 		{
1470 			auto ts = i2p::util::GetSecondsSinceEpoch ();
1471 			// established
1472 			for (auto& it: m_NTCP2Sessions)
1473 				if (it.second->IsTerminationTimeoutExpired (ts))
1474 				{
1475 					auto session = it.second;
1476 					LogPrint (eLogDebug, "NTCP2: No activity for ", session->GetTerminationTimeout (), " seconds");
1477 					session->TerminateByTimeout (); // it doesn't change m_NTCP2Session right a way
1478 				}
1479 				else
1480 					it.second->DeleteNextReceiveBuffer (ts);
1481 			// pending
1482 			for (auto it = m_PendingIncomingSessions.begin (); it != m_PendingIncomingSessions.end ();)
1483 			{
1484 				if ((*it)->IsEstablished () || (*it)->IsTerminationTimeoutExpired (ts))
1485 				{
1486 					(*it)->Terminate ();
1487 					it = m_PendingIncomingSessions.erase (it); // established of expired
1488 				}
1489 				else if ((*it)->IsTerminated ())
1490 					it = m_PendingIncomingSessions.erase (it); // already terminated
1491 				else
1492 					it++;
1493 			}
1494 
1495 			ScheduleTermination ();
1496 		}
1497 	}
1498 
ConnectWithProxy(std::shared_ptr<NTCP2Session> conn)1499 	void NTCP2Server::ConnectWithProxy (std::shared_ptr<NTCP2Session> conn)
1500 	{
1501 		if(!m_ProxyEndpoint) return;
1502 		if (!conn || conn->GetRemoteEndpoint ().address ().is_unspecified ())
1503 		{
1504 			LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
1505 			return;
1506 		}
1507 		GetService().post([this, conn]()
1508 		{
1509 			if (this->AddNTCP2Session (conn))
1510 			{
1511 				auto timer = std::make_shared<boost::asio::deadline_timer>(GetService());
1512 				auto timeout = NTCP2_CONNECT_TIMEOUT * 5;
1513 				conn->SetTerminationTimeout(timeout * 2);
1514 				timer->expires_from_now (boost::posix_time::seconds(timeout));
1515 				timer->async_wait ([conn, timeout](const boost::system::error_code& ecode)
1516 				{
1517 					if (ecode != boost::asio::error::operation_aborted)
1518 					{
1519 						LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds");
1520 						conn->Terminate ();
1521 					}
1522 				});
1523 				conn->GetSocket ().async_connect (*m_ProxyEndpoint, std::bind (&NTCP2Server::HandleProxyConnect, this, std::placeholders::_1, conn, timer));
1524 			}
1525 		});
1526 	}
1527 
UseProxy(ProxyType proxytype,const std::string & addr,uint16_t port,const std::string & user,const std::string & pass)1528 	void NTCP2Server::UseProxy(ProxyType proxytype, const std::string& addr, uint16_t port,
1529 		const std::string& user, const std::string& pass)
1530 	{
1531 		m_ProxyType = proxytype;
1532 		m_ProxyAddress = addr;
1533 		m_ProxyPort = port;
1534 		if (m_ProxyType == eHTTPProxy )
1535 			m_ProxyAuthorization = i2p::http::CreateBasicAuthorizationString (user, pass);
1536 	}
1537 
HandleProxyConnect(const boost::system::error_code & ecode,std::shared_ptr<NTCP2Session> conn,std::shared_ptr<boost::asio::deadline_timer> timer)1538 	void NTCP2Server::HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer)
1539 	{
1540 		if (ecode)
1541 		{
1542 			LogPrint(eLogWarning, "NTCP2: Failed to connect to proxy ", ecode.message());
1543 			timer->cancel();
1544 			conn->Terminate();
1545 			return;
1546 		}
1547 		switch (m_ProxyType)
1548 		{
1549 			case eSocksProxy:
1550 			{
1551 				// TODO: support username/password auth etc
1552 				static const uint8_t buff[3] = {0x05, 0x01, 0x00};
1553 				boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(),
1554 					[] (const boost::system::error_code & ec, std::size_t transferred)
1555 					{
1556 						(void) transferred;
1557 						if(ec)
1558 						{
1559 							LogPrint(eLogWarning, "NTCP2: SOCKS5 write error ", ec.message());
1560 						}
1561 					});
1562 				auto readbuff = std::make_shared<std::vector<uint8_t> >(2);
1563 				boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 2),
1564 					[this, readbuff, timer, conn](const boost::system::error_code & ec, std::size_t transferred)
1565 					{
1566 						if(ec)
1567 						{
1568 							LogPrint(eLogError, "NTCP2: SOCKS5 read error ", ec.message());
1569 							timer->cancel();
1570 							conn->Terminate();
1571 							return;
1572 						}
1573 						else if(transferred == 2)
1574 						{
1575 							if((*readbuff)[1] == 0x00)
1576 							{
1577 								AfterSocksHandshake(conn, timer);
1578 								return;
1579 							}
1580 							else if ((*readbuff)[1] == 0xff)
1581 							{
1582 								LogPrint(eLogError, "NTCP2: SOCKS5 proxy rejected authentication");
1583 								timer->cancel();
1584 								conn->Terminate();
1585 								return;
1586 							}
1587 							LogPrint(eLogError, "NTCP2:", (int)(*readbuff)[1]);
1588 						}
1589 						LogPrint(eLogError, "NTCP2: SOCKS5 server gave invalid response");
1590 						timer->cancel();
1591 						conn->Terminate();
1592 					});
1593 				break;
1594 			}
1595 			case eHTTPProxy:
1596 			{
1597 				auto& ep = conn->GetRemoteEndpoint ();
1598 				i2p::http::HTTPReq req;
1599 				req.method = "CONNECT";
1600 				req.version ="HTTP/1.1";
1601 				if(ep.address ().is_v6 ())
1602 					req.uri = "[" + ep.address ().to_string() + "]:" + std::to_string(ep.port ());
1603 				else
1604 					req.uri = ep.address ().to_string() + ":" + std::to_string(ep.port ());
1605 				if (!m_ProxyAuthorization.empty ())
1606 					req.AddHeader("Proxy-Authorization", m_ProxyAuthorization);
1607 
1608 				boost::asio::streambuf writebuff;
1609 				std::ostream out(&writebuff);
1610 				out << req.to_string();
1611 
1612 				boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(),
1613 					[](const boost::system::error_code & ec, std::size_t transferred)
1614 					{
1615 						(void) transferred;
1616 						if(ec)
1617 							LogPrint(eLogError, "NTCP2: HTTP proxy write error ", ec.message());
1618 					});
1619 
1620 				boost::asio::streambuf * readbuff = new boost::asio::streambuf;
1621 				boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n",
1622 					[readbuff, timer, conn] (const boost::system::error_code & ec, std::size_t transferred)
1623 					{
1624 						if(ec)
1625 						{
1626 							LogPrint(eLogError, "NTCP2: HTTP proxy read error ", ec.message());
1627 							timer->cancel();
1628 							conn->Terminate();
1629 						}
1630 						else
1631 						{
1632 							readbuff->commit(transferred);
1633 							i2p::http::HTTPRes res;
1634 							if(res.parse(boost::asio::buffer_cast<const char*>(readbuff->data()), readbuff->size()) > 0)
1635 							{
1636 								if(res.code == 200)
1637 								{
1638 									timer->cancel();
1639 									conn->ClientLogin();
1640 									delete readbuff;
1641 									return;
1642 								}
1643 								else
1644 									LogPrint(eLogError, "NTCP2: HTTP proxy rejected request ", res.code);
1645 							}
1646 							else
1647 								LogPrint(eLogError, "NTCP2: HTTP proxy gave malformed response");
1648 							timer->cancel();
1649 							conn->Terminate();
1650 							delete readbuff;
1651 						}
1652 					});
1653 				break;
1654 			}
1655 			default:
1656 				LogPrint(eLogError, "NTCP2: Unknown proxy type, invalid state");
1657 		}
1658 	}
1659 
AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn,std::shared_ptr<boost::asio::deadline_timer> timer)1660 	void NTCP2Server::AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer)
1661 	{
1662 		// build request
1663 		size_t sz = 6; // header + port
1664 		auto buff = std::make_shared<std::vector<int8_t> >(256);
1665 		auto readbuff = std::make_shared<std::vector<int8_t> >(256);
1666 		(*buff)[0] = 0x05;
1667 		(*buff)[1] = 0x01;
1668 		(*buff)[2] = 0x00;
1669 
1670 		auto& ep = conn->GetRemoteEndpoint ();
1671 		if(ep.address ().is_v4 ())
1672 		{
1673 			(*buff)[3] = 0x01;
1674 			auto addrbytes = ep.address ().to_v4().to_bytes();
1675 			sz += 4;
1676 			memcpy(buff->data () + 4, addrbytes.data(), 4);
1677 		}
1678 		else if (ep.address ().is_v6 ())
1679 		{
1680 			(*buff)[3] = 0x04;
1681 			auto addrbytes = ep.address ().to_v6().to_bytes();
1682 			sz += 16;
1683 			memcpy(buff->data () + 4, addrbytes.data(), 16);
1684 		}
1685 		else
1686 		{
1687 			// We mustn't really fall here because all connections are made to IP addresses
1688 			LogPrint(eLogError, "NTCP2: Tried to connect to unexpected address via proxy");
1689 			return;
1690 		}
1691 		htobe16buf(buff->data () + sz - 2, ep.port ());
1692 		boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff->data (), sz), boost::asio::transfer_all(),
1693 			[buff](const boost::system::error_code & ec, std::size_t written)
1694 			{
1695 				if(ec)
1696 				{
1697 					LogPrint(eLogError, "NTCP2: Failed to write handshake to socks proxy ", ec.message());
1698 					return;
1699 				}
1700 			});
1701 
1702 		boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 10),
1703 			[timer, conn, sz, readbuff](const boost::system::error_code & e, std::size_t transferred)
1704 			{
1705 				if(e)
1706 				{
1707 					LogPrint(eLogError, "NTCP2: SOCKS proxy read error ", e.message());
1708 				}
1709 				else if(transferred == sz)
1710 				{
1711 					if((*readbuff)[1] == 0x00)
1712 					{
1713 						timer->cancel();
1714 						conn->ClientLogin();
1715 						return;
1716 					}
1717 				}
1718 				timer->cancel();
1719 				conn->Terminate();
1720 			});
1721 	}
1722 
SetLocalAddress(const boost::asio::ip::address & localAddress)1723 	void NTCP2Server::SetLocalAddress (const boost::asio::ip::address& localAddress)
1724 	{
1725 		auto addr = std::make_shared<boost::asio::ip::tcp::endpoint>(boost::asio::ip::tcp::endpoint(localAddress, 0));
1726 		if (localAddress.is_v6 ())
1727 		{
1728 			if (i2p::util::net::IsYggdrasilAddress (localAddress))
1729 				m_YggdrasilAddress = addr;
1730 			else
1731 				m_Address6 = addr;
1732 		}
1733 		else
1734 			m_Address4 = addr;
1735 	}
1736 }
1737 }
1738