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 #include <stdio.h>
10 #include <string.h>
11 #include "I2PEndian.h"
12 #include <fstream>
13 #include <boost/lexical_cast.hpp>
14 #include <boost/make_shared.hpp>
15 #if (BOOST_VERSION >= 105300)
16 #include <boost/atomic.hpp>
17 #endif
18 #include "version.h"
19 #include "util.h"
20 #include "Crypto.h"
21 #include "Base.h"
22 #include "Timestamp.h"
23 #include "Log.h"
24 #include "NetDb.hpp"
25 #include "RouterContext.h"
26 #include "RouterInfo.h"
27 
28 namespace i2p
29 {
30 namespace data
31 {
RouterInfo()32 	RouterInfo::RouterInfo (): m_Buffer (nullptr)
33 	{
34 		m_Addresses = boost::make_shared<Addresses>(); // create empty list
35 	}
36 
RouterInfo(const std::string & fullPath)37 	RouterInfo::RouterInfo (const std::string& fullPath):
38 		m_IsUpdated (false), m_IsUnreachable (false), m_SupportedTransports (0),
39 		m_ReachableTransports (0), m_Caps (0), m_Version (0)
40 	{
41 		m_Addresses = boost::make_shared<Addresses>(); // create empty list
42 		m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
43 		ReadFromFile (fullPath);
44 	}
45 
RouterInfo(const uint8_t * buf,int len)46 	RouterInfo::RouterInfo (const uint8_t * buf, int len):
47 		m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0),
48 		m_ReachableTransports (0), m_Caps (0), m_Version (0)
49 	{
50 		m_Addresses = boost::make_shared<Addresses>(); // create empty list
51 		if (len <= MAX_RI_BUFFER_SIZE)
52 		{
53 			m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
54 			memcpy (m_Buffer, buf, len);
55 			m_BufferLen = len;
56 			ReadFromBuffer (true);
57 		}
58 		else
59 		{
60 			LogPrint (eLogError, "RouterInfo: Buffer is too long ", len, ". Ignored");
61 			m_Buffer = nullptr;
62 			m_IsUnreachable = true;
63 		}
64 	}
65 
~RouterInfo()66 	RouterInfo::~RouterInfo ()
67 	{
68 		delete[] m_Buffer;
69 	}
70 
Update(const uint8_t * buf,size_t len)71 	void RouterInfo::Update (const uint8_t * buf, size_t len)
72 	{
73 		if (len > MAX_RI_BUFFER_SIZE)
74 		{
75 			LogPrint (eLogError, "RouterInfo: Buffer is too long ", len);
76 			m_IsUnreachable = true;
77 			return;
78 		}
79 		// verify signature since we have identity already
80 		int l = len - m_RouterIdentity->GetSignatureLen ();
81 		if (m_RouterIdentity->Verify (buf, l, buf + l))
82 		{
83 			// clean up
84 			m_IsUpdated = true;
85 			m_IsUnreachable = false;
86 			m_SupportedTransports = 0;
87 			m_ReachableTransports = 0;
88 			m_Caps = 0;
89 			// don't clean up m_Addresses, it will be replaced in ReadFromStream
90 			m_Properties.clear ();
91 			// copy buffer
92 			if (!m_Buffer)
93 				m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
94 			memcpy (m_Buffer, buf, len);
95 			m_BufferLen = len;
96 			// skip identity
97 			size_t identityLen = m_RouterIdentity->GetFullLen ();
98 			// read new RI
99 			std::stringstream str (std::string ((char *)m_Buffer + identityLen, m_BufferLen - identityLen));
100 			ReadFromStream (str);
101 			// don't delete buffer until saved to the file
102 		}
103 		else
104 		{
105 			LogPrint (eLogError, "RouterInfo: Signature verification failed");
106 			m_IsUnreachable = true;
107 		}
108 	}
109 
SetRouterIdentity(std::shared_ptr<const IdentityEx> identity)110 	void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
111 	{
112 		m_RouterIdentity = identity;
113 		m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
114 	}
115 
LoadFile(const std::string & fullPath)116 	bool RouterInfo::LoadFile (const std::string& fullPath)
117 	{
118 		std::ifstream s(fullPath, std::ifstream::binary);
119 		if (s.is_open ())
120 		{
121 			s.seekg (0,std::ios::end);
122 			m_BufferLen = s.tellg ();
123 			if (m_BufferLen < 40 || m_BufferLen > MAX_RI_BUFFER_SIZE)
124 			{
125 				LogPrint(eLogError, "RouterInfo: File", fullPath, " is malformed");
126 				return false;
127 			}
128 			s.seekg(0, std::ios::beg);
129 			if (!m_Buffer) m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
130 			s.read((char *)m_Buffer, m_BufferLen);
131 		}
132 		else
133 		{
134 			LogPrint (eLogError, "RouterInfo: Can't open file ", fullPath);
135 			return false;
136 		}
137 		return true;
138 	}
139 
ReadFromFile(const std::string & fullPath)140 	void RouterInfo::ReadFromFile (const std::string& fullPath)
141 	{
142 		if (LoadFile (fullPath))
143 			ReadFromBuffer (false);
144 		else
145 			m_IsUnreachable = true;
146 	}
147 
ReadFromBuffer(bool verifySignature)148 	void RouterInfo::ReadFromBuffer (bool verifySignature)
149 	{
150 		m_RouterIdentity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
151 		size_t identityLen = m_RouterIdentity->GetFullLen ();
152 		if (identityLen >= m_BufferLen)
153 		{
154 			LogPrint (eLogError, "RouterInfo: Identity length ", identityLen, " exceeds buffer size ", m_BufferLen);
155 			m_IsUnreachable = true;
156 			return;
157 		}
158 		if (verifySignature)
159 		{
160 			// reject RSA signatures
161 			if (m_RouterIdentity->IsRSA ())
162 			{
163 				LogPrint (eLogError, "RouterInfo: RSA signature type is not allowed");
164 				m_IsUnreachable = true;
165 				return;
166 			}
167 			// verify signature
168 			int l = m_BufferLen - m_RouterIdentity->GetSignatureLen ();
169 			if (l < 0 || !m_RouterIdentity->Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l))
170 			{
171 				LogPrint (eLogError, "RouterInfo: Signature verification failed");
172 				m_IsUnreachable = true;
173 				return;
174 			}
175 			m_RouterIdentity->DropVerifier ();
176 		}
177 		// parse RI
178 		std::stringstream str;
179 		str.write ((const char *)m_Buffer + identityLen, m_BufferLen - identityLen);
180 		ReadFromStream (str);
181 		if (!str)
182 		{
183 			LogPrint (eLogError, "RouterInfo: Malformed message");
184 			m_IsUnreachable = true;
185 		}
186 	}
187 
ReadFromStream(std::istream & s)188 	void RouterInfo::ReadFromStream (std::istream& s)
189 	{
190 		if (!s) return;
191 		m_Caps = 0;
192 		s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
193 		m_Timestamp = be64toh (m_Timestamp);
194 		// read addresses
195 		auto addresses = boost::make_shared<Addresses>();
196 		uint8_t numAddresses;
197 		s.read ((char *)&numAddresses, sizeof (numAddresses));
198 		addresses->reserve (numAddresses);
199 		for (int i = 0; i < numAddresses; i++)
200 		{
201 			uint8_t supportedTransports = 0;
202 			auto address = std::make_shared<Address>();
203 			uint8_t cost; // ignore
204 			s.read ((char *)&cost, sizeof (cost));
205 			s.read ((char *)&address->date, sizeof (address->date));
206 			bool isHost = false, isIntroKey = false, isStaticKey = false;
207 			char transportStyle[6];
208 			ReadString (transportStyle, 6, s);
209 			if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2
210 			{
211 				address->transportStyle = eTransportNTCP;
212 				address->ntcp2.reset (new NTCP2Ext ());
213 			}
214 			else if (!strcmp (transportStyle, "SSU"))
215 			{
216 				address->transportStyle = eTransportSSU;
217 				address->ssu.reset (new SSUExt ());
218 				address->ssu->mtu = 0;
219 			}
220 			else
221 				address->transportStyle = eTransportUnknown;
222 			address->caps = 0;
223 			address->port = 0;
224 			uint16_t size, r = 0;
225 			s.read ((char *)&size, sizeof (size)); if (!s) return;
226 			size = be16toh (size);
227 			while (r < size)
228 			{
229 				char key[255], value[255];
230 				r += ReadString (key, 255, s);
231 				s.seekg (1, std::ios_base::cur); r++; // =
232 				r += ReadString (value, 255, s);
233 				s.seekg (1, std::ios_base::cur); r++; // ;
234 				if (!s) return;
235 				if (!strcmp (key, "host"))
236 				{
237 					boost::system::error_code ecode;
238 					address->host = boost::asio::ip::address::from_string (value, ecode);
239 					if (!ecode && !address->host.is_unspecified ()) isHost = true;
240 				}
241 				else if (!strcmp (key, "port"))
242 					address->port = boost::lexical_cast<int>(value);
243 				else if (!strcmp (key, "mtu"))
244 				{
245 					if (address->ssu)
246 						address->ssu->mtu = boost::lexical_cast<int>(value);
247 					else
248 						LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP");
249 				}
250 				else if (!strcmp (key, "key"))
251 				{
252 					if (address->ssu)
253 						isIntroKey = (Base64ToByteStream (value, strlen (value), address->ssu->key, 32) == 32);
254 					else
255 						LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP");
256 				}
257 				else if (!strcmp (key, "caps"))
258 					address->caps = ExtractAddressCaps (value);
259 				else if (!strcmp (key, "s")) // ntcp2 static key
260 				{
261 					Base64ToByteStream (value, strlen (value), address->ntcp2->staticKey, 32);
262 					isStaticKey = true;
263 				}
264 				else if (!strcmp (key, "i")) // ntcp2 iv
265 				{
266 					Base64ToByteStream (value, strlen (value), address->ntcp2->iv, 16);
267 					address->published = true; // presence if "i" means "published"
268 				}
269 				else if (key[0] == 'i')
270 				{
271 					// introducers
272 					if (!address->ssu)
273 					{
274 						LogPrint (eLogError, "RouterInfo: Introducer is presented for non-SSU address. Skipped");
275 						continue;
276 					}
277 					size_t l = strlen(key);
278 					unsigned char index = key[l-1] - '0'; // TODO:
279 					key[l-1] = 0;
280 					if (index > 9)
281 					{
282 						LogPrint (eLogError, "RouterInfo: Unexpected introducer's index ", index, " skipped");
283 						if (s) continue; else return;
284 					}
285 					if (index >= address->ssu->introducers.size ())
286 					{
287 						if (address->ssu->introducers.empty ()) // first time
288 							address->ssu->introducers.reserve (3);
289 						address->ssu->introducers.resize (index + 1);
290 					}
291 					Introducer& introducer = address->ssu->introducers.at (index);
292 					if (!strcmp (key, "ihost"))
293 					{
294 						boost::system::error_code ecode;
295 						introducer.iHost = boost::asio::ip::address::from_string (value, ecode);
296 					}
297 					else if (!strcmp (key, "iport"))
298 						introducer.iPort = boost::lexical_cast<int>(value);
299 					else if (!strcmp (key, "itag"))
300 						introducer.iTag = boost::lexical_cast<uint32_t>(value);
301 					else if (!strcmp (key, "ikey"))
302 						Base64ToByteStream (value, strlen (value), introducer.iKey, 32);
303 					else if (!strcmp (key, "iexp"))
304 						introducer.iExp = boost::lexical_cast<uint32_t>(value);
305 				}
306 				if (!s) return;
307 			}
308 			if (address->transportStyle == eTransportNTCP)
309 			{
310 				if (isStaticKey)
311 				{
312 					if (isHost)
313 					{
314 						if (address->host.is_v6 ())
315 							supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh :  eNTCP2V6);
316 						else
317 							supportedTransports |= eNTCP2V4;
318 						m_ReachableTransports |= supportedTransports;
319 					}
320 					else if (!address->published)
321 					{
322 						if (address->caps)
323 						{
324 							if (address->caps & AddressCaps::eV4) supportedTransports |= eNTCP2V4;
325 							if (address->caps & AddressCaps::eV6) supportedTransports |= eNTCP2V6;
326 						}
327 						else
328 							supportedTransports |= eNTCP2V4; // most likely, since we don't have host
329 					}
330 				}
331 			}
332 			else if (address->transportStyle == eTransportSSU)
333 			{
334 				if (isIntroKey)
335 				{
336 					if (isHost)
337 						supportedTransports |= address->host.is_v4 () ? eSSUV4 :  eSSUV6;
338 					else if (address->caps & AddressCaps::eV6)
339 					{
340 						supportedTransports |= eSSUV6;
341 						if (address->caps & AddressCaps::eV4) supportedTransports |= eSSUV4; // in additional to v6
342 					}
343 					else
344 						supportedTransports |= eSSUV4; // in case if host or 6 caps is not preasented, we assume 4
345 					if (address->ssu && !address->ssu->introducers.empty ())
346 					{
347 						// exclude invalid introducers
348 						uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
349 						int numValid = 0;
350 						for (auto& it: address->ssu->introducers)
351 						{
352 							if (!it.iExp) it.iExp = m_Timestamp/1000 + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT;
353 							if (ts <= it.iExp && it.iPort > 0 &&
354 							    ((it.iHost.is_v4 () && address->IsV4 ()) || (it.iHost.is_v6 () && address->IsV6 ())))
355 								numValid++;
356 							else
357 								it.iPort = 0;
358 						}
359 						if (numValid)
360 							m_ReachableTransports |= supportedTransports;
361 						else
362 							address->ssu->introducers.resize (0);
363 					}
364 					else if (isHost && address->port)
365 					{
366 						address->published = true;
367 						m_ReachableTransports |= supportedTransports;
368 					}
369 				}
370 			}
371 			if (supportedTransports)
372 			{
373 				addresses->push_back(address);
374 				m_SupportedTransports |= supportedTransports;
375 			}
376 		}
377 #if (BOOST_VERSION >= 105300)
378 		boost::atomic_store (&m_Addresses, addresses);
379 #else
380 		m_Addresses = addresses; // race condition
381 #endif
382 		// read peers
383 		uint8_t numPeers;
384 		s.read ((char *)&numPeers, sizeof (numPeers)); if (!s) return;
385 		s.seekg (numPeers*32, std::ios_base::cur); // TODO: read peers
386 		// read properties
387 		uint16_t size, r = 0;
388 		s.read ((char *)&size, sizeof (size)); if (!s) return;
389 		size = be16toh (size);
390 		while (r < size)
391 		{
392 			char key[255], value[255];
393 			r += ReadString (key, 255, s);
394 			s.seekg (1, std::ios_base::cur); r++; // =
395 			r += ReadString (value, 255, s);
396 			s.seekg (1, std::ios_base::cur); r++; // ;
397 			if (!s) return;
398 			m_Properties[key] = value;
399 
400 			// extract caps
401 			if (!strcmp (key, "caps"))
402 				ExtractCaps (value);
403 			// extract version
404 			else if (!strcmp (key, ROUTER_INFO_PROPERTY_VERSION))
405 			{
406 				m_Version = 0;
407 				char * ch = value;
408 				while (*ch)
409 				{
410 					if (*ch >= '0' && *ch <= '9')
411 					{
412 						m_Version *= 10;
413 						m_Version += (*ch - '0');
414 					}
415 					ch++;
416 				}
417 			}
418 			// check netId
419 			else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID) && atoi (value) != i2p::context.GetNetID ())
420 			{
421 				LogPrint (eLogError, "RouterInfo: Unexpected ", ROUTER_INFO_PROPERTY_NETID, "=", value);
422 				m_IsUnreachable = true;
423 			}
424 			// family
425 			else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY))
426 			{
427 				m_Family = value;
428 				boost::to_lower (m_Family);
429 			}
430 			else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY_SIG))
431 			{
432 				if (!netdb.GetFamilies ().VerifyFamily (m_Family, GetIdentHash (), value))
433 				{
434 					LogPrint (eLogWarning, "RouterInfo: Family signature verification failed");
435 					m_Family.clear ();
436 				}
437 			}
438 
439 			if (!s) return;
440 		}
441 
442 		if (!m_SupportedTransports)
443 			SetUnreachable (true);
444 	}
445 
IsFamily(const std::string & fam) const446 	bool RouterInfo::IsFamily(const std::string & fam) const
447 	{
448 		return m_Family == fam;
449 	}
450 
ExtractCaps(const char * value)451 	void RouterInfo::ExtractCaps (const char * value)
452 	{
453 		const char * cap = value;
454 		while (*cap)
455 		{
456 			switch (*cap)
457 			{
458 				case CAPS_FLAG_FLOODFILL:
459 					m_Caps |= Caps::eFloodfill;
460 				break;
461 				case CAPS_FLAG_HIGH_BANDWIDTH1:
462 				case CAPS_FLAG_HIGH_BANDWIDTH2:
463 				case CAPS_FLAG_HIGH_BANDWIDTH3:
464 					m_Caps |= Caps::eHighBandwidth;
465 				break;
466 				case CAPS_FLAG_EXTRA_BANDWIDTH1:
467 				case CAPS_FLAG_EXTRA_BANDWIDTH2:
468 					m_Caps |= Caps::eExtraBandwidth | Caps::eHighBandwidth;
469 				break;
470 				case CAPS_FLAG_HIDDEN:
471 					m_Caps |= Caps::eHidden;
472 				break;
473 				case CAPS_FLAG_REACHABLE:
474 					m_Caps |= Caps::eReachable;
475 				break;
476 				case CAPS_FLAG_UNREACHABLE:
477 					m_Caps |= Caps::eUnreachable;
478 				break;
479 				default: ;
480 			}
481 			cap++;
482 		}
483 	}
484 
ExtractAddressCaps(const char * value) const485 	uint8_t RouterInfo::ExtractAddressCaps (const char * value) const
486 	{
487 		uint8_t caps = 0;
488 		const char * cap = value;
489 		while (*cap)
490 		{
491 			switch (*cap)
492 			{
493 				case CAPS_FLAG_V4:
494 					caps |= AddressCaps::eV4;
495 				break;
496 				case CAPS_FLAG_V6:
497 					caps |= AddressCaps::eV6;
498 				break;
499 				case CAPS_FLAG_SSU_TESTING:
500 					caps |= AddressCaps::eSSUTesting;
501 				break;
502 				case CAPS_FLAG_SSU_INTRODUCER:
503 					caps |= AddressCaps::eSSUIntroducer;
504 				break;
505 				default: ;
506 			}
507 			cap++;
508 		}
509 		return caps;
510 	}
511 
UpdateCapsProperty()512 	void RouterInfo::UpdateCapsProperty ()
513 	{
514 		std::string caps;
515 		if (m_Caps & eFloodfill)
516 		{
517 			if (m_Caps & eExtraBandwidth) caps += (m_Caps & eHighBandwidth) ?
518 				CAPS_FLAG_EXTRA_BANDWIDTH2 : // 'X'
519 				CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P'
520 			else
521 				caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
522 			caps += CAPS_FLAG_FLOODFILL; // floodfill
523 		}
524 		else
525 		{
526 			if (m_Caps & eExtraBandwidth)
527 				caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_EXTRA_BANDWIDTH2 /* 'X' */ : CAPS_FLAG_EXTRA_BANDWIDTH1; /*'P' */
528 			else
529 				caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth
530 		}
531 		if (m_Caps & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden
532 		if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
533 		if (m_Caps & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
534 
535 		SetProperty ("caps", caps);
536 	}
537 
WriteToStream(std::ostream & s) const538 	void RouterInfo::WriteToStream (std::ostream& s) const
539 	{
540 		uint64_t ts = htobe64 (m_Timestamp);
541 		s.write ((const char *)&ts, sizeof (ts));
542 
543 		// addresses
544 		uint8_t numAddresses = m_Addresses->size ();
545 		s.write ((char *)&numAddresses, sizeof (numAddresses));
546 		for (const auto& addr_ptr : *m_Addresses)
547 		{
548 			const Address& address = *addr_ptr;
549 			// calculate cost
550 			uint8_t cost = 0x7f;
551 			if (address.transportStyle == eTransportNTCP)
552 				cost = address.published ? COST_NTCP2_PUBLISHED : COST_NTCP2_NON_PUBLISHED;
553 			else if (address.transportStyle == eTransportSSU)
554 				cost = address.published ? COST_SSU_DIRECT : COST_SSU_THROUGH_INTRODUCERS;
555 			s.write ((const char *)&cost, sizeof (cost));
556 			s.write ((const char *)&address.date, sizeof (address.date));
557 			std::stringstream properties;
558 			bool isPublished = false;
559 			if (address.transportStyle == eTransportNTCP)
560 			{
561 				if (address.IsNTCP2 ())
562 				{
563 					WriteString ("NTCP2", s);
564 					if (address.IsPublishedNTCP2 () && !address.host.is_unspecified () && address.port)
565 						 isPublished = true;
566 					else
567 					{
568 						WriteString ("caps", properties);
569 						properties << '=';
570 						std::string caps;
571 						if (address.IsV4 ()) caps += CAPS_FLAG_V4;
572 						if (address.IsV6 ()) caps += CAPS_FLAG_V6;
573 						if (caps.empty ()) caps += CAPS_FLAG_V4;
574 						WriteString (caps, properties);
575 						properties << ';';
576 					}
577 				}
578 				else
579 					continue; // don't write NTCP address
580 			}
581 			else if (address.transportStyle == eTransportSSU)
582 			{
583 				WriteString ("SSU", s);
584 				// caps
585 				WriteString ("caps", properties);
586 				properties << '=';
587 				std::string caps;
588 				if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING;
589 				if (address.host.is_v4 ())
590 				{
591 					if (address.published)
592 					{
593 						isPublished = true;
594 						if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
595 					}
596 					else
597 						caps += CAPS_FLAG_V4;
598 				}
599 				else if (address.host.is_v6 ())
600 				{
601 					if (address.published)
602 					{
603 						isPublished = true;
604 						if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
605 					}
606 					else
607 						caps += CAPS_FLAG_V6;
608 				}
609 				else
610 				{
611 					if (address.IsV4 ()) caps += CAPS_FLAG_V4;
612 					if (address.IsV6 ()) caps += CAPS_FLAG_V6;
613 					if (caps.empty ()) caps += CAPS_FLAG_V4;
614 				}
615 				WriteString (caps, properties);
616 				properties << ';';
617 			}
618 			else
619 				WriteString ("", s);
620 
621 			if (isPublished)
622 			{
623 				WriteString ("host", properties);
624 				properties << '=';
625 				WriteString (address.host.to_string (), properties);
626 				properties << ';';
627 			}
628 			if (address.transportStyle == eTransportSSU)
629 			{
630 				// write introducers if any
631 				if (!address.ssu->introducers.empty())
632 				{
633 					int i = 0;
634 					for (const auto& introducer: address.ssu->introducers)
635 					{
636 						if (introducer.iExp) // expiration is specified
637 						{
638 							WriteString ("iexp" + boost::lexical_cast<std::string>(i), properties);
639 							properties << '=';
640 							WriteString (boost::lexical_cast<std::string>(introducer.iExp), properties);
641 							properties << ';';
642 						}
643 						i++;
644 					}
645 					i = 0;
646 					for (const auto& introducer: address.ssu->introducers)
647 					{
648 						WriteString ("ihost" + boost::lexical_cast<std::string>(i), properties);
649 						properties << '=';
650 						WriteString (introducer.iHost.to_string (), properties);
651 						properties << ';';
652 						i++;
653 					}
654 					i = 0;
655 					for (const auto& introducer: address.ssu->introducers)
656 					{
657 						WriteString ("ikey" + boost::lexical_cast<std::string>(i), properties);
658 						properties << '=';
659 						char value[64];
660 						size_t l = ByteStreamToBase64 (introducer.iKey, 32, value, 64);
661 						value[l] = 0;
662 						WriteString (value, properties);
663 						properties << ';';
664 						i++;
665 					}
666 					i = 0;
667 					for (const auto& introducer: address.ssu->introducers)
668 					{
669 						WriteString ("iport" + boost::lexical_cast<std::string>(i), properties);
670 						properties << '=';
671 						WriteString (boost::lexical_cast<std::string>(introducer.iPort), properties);
672 						properties << ';';
673 						i++;
674 					}
675 					i = 0;
676 					for (const auto& introducer: address.ssu->introducers)
677 					{
678 						WriteString ("itag" + boost::lexical_cast<std::string>(i), properties);
679 						properties << '=';
680 						WriteString (boost::lexical_cast<std::string>(introducer.iTag), properties);
681 						properties << ';';
682 						i++;
683 					}
684 				}
685 				// write intro key
686 				WriteString ("key", properties);
687 				properties << '=';
688 				char value[64];
689 				size_t l = ByteStreamToBase64 (address.ssu->key, 32, value, 64);
690 				value[l] = 0;
691 				WriteString (value, properties);
692 				properties << ';';
693 				// write mtu
694 				if (address.ssu->mtu)
695 				{
696 					WriteString ("mtu", properties);
697 					properties << '=';
698 					WriteString (boost::lexical_cast<std::string>(address.ssu->mtu), properties);
699 					properties << ';';
700 				}
701 			}
702 
703 			if (address.IsNTCP2 () && isPublished)
704 			{
705 				// publish i for NTCP2
706 				WriteString ("i", properties); properties << '=';
707 				WriteString (address.ntcp2->iv.ToBase64 (), properties); properties << ';';
708 			}
709 
710 			if (isPublished || address.ssu)
711 			{
712 				WriteString ("port", properties);
713 				properties << '=';
714 				WriteString (boost::lexical_cast<std::string>(address.port), properties);
715 				properties << ';';
716 			}
717 			if (address.IsNTCP2 ())
718 			{
719 				// publish s and v for NTCP2
720 				WriteString ("s", properties); properties << '=';
721 				WriteString (address.ntcp2->staticKey.ToBase64 (), properties); properties << ';';
722 				WriteString ("v", properties); properties << '=';
723 				WriteString ("2", properties); properties << ';';
724 			}
725 
726 			uint16_t size = htobe16 (properties.str ().size ());
727 			s.write ((char *)&size, sizeof (size));
728 			s.write (properties.str ().c_str (), properties.str ().size ());
729 		}
730 
731 		// peers
732 		uint8_t numPeers = 0;
733 		s.write ((char *)&numPeers, sizeof (numPeers));
734 
735 		// properties
736 		std::stringstream properties;
737 		for (const auto& p : m_Properties)
738 		{
739 			WriteString (p.first, properties);
740 			properties << '=';
741 			WriteString (p.second, properties);
742 			properties << ';';
743 		}
744 		uint16_t size = htobe16 (properties.str ().size ());
745 		s.write ((char *)&size, sizeof (size));
746 		s.write (properties.str ().c_str (), properties.str ().size ());
747 	}
748 
IsNewer(const uint8_t * buf,size_t len) const749 	bool RouterInfo::IsNewer (const uint8_t * buf, size_t len) const
750 	{
751 		if (!m_RouterIdentity) return false;
752 		size_t size = m_RouterIdentity->GetFullLen ();
753 		if (size + 8 > len) return false;
754 		return bufbe64toh (buf + size) > m_Timestamp;
755 	}
756 
LoadBuffer(const std::string & fullPath)757 	const uint8_t * RouterInfo::LoadBuffer (const std::string& fullPath)
758 	{
759 		if (!m_Buffer)
760 		{
761 			if (LoadFile (fullPath))
762 				LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
763 		}
764 		return m_Buffer;
765 	}
766 
CreateBuffer(const PrivateKeys & privateKeys)767 	void RouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
768 	{
769 		m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); // refresh timstamp
770 		std::stringstream s;
771 		uint8_t ident[1024];
772 		auto identLen = privateKeys.GetPublic ()->ToBuffer (ident, 1024);
773 		auto signatureLen = privateKeys.GetPublic ()->GetSignatureLen ();
774 		s.write ((char *)ident, identLen);
775 		WriteToStream (s);
776 		m_BufferLen = s.str ().size ();
777 		if (!m_Buffer)
778 			m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
779 		if (m_BufferLen + signatureLen < MAX_RI_BUFFER_SIZE)
780 		{
781 			memcpy (m_Buffer, s.str ().c_str (), m_BufferLen);
782 			// signature
783 			privateKeys.Sign ((uint8_t *)m_Buffer, m_BufferLen, (uint8_t *)m_Buffer + m_BufferLen);
784 			m_BufferLen += signatureLen;
785 		}
786 		else
787 			LogPrint (eLogError, "RouterInfo: Our RouterInfo is too long ", m_BufferLen + signatureLen);
788 	}
789 
SaveToFile(const std::string & fullPath)790 	bool RouterInfo::SaveToFile (const std::string& fullPath)
791 	{
792 		if (!m_Buffer)
793 		{
794 			LogPrint (eLogError, "RouterInfo: Can't save, m_Buffer == NULL");
795 			return false;
796 		}
797 		std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
798 		if (!f.is_open ()) {
799 			LogPrint(eLogError, "RouterInfo: Can't save to ", fullPath);
800 			return false;
801 		}
802 		f.write ((char *)m_Buffer, m_BufferLen);
803 		return true;
804 	}
805 
ReadString(char * str,size_t len,std::istream & s) const806 	size_t RouterInfo::ReadString (char * str, size_t len, std::istream& s) const
807 	{
808 		uint8_t l;
809 		s.read ((char *)&l, 1);
810 		if (l < len)
811 		{
812 			s.read (str, l);
813 			if (!s) l = 0; // failed, return empty string
814 			str[l] = 0;
815 		}
816 		else
817 		{
818 			LogPrint (eLogWarning, "RouterInfo: String length ", (int)l, " exceeds buffer size ", len);
819 			s.seekg (l, std::ios::cur); // skip
820 			str[0] = 0;
821 		}
822 		return l+1;
823 	}
824 
WriteString(const std::string & str,std::ostream & s) const825 	void RouterInfo::WriteString (const std::string& str, std::ostream& s) const
826 	{
827 		uint8_t len = str.size ();
828 		s.write ((char *)&len, 1);
829 		s.write (str.c_str (), len);
830 	}
831 
AddSSUAddress(const char * host,int port,const uint8_t * key,int mtu)832 	void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu)
833 	{
834 		auto addr = std::make_shared<Address>();
835 		addr->host = boost::asio::ip::address::from_string (host);
836 		addr->port = port;
837 		addr->transportStyle = eTransportSSU;
838 		addr->published = true;
839 		addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
840 		addr->date = 0;
841 		addr->ssu.reset (new SSUExt ());
842 		addr->ssu->mtu = mtu;
843 		if (key)
844 			memcpy (addr->ssu->key, key, 32);
845 		else
846 			RAND_bytes (addr->ssu->key, 32);
847 		for (const auto& it: *m_Addresses) // don't insert same address twice
848 			if (*it == *addr) return;
849 		m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
850 		m_ReachableTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
851 		m_Addresses->push_back(std::move(addr));
852 	}
853 
AddNTCP2Address(const uint8_t * staticKey,const uint8_t * iv,const boost::asio::ip::address & host,int port,uint8_t caps)854 	void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
855 		const boost::asio::ip::address& host, int port, uint8_t caps)
856 	{
857 		auto addr = std::make_shared<Address>();
858 		addr->host = host;
859 		addr->port = port;
860 		addr->transportStyle = eTransportNTCP;
861 		addr->caps = caps;
862 		addr->date = 0;
863 		addr->ntcp2.reset (new NTCP2Ext ());
864 		if (port) addr->published = true;
865 		memcpy (addr->ntcp2->staticKey, staticKey, 32);
866 		memcpy (addr->ntcp2->iv, iv, 16);
867 		if (addr->IsV4 ())
868 		{
869 			m_SupportedTransports |= eNTCP2V4;
870 			if (addr->published) m_ReachableTransports |= eNTCP2V4;
871 		}
872 		if (addr->IsV6 ())
873 		{
874 			m_SupportedTransports |= eNTCP2V6;
875 			if (addr->published) m_ReachableTransports |= eNTCP2V6;
876 		}
877 		m_Addresses->push_back(std::move(addr));
878 	}
879 
AddIntroducer(const Introducer & introducer)880 	bool RouterInfo::AddIntroducer (const Introducer& introducer)
881 	{
882 		for (auto& addr : *m_Addresses)
883 		{
884 			if (addr->transportStyle == eTransportSSU &&
885 			   ((addr->IsV4 () && introducer.iHost.is_v4 ()) || (addr->IsV6 () && introducer.iHost.is_v6 ())))
886 			{
887 				for (auto& intro: addr->ssu->introducers)
888 					if (intro.iTag == introducer.iTag) return false; // already presented
889 				addr->ssu->introducers.push_back (introducer);
890 				m_ReachableTransports |= (addr->IsV4 () ? eSSUV4 : eSSUV6);
891 				return true;
892 			}
893 		}
894 		return false;
895 	}
896 
RemoveIntroducer(const boost::asio::ip::udp::endpoint & e)897 	bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
898 	{
899 		for (auto& addr: *m_Addresses)
900 		{
901 			if (addr->transportStyle == eTransportSSU &&
902 			   ((addr->IsV4 () && e.address ().is_v4 ()) || (addr->IsV6 () && e.address ().is_v6 ())))
903 			{
904 				for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
905 					if (boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e)
906 					{
907 						addr->ssu->introducers.erase (it);
908 						if (addr->ssu->introducers.empty ())
909 							m_ReachableTransports &= ~(addr->IsV4 () ? eSSUV4 : eSSUV6);
910 						return true;
911 					}
912 			}
913 		}
914 		return false;
915 	}
916 
SetCaps(uint8_t caps)917 	void RouterInfo::SetCaps (uint8_t caps)
918 	{
919 		m_Caps = caps;
920 		UpdateCapsProperty ();
921 	}
922 
SetCaps(const char * caps)923 	void RouterInfo::SetCaps (const char * caps)
924 	{
925 		SetProperty ("caps", caps);
926 		m_Caps = 0;
927 		ExtractCaps (caps);
928 	}
929 
SetProperty(const std::string & key,const std::string & value)930 	void RouterInfo::SetProperty (const std::string& key, const std::string& value)
931 	{
932 		m_Properties[key] = value;
933 	}
934 
DeleteProperty(const std::string & key)935 	void RouterInfo::DeleteProperty (const std::string& key)
936 	{
937 		m_Properties.erase (key);
938 	}
939 
GetProperty(const std::string & key) const940 	std::string RouterInfo::GetProperty (const std::string& key) const
941 	{
942 		auto it = m_Properties.find (key);
943 		if (it != m_Properties.end ())
944 			return it->second;
945 		return "";
946 	}
947 
IsSSU(bool v4only) const948 	bool RouterInfo::IsSSU (bool v4only) const
949 	{
950 		if (v4only)
951 			return m_SupportedTransports & eSSUV4;
952 		else
953 			return m_SupportedTransports & (eSSUV4 | eSSUV6);
954 	}
955 
IsSSUV6() const956 	bool RouterInfo::IsSSUV6 () const
957 	{
958 		return m_SupportedTransports & eSSUV6;
959 	}
960 
IsNTCP2(bool v4only) const961 	bool RouterInfo::IsNTCP2 (bool v4only) const
962 	{
963 		if (v4only)
964 			return m_SupportedTransports & eNTCP2V4;
965 		else
966 			return m_SupportedTransports & (eNTCP2V4 | eNTCP2V6);
967 	}
968 
IsNTCP2V6() const969 	bool RouterInfo::IsNTCP2V6 () const
970 	{
971 		return m_SupportedTransports & eNTCP2V6;
972 	}
973 
IsV6() const974 	bool RouterInfo::IsV6 () const
975 	{
976 		return m_SupportedTransports & (eSSUV6 | eNTCP2V6);
977 	}
978 
IsV4() const979 	bool RouterInfo::IsV4 () const
980 	{
981 		return m_SupportedTransports & (eSSUV4 | eNTCP2V4);
982 	}
983 
IsMesh() const984 	bool RouterInfo::IsMesh () const
985 	{
986 		return m_SupportedTransports & eNTCP2V6Mesh;
987 	}
988 
EnableV6()989 	void RouterInfo::EnableV6 ()
990 	{
991 		if (!IsV6 ())
992 		{
993 			uint8_t addressCaps = AddressCaps::eV6;
994 			if (IsV4 ()) addressCaps |= AddressCaps::eV4;
995 			SetUnreachableAddressesTransportCaps (addressCaps);
996 			UpdateSupportedTransports ();
997 		}
998 	}
999 
EnableV4()1000 	void RouterInfo::EnableV4 ()
1001 	{
1002 		if (!IsV4 ())
1003 		{
1004 			uint8_t addressCaps = AddressCaps::eV4;
1005 			if (IsV6 ()) addressCaps |= AddressCaps::eV6;
1006 			SetUnreachableAddressesTransportCaps (addressCaps);
1007 			UpdateSupportedTransports ();
1008 		}
1009 	}
1010 
1011 
DisableV6()1012 	void RouterInfo::DisableV6 ()
1013 	{
1014 		if (IsV6 ())
1015 		{
1016 			for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
1017 			{
1018 				auto addr = *it;
1019 				if (addr->IsV6 ())
1020 				{
1021 					if (addr->IsV4 ())
1022 					{
1023 						addr->caps &= ~AddressCaps::eV6;
1024 						++it;
1025 					}
1026 					else
1027 						it = m_Addresses->erase (it);
1028 				}
1029 				else
1030 					++it;
1031 			}
1032 			UpdateSupportedTransports ();
1033 		}
1034 	}
1035 
DisableV4()1036 	void RouterInfo::DisableV4 ()
1037 	{
1038 		if (IsV4 ())
1039 		{
1040 			for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
1041 			{
1042 				auto addr = *it;
1043 				if (addr->IsV4 ())
1044 				{
1045 					if (addr->IsV6 ())
1046 					{
1047 						addr->caps &= ~AddressCaps::eV4;
1048 						++it;
1049 					}
1050 					else
1051 						it = m_Addresses->erase (it);
1052 				}
1053 				else
1054 					++it;
1055 			}
1056 			UpdateSupportedTransports ();
1057 		}
1058 	}
1059 
EnableMesh()1060 	void RouterInfo::EnableMesh ()
1061 	{
1062 		if (!IsMesh ())
1063 		{
1064 			m_SupportedTransports |= eNTCP2V6Mesh;
1065 			m_ReachableTransports |= eNTCP2V6Mesh;
1066 		}
1067 	}
1068 
DisableMesh()1069 	void RouterInfo::DisableMesh ()
1070 	{
1071 		if (IsMesh ())
1072 		{
1073 			m_SupportedTransports &= ~eNTCP2V6Mesh;
1074 			m_ReachableTransports &= ~eNTCP2V6Mesh;
1075 			for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
1076 			{
1077 				auto addr = *it;
1078 				if (i2p::util::net::IsYggdrasilAddress (addr->host))
1079 					it = m_Addresses->erase (it);
1080 				else
1081 					++it;
1082 			}
1083 		}
1084 	}
1085 
GetSSUAddress(bool v4only) const1086 	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUAddress (bool v4only) const
1087 	{
1088 		return GetAddress (
1089 			[v4only](std::shared_ptr<const RouterInfo::Address> address)->bool
1090 			{
1091 				return (address->transportStyle == eTransportSSU) && (!v4only || address->IsV4 ());
1092 			});
1093 	}
1094 
GetSSUV6Address() const1095 	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUV6Address () const
1096 	{
1097 		return GetAddress (
1098 			[](std::shared_ptr<const RouterInfo::Address> address)->bool
1099 			{
1100 				return (address->transportStyle == eTransportSSU) && address->IsV6();
1101 			});
1102 	}
1103 
1104 	template<typename Filter>
GetAddress(Filter filter) const1105 	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (Filter filter) const
1106 	{
1107 		// TODO: make it more generic using comparator
1108 #if (BOOST_VERSION >= 105300)
1109 		auto addresses = boost::atomic_load (&m_Addresses);
1110 #else
1111 		auto addresses = m_Addresses;
1112 #endif
1113 		for (const auto& address : *addresses)
1114 			if (filter (address)) return address;
1115 
1116 		return nullptr;
1117 	}
1118 
GetNTCP2AddressWithStaticKey(const uint8_t * key) const1119 	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2AddressWithStaticKey (const uint8_t * key) const
1120 	{
1121 		if (!key) return nullptr;
1122 		return GetAddress (
1123 			[key](std::shared_ptr<const RouterInfo::Address> address)->bool
1124 			{
1125 				return address->IsNTCP2 () && !memcmp (address->ntcp2->staticKey, key, 32);
1126 			});
1127 	}
1128 
GetPublishedNTCP2V4Address() const1129 	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetPublishedNTCP2V4Address () const
1130 	{
1131 		return GetAddress (
1132 			[](std::shared_ptr<const RouterInfo::Address> address)->bool
1133 			{
1134 				return address->IsPublishedNTCP2 () && address->host.is_v4 ();
1135 			});
1136 	}
1137 
GetPublishedNTCP2V6Address() const1138 	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetPublishedNTCP2V6Address () const
1139 	{
1140 		return GetAddress (
1141 			[](std::shared_ptr<const RouterInfo::Address> address)->bool
1142 			{
1143 				return address->IsPublishedNTCP2 () && address->host.is_v6 () &&
1144 					!i2p::util::net::IsYggdrasilAddress (address->host);
1145 			});
1146 	}
1147 
GetYggdrasilAddress() const1148 	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetYggdrasilAddress () const
1149 	{
1150 		return GetAddress (
1151 			[](std::shared_ptr<const RouterInfo::Address> address)->bool
1152 			{
1153 				return address->IsPublishedNTCP2 () && i2p::util::net::IsYggdrasilAddress (address->host);
1154 			});
1155 	}
1156 
GetProfile() const1157 	std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
1158 	{
1159 		if (!m_Profile)
1160 			m_Profile = GetRouterProfile (GetIdentHash ());
1161 		return m_Profile;
1162 	}
1163 
Encrypt(const uint8_t * data,uint8_t * encrypted) const1164 	void RouterInfo::Encrypt (const uint8_t * data, uint8_t * encrypted) const
1165 	{
1166 		auto encryptor = m_RouterIdentity->CreateEncryptor (nullptr);
1167 		if (encryptor)
1168 			encryptor->Encrypt (data, encrypted);
1169 	}
1170 
IsEligibleFloodfill() const1171 	bool RouterInfo::IsEligibleFloodfill () const
1172 	{
1173 		// floodfill must be reachable by ipv4, >= 0.9.38 and not DSA
1174 		return IsReachableBy (eNTCP2V4 | eSSUV4) && m_Version >= NETDB_MIN_FLOODFILL_VERSION &&
1175 			GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
1176 	}
1177 
IsPeerTesting(bool v4) const1178 	bool RouterInfo::IsPeerTesting (bool v4) const
1179 	{
1180 		if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false;
1181 		return (bool)GetAddress (
1182 			[v4](std::shared_ptr<const RouterInfo::Address> address)->bool
1183 			{
1184 				return (address->transportStyle == eTransportSSU) && address->IsPeerTesting () &&
1185 					((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && address->IsReachableSSU ();
1186 			});
1187 	}
1188 
IsIntroducer(bool v4) const1189 	bool RouterInfo::IsIntroducer (bool v4) const
1190 	{
1191 		if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false;
1192 		return (bool)GetAddress (
1193 			[v4](std::shared_ptr<const RouterInfo::Address> address)->bool
1194 			{
1195 				return (address->transportStyle == eTransportSSU) && address->IsIntroducer () &&
1196 					((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && !address->host.is_unspecified ();
1197 			});
1198 	}
1199 
SetUnreachableAddressesTransportCaps(uint8_t transports)1200 	void RouterInfo::SetUnreachableAddressesTransportCaps (uint8_t transports)
1201 	{
1202 		for (auto& addr: *m_Addresses)
1203 		{
1204 			// TODO: implement SSU
1205 			if (addr->transportStyle == eTransportNTCP && !addr->IsPublishedNTCP2 ())
1206 			{
1207 				addr->caps &= ~(eV4 | eV6);
1208 				addr->caps |= transports;
1209 			}
1210 		}
1211 	}
1212 
UpdateSupportedTransports()1213 	void RouterInfo::UpdateSupportedTransports ()
1214 	{
1215 		m_SupportedTransports = 0;
1216 		m_ReachableTransports = 0;
1217 		for (const auto& addr: *m_Addresses)
1218 		{
1219 			uint8_t transports = 0;
1220 			if (addr->transportStyle == eTransportNTCP)
1221 			{
1222 				if (addr->IsV4 ()) transports |= eNTCP2V4;
1223 				if (addr->IsV6 ())
1224 					transports |= (i2p::util::net::IsYggdrasilAddress (addr->host) ? eNTCP2V6Mesh : eNTCP2V6);
1225 				if (addr->IsPublishedNTCP2 ())
1226 					m_ReachableTransports |= transports;
1227 			}
1228 			else if (addr->transportStyle == eTransportSSU)
1229 			{
1230 				if (addr->IsV4 ()) transports |= eSSUV4;
1231 				if (addr->IsV6 ()) transports |= eSSUV6;
1232 				if (addr->IsReachableSSU ())
1233 					m_ReachableTransports |= transports;
1234 			}
1235 			m_SupportedTransports |= transports;
1236 		}
1237 	}
1238 }
1239 }
1240