/ libi2pd / RouterInfo.cpp
RouterInfo.cpp
   1  /*
   2  * Copyright (c) 2013-2026, 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 <memory>
  14  #include <charconv>
  15  #include <boost/algorithm/string.hpp> // for boost::to_lower
  16  #ifndef __cpp_lib_atomic_shared_ptr
  17  #include <boost/atomic.hpp>
  18  #endif
  19  #include "version.h"
  20  #include "util.h"
  21  #include "Crypto.h"
  22  #include "Base.h"
  23  #include "Timestamp.h"
  24  #include "Log.h"
  25  #include "Transports.h"
  26  #include "NetDb.hpp"
  27  #include "RouterContext.h"
  28  #include "CryptoKey.h"
  29  #include "RouterInfo.h"
  30  
  31  namespace i2p
  32  {
  33  namespace data
  34  {
  35  	RouterInfo::Buffer::Buffer (const uint8_t * buf, size_t len)
  36  	{
  37  		if (len > size ()) len = size ();
  38  		memcpy (data (), buf, len);
  39  		m_BufferLen = len;
  40  	}
  41  
  42  	RouterInfo::RouterInfo (): m_Buffer (nullptr)
  43  	{
  44  		m_Addresses = AddressesPtr(new Addresses ()); // create empty list
  45  	}
  46  
  47  	RouterInfo::RouterInfo (const std::string& fullPath):
  48  		m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false), m_IsFloodfill (false),
  49  		m_IsBufferScheduledToDelete (false), m_SupportedTransports (0),
  50  		m_ReachableTransports (0), m_PublishedTransports (0), m_Caps (0), m_Version (0),
  51  		m_Congestion (eLowCongestion)
  52  	{
  53  		m_Addresses = AddressesPtr(new Addresses ()); // create empty list
  54  		m_Buffer = RouterInfo::NewBuffer (); // always RouterInfo's
  55  		ReadFromFile (fullPath);
  56  	}
  57  
  58  	RouterInfo::RouterInfo (std::shared_ptr<Buffer>&& buf, size_t len):
  59  		m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false), m_IsFloodfill (false),
  60  		m_IsBufferScheduledToDelete (false), m_SupportedTransports (0), m_ReachableTransports (0), m_PublishedTransports (0),
  61  		m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
  62  	{
  63  		if (len <= MAX_RI_BUFFER_SIZE)
  64  		{
  65  			m_Addresses = AddressesPtr(new Addresses ()); // create empty list
  66  			m_Buffer = buf;
  67  			if (m_Buffer) m_Buffer->SetBufferLen (len);
  68  			ReadFromBuffer (true);
  69  		}
  70  		else
  71  		{
  72  			LogPrint (eLogError, "RouterInfo: Buffer is too long ", len, ". Ignored");
  73  			m_Buffer = nullptr;
  74  			m_IsUnreachable = true;
  75  		}
  76  	}
  77  
  78  	RouterInfo::RouterInfo (const uint8_t * buf, size_t len):
  79  		RouterInfo (netdb.NewRouterInfoBuffer (buf, len), len)
  80  	{
  81  	}
  82  
  83  	RouterInfo::~RouterInfo ()
  84  	{
  85  	}
  86  
  87  	bool RouterInfo::Update (const uint8_t * buf, size_t len)
  88  	{
  89  		if (len > MAX_RI_BUFFER_SIZE)
  90  		{
  91  			LogPrint (eLogWarning, "RouterInfo: Updated buffer is too long ", len, ". Not changed");
  92  			return false;
  93  		}
  94  		// verify signature since we have identity already
  95  		int l = len - m_RouterIdentity->GetSignatureLen ();
  96  		if (m_RouterIdentity->Verify (buf, l, buf + l))
  97  		{
  98  			// clean up
  99  			m_IsUpdated = true;
 100  			m_IsUnreachable = false;
 101  			m_SupportedTransports = 0;
 102  			m_ReachableTransports = 0;
 103  			m_PublishedTransports = 0;
 104  			m_Caps = 0; m_IsFloodfill = false;
 105  			// don't clean up m_Addresses, it will be replaced in ReadFromStream
 106  			ClearProperties ();
 107  			// skip identity
 108  			size_t identityLen = m_RouterIdentity->GetFullLen ();
 109  			// read new RI
 110  			ReadFromBuffer (buf + identityLen, len - identityLen);
 111  			if (!m_IsUnreachable)
 112  				UpdateBuffer (buf, len); // save buffer
 113  			// don't delete buffer until saved to the file
 114  		}
 115  		else
 116  		{
 117  			LogPrint (eLogWarning, "RouterInfo: Updated signature verification failed. Not changed");
 118  			return false;
 119  		}
 120  		return true;
 121  	}
 122  
 123  	void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
 124  	{
 125  		m_RouterIdentity = identity;
 126  		m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
 127  	}
 128  
 129  	bool RouterInfo::LoadFile (const std::string& fullPath)
 130  	{
 131  		std::ifstream s(fullPath, std::ifstream::binary);
 132  		if (s.is_open ())
 133  		{
 134  			s.seekg (0,std::ios::end);
 135  			size_t bufferLen = s.tellg ();
 136  			if (bufferLen < 40 || bufferLen > MAX_RI_BUFFER_SIZE)
 137  			{
 138  				LogPrint(eLogError, "RouterInfo: File ", fullPath, " is malformed");
 139  				return false;
 140  			}
 141  			s.seekg(0, std::ios::beg);
 142  			if (!m_Buffer)
 143  				m_Buffer = NewBuffer ();
 144  			s.read((char *)m_Buffer->data (), bufferLen);
 145  			m_Buffer->SetBufferLen (bufferLen);
 146  		}
 147  		else
 148  		{
 149  			LogPrint (eLogError, "RouterInfo: Can't open file ", fullPath);
 150  			return false;
 151  		}
 152  		return true;
 153  	}
 154  
 155  	void RouterInfo::ReadFromFile (const std::string& fullPath)
 156  	{
 157  		if (LoadFile (fullPath))
 158  			ReadFromBuffer (false);
 159  		else
 160  			m_IsUnreachable = true;
 161  	}
 162  
 163  	void RouterInfo::ReadFromBuffer (bool verifySignature)
 164  	{
 165  		if (!m_Buffer)
 166  		{
 167  			m_IsUnreachable = true;
 168  			return;
 169  		}
 170  		size_t bufferLen = m_Buffer->GetBufferLen ();
 171  		m_RouterIdentity = NewIdentity (m_Buffer->data (), bufferLen);
 172  		size_t identityLen = m_RouterIdentity->GetFullLen ();
 173  		if (identityLen >= bufferLen)
 174  		{
 175  			LogPrint (eLogError, "RouterInfo: Identity length ", identityLen, " exceeds buffer size ", bufferLen);
 176  			m_IsUnreachable = true;
 177  			return;
 178  		}
 179  		if (verifySignature)
 180  		{
 181  			// reject RSA signatures
 182  			if (m_RouterIdentity->IsRSA ())
 183  			{
 184  				LogPrint (eLogError, "RouterInfo: RSA signature type is not allowed");
 185  				m_IsUnreachable = true;
 186  				return;
 187  			}
 188  			// verify signature
 189  			int l = bufferLen - m_RouterIdentity->GetSignatureLen ();
 190  			if (l < 0 || !m_RouterIdentity->Verify ((uint8_t *)m_Buffer->data (), l, (uint8_t *)m_Buffer->data () + l))
 191  			{
 192  				LogPrint (eLogError, "RouterInfo: Signature verification failed");
 193  				m_IsUnreachable = true;
 194  				return;
 195  			}
 196  		}
 197  		// parse RI
 198  		if (!ReadFromBuffer (m_Buffer->data () + identityLen, bufferLen - identityLen))
 199  		{
 200  			LogPrint (eLogError, "RouterInfo: Malformed message");
 201  			m_IsUnreachable = true;
 202  		}
 203  	}
 204  
 205  	bool RouterInfo::ReadFromBuffer (const uint8_t * buf, size_t len)
 206  	{
 207  		if (len < 9) return false;
 208  		m_Caps = 0; m_Congestion = eLowCongestion;
 209  		m_Timestamp = bufbe64toh (buf);
 210  		size_t offset = 8; // timestamp
 211  		// read addresses
 212  		auto addresses = NewAddresses ();
 213  		uint8_t numAddresses = buf[offset]; offset++;
 214  		for (int i = 0; i < numAddresses; i++)
 215  		{
 216  			if (offset + 9 > len) return false; // 1 byte cost + 8 bytes date
 217  			uint8_t supportedTransports = 0;
 218  			auto address = NewAddress ();
 219  			offset++; // cost, ignore
 220  			address->date = bufbe64toh (buf + offset); offset += 8; // date
 221  			bool isHost = false, isStaticKey = false, isV2 = false, isIntroKey = false;
 222  			int pq = 0;
 223  			auto transportStyle = ExtractString (buf + offset, len - offset); offset += transportStyle.length () + 1;
 224  			if (!transportStyle.compare (0, 4, "NTCP")) // NTCP or NTCP2
 225  				address->transportStyle = eTransportNTCP2;
 226  			else if (!transportStyle.compare (0, 3, "SSU")) // SSU or SSU2
 227  			{
 228  				address->transportStyle = eTransportSSU2;
 229  				address->ssu.reset (new SSUExt ());
 230  				address->ssu->mtu = 0;
 231  			}
 232  			else
 233  				address->transportStyle = eTransportUnknown;
 234  			address->caps = 0;
 235  			address->port = 0;
 236  			if (offset + 2 > len) return false;
 237  			uint16_t size = bufbe16toh (buf + offset); offset += 2; // size
 238  			if (offset + size >= len) return false;
 239  			if (address->transportStyle == eTransportUnknown)
 240  			{
 241  				// skip unknown address
 242  				offset += size;
 243  				continue;
 244  			}
 245  			size_t r = 0;
 246  			while (r < size)
 247  			{
 248  				auto [key, value, sz] = ExtractParam (buf + offset, len - offset);
 249  				r += sz; offset += sz;
 250  				if (key.empty ()) continue;
 251  				if (key == "host")
 252  				{
 253  					boost::system::error_code ecode;
 254  					address->host = boost::asio::ip::make_address (value, ecode);
 255  					if (!ecode && !address->host.is_unspecified ())
 256  					{
 257  						if (!i2p::transport::transports.IsInReservedRange (address->host) ||
 258  						    i2p::util::net::IsYggdrasilAddress (address->host))
 259  							isHost = true;
 260  						else
 261  							// we consider such address as invalid
 262  							address->transportStyle = eTransportUnknown;
 263  					}
 264  				}
 265  				else if (key == "port")
 266  				{
 267  					auto res = std::from_chars(value.data(), value.data() + value.size(), address->port);
 268  					if (res.ec != std::errc())
 269  						LogPrint (eLogWarning, "RouterInfo: 'port' conversion error: ", std::make_error_code (res.ec).message ());
 270  				}
 271  				else if (key == "mtu")
 272  				{
 273  					if (address->ssu)
 274  					{
 275  						auto res = std::from_chars(value.data(), value.data() + value.size(), address->ssu->mtu);
 276  						if (res.ec != std::errc())
 277  							LogPrint (eLogWarning, "RouterInfo: 'mtu' conversion error: ", std::make_error_code (res.ec).message ());
 278  					}
 279  					else
 280  						LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP2");
 281  				}
 282  				else if (key == "caps")
 283  					address->caps = ExtractAddressCaps (value);
 284  				else if (key == "s") // ntcp2 or ssu2 static key
 285  				{
 286  					if (Base64ToByteStream (value, address->s, 32) == 32 &&
 287  						!(address->s[31] & 0x80)) // check if x25519 public key
 288  							isStaticKey = true;
 289  					else
 290  						address->transportStyle = eTransportUnknown; // invalid address
 291  				}
 292  				else if (key == "i") // ntcp2 iv or ssu2 intro
 293  				{
 294  					if (address->IsNTCP2 ())
 295  					{
 296  						if (Base64ToByteStream (value, address->i, 16) == 16)
 297  							address->published = true; // presence of "i" means "published" NTCP2
 298  						else
 299  							address->transportStyle = eTransportUnknown; // invalid address
 300  					}
 301  					else if (address->IsSSU2 ())
 302  					{
 303  						if (Base64ToByteStream (value, address->i, 32) == 32)
 304  							isIntroKey = true;
 305  						else
 306  							address->transportStyle = eTransportUnknown; // invalid address
 307  					}
 308  				}
 309  				else if (key == "v")
 310  				{
 311  					if (value.size () == 1 && value[0] >= '2' && value[0] <= '5') // only 2,3,4,5 allowed
 312  					{
 313                          if (pq >= 3 && pq <= 5)
 314                              address->v = pq;
 315                          else
 316                              address->v = value[0] - '0';
 317  						isV2 = true;
 318  					}
 319  					else
 320  					{
 321  						LogPrint (eLogWarning, "RouterInfo: Unexpected value ", value, " for v");
 322  						address->transportStyle = eTransportUnknown; // invalid address
 323  					}
 324  				}
 325  				else if (key == "pq")
 326  				{
 327                      if (address->transportStyle == eTransportNTCP2 && // for NTCP2 only for now
 328                          value.size () == 1 && value[0] >= '3' && value[0] <= '5') // only 3,4,5 allowed
 329                              pq = value[0] - '0';
 330  				}
 331  				else if (key[0] == 'i')
 332  				{
 333  					// introducers
 334  					if (!address->ssu)
 335  					{
 336  						LogPrint (eLogError, "RouterInfo: Introducer is presented for non-SSU address. Skipped");
 337  						continue;
 338  					}
 339  					unsigned char index = key[key.length () - 1] - '0'; // TODO:
 340  					if (index > 9)
 341  					{
 342  						LogPrint (eLogError, "RouterInfo: Unexpected introducer's index ", index, " skipped");
 343  						continue;
 344  					}
 345  					if (index >= address->ssu->introducers.size ())
 346  					{
 347  						if (address->ssu->introducers.empty ()) // first time
 348  							address->ssu->introducers.reserve (3);
 349  						address->ssu->introducers.resize (index + 1);
 350  					}
 351  					Introducer& introducer = address->ssu->introducers.at (index);
 352  					auto key1 = key.substr(0, key.length () - 1);
 353  					if (key1 == "itag")
 354  					{
 355  						auto res = std::from_chars(value.data(), value.data() + value.size(), introducer.iTag);
 356  						if (res.ec != std::errc())
 357  							LogPrint (eLogWarning, "RouterInfo: 'itag' conversion error: ", std::make_error_code (res.ec).message ());
 358  					}
 359  					else if (key1 == "ih")
 360  						Base64ToByteStream (value, introducer.iH, 32);
 361  					else if (key1 == "iexp")
 362  					{
 363  						auto res = std::from_chars(value.data(), value.data() + value.size(), introducer.iExp);
 364  						if (res.ec != std::errc())
 365  							LogPrint (eLogWarning, "RouterInfo: 'iexp' conversion error: ", std::make_error_code (res.ec).message ());
 366  					}
 367  				}
 368  			}
 369  			if (address->transportStyle == eTransportNTCP2)
 370  			{
 371  				if (isStaticKey)
 372  				{
 373  					if (isHost && address->port)
 374  					{
 375  						if (address->host.is_v6 ())
 376  							supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6);
 377  						else
 378  							supportedTransports |= eNTCP2V4;
 379  						m_PublishedTransports |= supportedTransports;
 380  					}
 381  					else
 382  					{
 383  						address->published = false;
 384  						if (address->caps)
 385  						{
 386  							if (address->caps & AddressCaps::eV4) supportedTransports |= eNTCP2V4;
 387  							if (address->caps & AddressCaps::eV6) supportedTransports |= eNTCP2V6;
 388  						}
 389  						else
 390  							supportedTransports |= eNTCP2V4; // most likely, since we don't have host
 391  					}
 392  				}
 393  			}
 394  			else if (address->transportStyle == eTransportSSU2 && isV2 && isStaticKey && isIntroKey)
 395  			{
 396  				if (address->IsV4 ()) supportedTransports |= eSSU2V4;
 397  				if (address->IsV6 ()) supportedTransports |= eSSU2V6;
 398  				if (isHost && address->port)
 399  				{
 400  					if (address->host.is_v4 ()) m_PublishedTransports |= eSSU2V4;
 401  					if (address->host.is_v6 ()) m_PublishedTransports |= eSSU2V6;
 402  					address->published = true;
 403  				}
 404  				else if (address->ssu && !address->ssu->introducers.empty ())
 405  				{
 406  					// exclude invalid introducers
 407  					uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
 408  					UpdateIntroducers (address, ts);
 409  					if (!address->ssu->introducers.empty ()) // still has something
 410  						m_ReachableTransports |= supportedTransports;
 411  				}
 412  			}
 413  			if (supportedTransports)
 414  			{
 415  				if (!(m_SupportedTransports & supportedTransports)) // avoid duplicates
 416  				{
 417  					for (uint8_t i = 0; i < eNumTransports; i++)
 418  						if ((1 << i) & supportedTransports)
 419  							(*addresses)[i] = address;
 420  				}
 421  				m_SupportedTransports |= supportedTransports;
 422  			}
 423  		}
 424  		m_ReachableTransports |= m_PublishedTransports;
 425  		// update addresses
 426  #ifdef __cpp_lib_atomic_shared_ptr
 427  		m_Addresses = addresses;
 428  #else
 429  		boost::atomic_store (&m_Addresses, addresses);
 430  #endif
 431  		// read peers
 432  		if (offset + 1 > len) return false;
 433  		uint8_t numPeers = buf[offset]; offset++; // num peers
 434  		offset += numPeers*32; // TODO: read peers
 435  		// read properties
 436  		if (offset + 2 > len) return false;
 437  		m_Version = 0;
 438  		bool isNetId = false;
 439  		std::string family;
 440  		uint16_t size = bufbe16toh (buf + offset); offset += 2; // size
 441  		if (offset + size > len) return false;
 442  		size_t r = 0;
 443  		while (r < size)
 444  		{
 445  			auto [key, value, sz] = ExtractParam (buf + offset, len - offset);
 446  			r += sz; offset += sz;
 447  			if (key.empty ()) continue;
 448  			SetProperty (key, value);
 449  
 450  			// extract caps
 451  			if (key == "caps")
 452  			{
 453  				ExtractCaps (value);
 454  				m_IsFloodfill = IsDeclaredFloodfill ();
 455  			}
 456  			// extract version
 457  			else if (key == ROUTER_INFO_PROPERTY_VERSION)
 458  			{
 459  				m_Version = 0;
 460  				for (auto ch: value)
 461  				{
 462  					if (ch >= '0' && ch <= '9')
 463  					{
 464  						m_Version *= 10;
 465  						m_Version += (ch - '0');
 466  					}
 467  				}
 468  				if (m_Version < NETDB_MIN_PEER_TEST_VERSION && (m_SupportedTransports & (eSSU2V4 | eSSU2V6)))
 469  				{
 470  					auto addresses = GetAddresses ();
 471  					if (addresses)
 472  					{
 473  						if ((*addresses)[eSSU2V4Idx]) (*addresses)[eSSU2V4Idx]->caps &= ~eSSUTesting;
 474  						if ((*addresses)[eSSU2V6Idx]) (*addresses)[eSSU2V6Idx]->caps &= ~eSSUTesting;
 475  					}
 476  				}
 477  			}
 478  			// check netId
 479  			else if (key == ROUTER_INFO_PROPERTY_NETID)
 480  			{
 481  				isNetId = true;
 482  				int netID;
 483  				auto res = std::from_chars(value.data(), value.data() + value.size(), netID);
 484  				if (res.ec != std::errc() || netID != i2p::context.GetNetID ())
 485  				{
 486  					LogPrint (eLogError, "RouterInfo: Unexpected ", ROUTER_INFO_PROPERTY_NETID, "=", value);
 487  					m_IsUnreachable = true;
 488  				}
 489  			}
 490  			// family
 491  			else if (key == ROUTER_INFO_PROPERTY_FAMILY)
 492  			{
 493  				family = value;
 494  				boost::to_lower (family);
 495  			}
 496  			else if (key == ROUTER_INFO_PROPERTY_FAMILY_SIG)
 497  			{
 498  				if (netdb.GetFamilies ().VerifyFamily (family, GetIdentHash (), value)) // TODO
 499  					m_FamilyID = netdb.GetFamilies ().GetFamilyID (family);
 500  				else
 501  				{
 502  					LogPrint (eLogWarning, "RouterInfo: Family ", family, " signature verification failed");
 503  					SetUnreachable (true);
 504  				}
 505  			}
 506  		}
 507  
 508  		if (!m_SupportedTransports || !isNetId || !m_Version)
 509  			SetUnreachable (true);
 510  
 511  		return true;
 512  	}
 513  
 514  	bool RouterInfo::IsFamily (FamilyID famid) const
 515  	{
 516  		return m_FamilyID == famid;
 517  	}
 518  
 519  	void RouterInfo::ExtractCaps (std::string_view value)
 520  	{
 521  		for (auto cap: value)
 522  		{
 523  			switch (cap)
 524  			{
 525  				case CAPS_FLAG_FLOODFILL:
 526  					m_Caps |= Caps::eFloodfill;
 527  				break;
 528  				case CAPS_FLAG_LOW_BANDWIDTH1:
 529  				case CAPS_FLAG_LOW_BANDWIDTH2:
 530  				case CAPS_FLAG_LOW_BANDWIDTH3:
 531  				case CAPS_FLAG_LOW_BANDWIDTH4:
 532  					m_BandwidthCap = cap;
 533  				break;
 534  				case CAPS_FLAG_HIGH_BANDWIDTH:
 535  					m_Caps |= Caps::eHighBandwidth;
 536  					m_BandwidthCap = cap;
 537  				break;
 538  				case CAPS_FLAG_EXTRA_BANDWIDTH1:
 539  				case CAPS_FLAG_EXTRA_BANDWIDTH2:
 540  					m_Caps |= Caps::eExtraBandwidth | Caps::eHighBandwidth;
 541  					m_BandwidthCap = cap;
 542  				break;
 543  				case CAPS_FLAG_HIDDEN:
 544  					m_Caps |= Caps::eHidden;
 545  				break;
 546  				case CAPS_FLAG_REACHABLE:
 547  					m_Caps |= Caps::eReachable;
 548  				break;
 549  				case CAPS_FLAG_UNREACHABLE:
 550  					m_Caps |= Caps::eUnreachable;
 551  				break;
 552  				case CAPS_FLAG_MEDIUM_CONGESTION:
 553  					m_Congestion = eMediumCongestion;
 554  				break;
 555  				case CAPS_FLAG_HIGH_CONGESTION:
 556  					m_Congestion = eHighCongestion;
 557  				break;
 558  				case CAPS_FLAG_REJECT_ALL_CONGESTION:
 559  					m_Congestion = eRejectAll;
 560  				break;
 561  				default: ;
 562  			}
 563  		}
 564  	}
 565  
 566  	uint8_t RouterInfo::ExtractAddressCaps (std::string_view value) const
 567  	{
 568  		uint8_t caps = 0;
 569  		for (auto cap: value)
 570  		{
 571  			switch (cap)
 572  			{
 573  				case CAPS_FLAG_V4:
 574  					caps |= AddressCaps::eV4;
 575  				break;
 576  				case CAPS_FLAG_V6:
 577  					caps |= AddressCaps::eV6;
 578  				break;
 579  				case CAPS_FLAG_SSU2_TESTING:
 580  					caps |= AddressCaps::eSSUTesting;
 581  				break;
 582  				case CAPS_FLAG_SSU2_INTRODUCER:
 583  					caps |= AddressCaps::eSSUIntroducer;
 584  				break;
 585  				default: ;
 586  			}
 587  		}
 588  		return caps;
 589  	}
 590  
 591  	void RouterInfo::UpdateIntroducers (std::shared_ptr<Address> address, uint64_t ts)
 592  	{
 593  		if (!address || !address->ssu) return;
 594  		int numValid = 0;
 595  		for (auto& it: address->ssu->introducers)
 596  		{
 597  			if (it.iTag && ts < it.iExp && !it.iH.IsZero ())
 598  				numValid++;
 599  			else
 600  				it.iTag = 0;
 601  		}
 602  		if (!numValid)
 603  			address->ssu->introducers.resize (0);
 604  	}
 605  
 606  	bool RouterInfo::IsNewer (const uint8_t * buf, size_t len) const
 607  	{
 608  		if (!m_RouterIdentity) return false;
 609  		size_t size = m_RouterIdentity->GetFullLen ();
 610  		if (size + 8 > len) return false;
 611  		return bufbe64toh (buf + size) > m_Timestamp;
 612  	}
 613  
 614  	const uint8_t * RouterInfo::LoadBuffer (const std::string& fullPath)
 615  	{
 616  		if (!m_Buffer)
 617  		{
 618  			if (LoadFile (fullPath))
 619  				LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
 620  			else
 621  				return nullptr;
 622  		}
 623  		return m_Buffer->data ();
 624  	}
 625  
 626  	bool RouterInfo::SaveToFile (const std::string& fullPath, std::shared_ptr<Buffer> buf)
 627  	{
 628  		if (!buf) return false;
 629  		std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
 630  		if (!f.is_open ())
 631  		{
 632  			LogPrint (eLogError, "RouterInfo: Can't save to ", fullPath);
 633  			return false;
 634  		}
 635  		f.write ((char *)buf->data (), buf->GetBufferLen ());
 636  		return true;
 637  	}
 638  
 639  	bool RouterInfo::SaveToFile (const std::string& fullPath)
 640  	{
 641  		if (m_IsUnreachable) return false; // don't save bad router
 642  		if (!m_Buffer)
 643  		{
 644  			LogPrint (eLogWarning, "RouterInfo: Can't save, m_Buffer == NULL");
 645  			return false;
 646  		}
 647  		return SaveToFile (fullPath, m_Buffer);
 648  	}
 649  
 650  	std::string_view RouterInfo::ExtractString (const uint8_t * buf, size_t len) const
 651  	{
 652  		uint8_t l = buf[0];
 653  		if (l > len)
 654  		{
 655  			LogPrint (eLogWarning, "RouterInfo: String length ", (int)l, " exceeds buffer size ", len);
 656  			l = len;
 657  		}
 658  		return { (const char *)(buf + 1), l };
 659  	}
 660  
 661  	std::tuple<std::string_view, std::string_view, size_t> RouterInfo::ExtractParam (const uint8_t * buf, size_t len) const
 662  	{
 663  		auto key = ExtractString (buf, len);
 664  		size_t offset = key.length () + 1;
 665  		if (offset >= len) return { std::string_view(), std::string_view(), len };
 666  		if (buf[offset] != '=')
 667  		{
 668  			LogPrint (eLogWarning, "RouterInfo: Unexpected character ", buf[offset], " instead '=' after ", key);
 669  			key = std::string_view();
 670  		}
 671  		offset++;
 672  		if (offset >= len) return { key, std::string_view(), len };
 673  		auto value = ExtractString (buf + offset, len - offset);
 674  		offset += value.length () + 1;
 675  		if (offset >= len) return { key, std::string_view(), len };
 676  		if (buf[offset] != ';')
 677  		{
 678  			LogPrint (eLogWarning, "RouterInfo: Unexpected character ", buf[offset], " instead ';' after ", value);
 679  			value = std::string_view();
 680  		}
 681  		offset++;
 682  		return { key, value, offset };
 683  	}
 684  
 685  	void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,int port, uint8_t caps)
 686  	{
 687  		auto addr = std::make_shared<Address>();
 688  		addr->port = port;
 689  		addr->transportStyle = eTransportNTCP2;
 690  		addr->caps = caps;
 691  		addr->date = 0;
 692  		addr->published = false;
 693  		memcpy (addr->s, staticKey, 32);
 694  		memcpy (addr->i, iv, 16);
 695  		if (addr->IsV4 ())
 696  		{
 697  			m_SupportedTransports |= eNTCP2V4;
 698  			(*GetAddresses ())[eNTCP2V4Idx] = addr;
 699  		}
 700  		if (addr->IsV6 ())
 701  		{
 702  			m_SupportedTransports |= eNTCP2V6;
 703  			(*GetAddresses ())[eNTCP2V6Idx] = addr;
 704  		}
 705  	}
 706  
 707  	void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
 708  		const boost::asio::ip::address& host, int port)
 709  	{
 710  		auto addr = std::make_shared<Address>();
 711  		addr->host = host;
 712  		addr->port = port;
 713  		addr->transportStyle = eTransportNTCP2;
 714  		addr->date = 0;
 715  		addr->published = true;
 716  		memcpy (addr->s, staticKey, 32);
 717  		memcpy (addr->i, iv, 16);
 718  		addr->caps = 0;
 719  		if (host.is_unspecified ())
 720  		{
 721  			if (host.is_v4 ()) addr->caps |= eV4;
 722  			if (host.is_v6 ()) addr->caps |= eV6;
 723  		}
 724  		auto addresses = GetAddresses ();
 725  		if (addr->IsV4 ())
 726  		{
 727  			m_SupportedTransports |= eNTCP2V4;
 728  			m_ReachableTransports |= eNTCP2V4;
 729  			(*addresses)[eNTCP2V4Idx] = addr;
 730  		}
 731  		if (addr->IsV6 ())
 732  		{
 733  			if (i2p::util::net::IsYggdrasilAddress (addr->host))
 734  			{
 735  				m_SupportedTransports |= eNTCP2V6Mesh;
 736  				m_ReachableTransports |= eNTCP2V6Mesh;
 737  				(*addresses)[eNTCP2V6MeshIdx] = addr;
 738  			}
 739  			else
 740  			{
 741  				m_SupportedTransports |= eNTCP2V6;
 742  				m_ReachableTransports |= eNTCP2V6;
 743  				(*addresses)[eNTCP2V6Idx] = addr;
 744  			}
 745  		}
 746  	}
 747  
 748  	void RouterInfo::RemoveNTCP2Address (bool v4)
 749  	{
 750  		auto addresses = GetAddresses ();
 751  		if (v4)
 752  		{
 753  			if ((*addresses)[eNTCP2V6Idx])
 754  				(*addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4;
 755  			(*addresses)[eNTCP2V4Idx].reset ();
 756  		}
 757  		else
 758  		{
 759  			if ((*addresses)[eNTCP2V4Idx])
 760  				(*addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6;
 761  			(*addresses)[eNTCP2V6Idx].reset ();
 762  		}
 763  		UpdateSupportedTransports ();
 764  	}
 765  
 766  	void RouterInfo::AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, int port, uint8_t caps)
 767  	{
 768  		auto addr = std::make_shared<Address>();
 769  		addr->transportStyle = eTransportSSU2;
 770  		addr->port = port;
 771  		addr->caps = caps;
 772  		addr->date = 0;
 773  		addr->ssu.reset (new SSUExt ());
 774  		addr->ssu->mtu = 0;
 775  		memcpy (addr->s, staticKey, 32);
 776  		memcpy (addr->i, introKey, 32);
 777  		auto addresses = GetAddresses ();
 778  		if (addr->IsV4 ())
 779  		{
 780  			m_SupportedTransports |= eSSU2V4;
 781  			(*addresses)[eSSU2V4Idx] = addr;
 782  		}
 783  		if (addr->IsV6 ())
 784  		{
 785  			m_SupportedTransports |= eSSU2V6;
 786  			(*addresses)[eSSU2V6Idx] = addr;
 787  		}
 788  	}
 789  
 790  	void RouterInfo::AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey,
 791  		const boost::asio::ip::address& host, int port)
 792  	{
 793  		auto addr = std::make_shared<Address>();
 794  		addr->transportStyle = eTransportSSU2;
 795  		addr->host = host;
 796  		addr->port = port;
 797  		addr->published = true;
 798  		addr->date = 0;
 799  		addr->ssu.reset (new SSUExt ());
 800  		addr->ssu->mtu = 0;
 801  		memcpy (addr->s, staticKey, 32);
 802  		memcpy (addr->i, introKey, 32);
 803  		if (!host.is_unspecified ())
 804  			addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
 805  		else
 806  		{
 807  			addr->caps = 0;
 808  			if (host.is_v4 ()) addr->caps |= eV4;
 809  			if (host.is_v6 ()) addr->caps |= eV6;
 810  		}
 811  		auto addresses = GetAddresses ();
 812  		if (addr->IsV4 ())
 813  		{
 814  			m_SupportedTransports |= eSSU2V4;
 815  			m_ReachableTransports |= eSSU2V4;
 816  			(*addresses)[eSSU2V4Idx] = addr;
 817  		}
 818  		if (addr->IsV6 ())
 819  		{
 820  			m_SupportedTransports |= eSSU2V6;
 821  			m_ReachableTransports |= eSSU2V6;
 822  			(*addresses)[eSSU2V6Idx] = addr;
 823  		}
 824  	}
 825  
 826  	void RouterInfo::RemoveSSU2Address (bool v4)
 827  	{
 828  		auto addresses = GetAddresses ();
 829  		if (v4)
 830  		{
 831  			if ((*addresses)[eSSU2V6Idx])
 832  				(*addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4;
 833  			(*addresses)[eSSU2V4Idx].reset ();
 834  		}
 835  		else
 836  		{
 837  			if ((*addresses)[eSSU2V4Idx])
 838  				(*addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6;
 839  			(*addresses)[eSSU2V6Idx].reset ();
 840  		}
 841  		UpdateSupportedTransports ();
 842  	}
 843  
 844  	bool RouterInfo::IsNTCP2 (bool v4only) const
 845  	{
 846  		if (v4only)
 847  			return m_SupportedTransports & eNTCP2V4;
 848  		else
 849  			return m_SupportedTransports & (eNTCP2V4 | eNTCP2V6);
 850  	}
 851  
 852  
 853  	void RouterInfo::EnableV6 ()
 854  	{
 855  		if (!IsV6 ())
 856  		{
 857  			uint8_t addressCaps = AddressCaps::eV6;
 858  			if (IsV4 ()) addressCaps |= AddressCaps::eV4;
 859  			SetUnreachableAddressesTransportCaps (addressCaps);
 860  			UpdateSupportedTransports ();
 861  		}
 862  	}
 863  
 864  	void RouterInfo::EnableV4 ()
 865  	{
 866  		if (!IsV4 ())
 867  		{
 868  			uint8_t addressCaps = AddressCaps::eV4;
 869  			if (IsV6 ()) addressCaps |= AddressCaps::eV6;
 870  			SetUnreachableAddressesTransportCaps (addressCaps);
 871  			UpdateSupportedTransports ();
 872  		}
 873  	}
 874  
 875  
 876  	void RouterInfo::DisableV6 ()
 877  	{
 878  		if (IsV6 ())
 879  		{
 880  			auto addresses = GetAddresses ();
 881  			if ((*addresses)[eNTCP2V6Idx])
 882  			{
 883  				if ((*addresses)[eNTCP2V6Idx]->IsV4 () && (*addresses)[eNTCP2V4Idx])
 884  					(*addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6;
 885  				(*addresses)[eNTCP2V6Idx].reset ();
 886  			}
 887  			if ((*addresses)[eSSU2V6Idx])
 888  			{
 889  				if ((*addresses)[eSSU2V6Idx]->IsV4 () && (*addresses)[eSSU2V4Idx])
 890  					(*addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6;
 891  				(*addresses)[eSSU2V6Idx].reset ();
 892  			}
 893  			UpdateSupportedTransports ();
 894  		}
 895  	}
 896  
 897  	void RouterInfo::DisableV4 ()
 898  	{
 899  		if (IsV4 ())
 900  		{
 901  			auto addresses = GetAddresses ();
 902  			if ((*addresses)[eNTCP2V4Idx])
 903  			{
 904  				if ((*addresses)[eNTCP2V4Idx]->IsV6 () && (*addresses)[eNTCP2V6Idx])
 905  					(*addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4;
 906  				(*addresses)[eNTCP2V4Idx].reset ();
 907  			}
 908  			if ((*addresses)[eSSU2V4Idx])
 909  			{
 910  				if ((*addresses)[eSSU2V4Idx]->IsV6 () && (*addresses)[eSSU2V6Idx])
 911  					(*addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4;
 912  				(*addresses)[eSSU2V4Idx].reset ();
 913  			}
 914  			UpdateSupportedTransports ();
 915  		}
 916  	}
 917  
 918  	void RouterInfo::EnableMesh ()
 919  	{
 920  		if (!IsMesh ())
 921  		{
 922  			m_SupportedTransports |= eNTCP2V6Mesh;
 923  			m_ReachableTransports |= eNTCP2V6Mesh;
 924  		}
 925  	}
 926  
 927  	void RouterInfo::DisableMesh ()
 928  	{
 929  		if (IsMesh ())
 930  		{
 931  			m_SupportedTransports &= ~eNTCP2V6Mesh;
 932  			m_ReachableTransports &= ~eNTCP2V6Mesh;
 933  			(*GetAddresses ())[eNTCP2V6MeshIdx].reset ();
 934  		}
 935  	}
 936  
 937  	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2V4Address () const
 938  	{
 939  		return (*GetAddresses ())[eSSU2V4Idx];
 940  	}
 941  
 942  	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2V6Address () const
 943  	{
 944  		return (*GetAddresses ())[eSSU2V6Idx];
 945  	}
 946  
 947  	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2Address (bool v4) const
 948  	{
 949  		if (v4)
 950  		{
 951  			if (m_SupportedTransports & eSSU2V4)
 952  				return GetSSU2V4Address ();
 953  		}
 954  		else
 955  		{
 956  			if (m_SupportedTransports & eSSU2V6)
 957  				return GetSSU2V6Address ();
 958  		}
 959  		return nullptr;
 960  	}
 961  
 962  	RouterInfo::AddressesPtr RouterInfo::GetAddresses () const
 963  	{
 964  #ifdef __cpp_lib_atomic_shared_ptr
 965  		return m_Addresses;
 966  #else
 967  		return boost::atomic_load (&m_Addresses);
 968  #endif
 969  	}
 970  
 971  	template<typename Filter>
 972  	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (Filter filter) const
 973  	{
 974  		auto addresses = GetAddresses ();
 975  		for (const auto& address : *addresses)
 976  			if (address && filter (address)) return address;
 977  		return nullptr;
 978  	}
 979  
 980  	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2V4Address () const
 981  	{
 982  		return (*GetAddresses ())[eNTCP2V4Idx];
 983  	}
 984  
 985  	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2V6Address () const
 986  	{
 987  		return (*GetAddresses ())[eNTCP2V6Idx];
 988  	}
 989  
 990  	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetPublishedNTCP2V4Address () const
 991  	{
 992  		auto addr = (*GetAddresses ())[eNTCP2V4Idx];
 993  		if (addr && addr->IsPublishedNTCP2 ()) return addr;
 994  		return nullptr;
 995  	}
 996  
 997  	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetPublishedNTCP2V6Address () const
 998  	{
 999  		auto addr = (*GetAddresses ())[eNTCP2V6Idx];
1000  		if (addr && addr->IsPublishedNTCP2 ()) return addr;
1001  		return nullptr;
1002  	}
1003  
1004  	std::shared_ptr<const RouterInfo::Address> RouterInfo::GetYggdrasilAddress () const
1005  	{
1006  		return (*GetAddresses ())[eNTCP2V6MeshIdx];
1007  	}
1008  
1009  	std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
1010  	{
1011  		auto profile = m_Profile;
1012  		if (!profile)
1013  		{
1014  			profile = GetRouterProfile (GetIdentHash ());
1015  			m_Profile = profile;
1016  		}
1017  		return profile;
1018  	}
1019  
1020  	void RouterInfo::Encrypt (const uint8_t * data, uint8_t * encrypted) const
1021  	{
1022  		auto encryptor = m_RouterIdentity->CreateEncryptor (nullptr);
1023  		if (encryptor)
1024  			encryptor->Encrypt (data, encrypted);
1025  	}
1026  
1027  	bool RouterInfo::IsEligibleFloodfill () const
1028  	{
1029  		// floodfill must have published ipv4 or reachable ipv4 and published ipv6
1030  		// >= 0.9.59 and not DSA
1031  		return m_Version >= NETDB_MIN_FLOODFILL_VERSION && (IsPublished (true) ||
1032  			(IsReachableBy (eNTCP2V4 | eSSU2V4) && IsPublished (false))) &&
1033  			GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
1034  	}
1035  
1036  	bool RouterInfo::IsPublished (bool v4) const
1037  	{
1038  		if (m_Caps & (eUnreachable | eHidden)) return false; // if router sets U or H we assume that all addresses are not published
1039  		return IsPublishedOn (v4 ? (eNTCP2V4 | eSSU2V4) : (eNTCP2V6 | eSSU2V6));
1040  	}
1041  
1042  	bool RouterInfo::IsPublishedOn (CompatibleTransports transports) const
1043  	{
1044  		return m_PublishedTransports & transports;
1045  	}
1046  
1047  	bool RouterInfo::IsNAT2NATOnly (const RouterInfo& other) const
1048  	{
1049  		return !(m_PublishedTransports & other.m_SupportedTransports) &&
1050  			!(other.m_PublishedTransports & m_SupportedTransports);
1051  	}
1052  
1053  	bool RouterInfo::IsSSU2PeerTesting (bool v4) const
1054  	{
1055  		if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false;
1056  		auto addr = (*GetAddresses ())[v4 ? eSSU2V4Idx : eSSU2V6Idx];
1057  		return addr && addr->IsPeerTesting () && addr->IsReachableSSU ();
1058  	}
1059  
1060  	bool RouterInfo::IsSSU2Introducer (bool v4) const
1061  	{
1062  		if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false;
1063  		auto addr = (*GetAddresses ())[v4 ? eSSU2V4Idx : eSSU2V6Idx];
1064  		return addr && addr->IsIntroducer () && !addr->host.is_unspecified () && addr->port;
1065  	}
1066  
1067  	void RouterInfo::SetUnreachableAddressesTransportCaps (uint8_t transports)
1068  	{
1069  		for (auto& addr: *GetAddresses ())
1070  		{
1071  			if (addr && !addr->published)
1072  			{
1073  				addr->caps &= ~(eV4 | eV6);
1074  				addr->caps |= transports;
1075  			}
1076  		}
1077  	}
1078  
1079  	void RouterInfo::UpdateSupportedTransports ()
1080  	{
1081  		m_SupportedTransports = 0;
1082  		m_ReachableTransports = 0;
1083  		for (const auto& addr: *GetAddresses ())
1084  		{
1085  			if (!addr) continue;
1086  			uint8_t transports = 0;
1087  			switch (addr->transportStyle)
1088  			{
1089  				case eTransportNTCP2:
1090  					if (addr->IsV4 ()) transports |= eNTCP2V4;
1091  					if (addr->IsV6 ())
1092  						transports |= (i2p::util::net::IsYggdrasilAddress (addr->host) ? eNTCP2V6Mesh : eNTCP2V6);
1093  					if (addr->IsPublishedNTCP2 ())
1094  						m_ReachableTransports |= transports;
1095  				break;
1096  				case eTransportSSU2:
1097  					if (addr->IsV4 ()) transports |= eSSU2V4;
1098  					if (addr->IsV6 ()) transports |= eSSU2V6;
1099  					if (addr->IsReachableSSU ())
1100  						m_ReachableTransports |= transports;
1101  				break;
1102  				default: ;
1103  			}
1104  			m_SupportedTransports |= transports;
1105  		}
1106  	}
1107  
1108  	void RouterInfo::UpdateIntroducers (uint64_t ts)
1109  	{
1110  		if (ts*1000 < m_Timestamp + INTRODUCER_UPDATE_INTERVAL) return;
1111  		if (m_ReachableTransports & eSSU2V4)
1112  		{
1113  			auto addr = (*GetAddresses ())[eSSU2V4Idx];
1114  			if (addr && addr->UsesIntroducer ())
1115  			{
1116  				UpdateIntroducers (addr, ts);
1117  				if (!addr->UsesIntroducer ()) // no more valid introducers
1118  					m_ReachableTransports &= ~eSSU2V4;
1119  			}
1120  		}
1121  		if (m_ReachableTransports & eSSU2V6)
1122  		{
1123  			auto addr = (*GetAddresses ())[eSSU2V6Idx];
1124  			if (addr && addr->UsesIntroducer ())
1125  			{
1126  				UpdateIntroducers (addr, ts);
1127  				if (!addr->UsesIntroducer ()) // no more valid introducers
1128  					m_ReachableTransports &= ~eSSU2V6;
1129  			}
1130  		}
1131  	}
1132  
1133  	void RouterInfo::UpdateBuffer (const uint8_t * buf, size_t len)
1134  	{
1135  		m_IsBufferScheduledToDelete = false;
1136  		if (!m_Buffer)
1137  			m_Buffer = NewBuffer ();
1138  		if (len > m_Buffer->size ()) len = m_Buffer->size ();
1139  		memcpy (m_Buffer->data (), buf, len);
1140  		m_Buffer->SetBufferLen (len);
1141  	}
1142  
1143  	std::shared_ptr<RouterInfo::Buffer> RouterInfo::CopyBuffer () const
1144  	{
1145  		if (!m_Buffer) return nullptr;
1146  		return netdb.NewRouterInfoBuffer (*m_Buffer);
1147  	}
1148  
1149  	std::shared_ptr<RouterInfo::Buffer> RouterInfo::NewBuffer () const
1150  	{
1151  		return netdb.NewRouterInfoBuffer ();
1152  	}
1153  
1154  	std::shared_ptr<RouterInfo::Address> RouterInfo::NewAddress () const
1155  	{
1156  		return netdb.NewRouterInfoAddress ();
1157  	}
1158  
1159  	RouterInfo::AddressesPtr RouterInfo::NewAddresses () const
1160  	{
1161  		return netdb.NewRouterInfoAddresses ();
1162  	}
1163  
1164  	std::shared_ptr<IdentityEx> RouterInfo::NewIdentity (const uint8_t * buf, size_t len) const
1165  	{
1166  		return netdb.NewIdentity (buf, len);
1167  	}
1168  
1169  	void RouterInfo::RefreshTimestamp ()
1170  	{
1171  		m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
1172  	}
1173  
1174  	bool RouterInfo::IsHighCongestion (bool highBandwidth) const
1175  	{
1176  		switch (m_Congestion)
1177  		{
1178  			case eLowCongestion:
1179  				return false;
1180  			break;
1181  			case eMediumCongestion:
1182  				return highBandwidth;
1183  			break;
1184  			case eHighCongestion:
1185  				return i2p::util::GetMillisecondsSinceEpoch () < m_Timestamp + HIGH_CONGESTION_INTERVAL*1000LL;
1186  			break;
1187  			case eRejectAll:
1188  				return true;
1189  			break;
1190  			default:
1191  				return false;
1192  		}
1193  	}
1194  
1195  	std::string RouterInfo::GetTransportName (SupportedTransports tr)
1196  	{
1197  		switch (tr)
1198  		{
1199  			case eNTCP2V4: return "NTCP2V4";
1200  			case eNTCP2V6: return "NTCP2V6";
1201  			case eSSU2V4: return "SSU2V4";
1202  			case eSSU2V6: return "SSU2V6";
1203  			case eNTCP2V6Mesh: return "Mesh";
1204  			default: return "";
1205  		}
1206  	}
1207  
1208  	bool RouterInfo::IsSameSubnet (const RouterInfo& other) const
1209  	{
1210  		auto transports = m_SupportedTransports & other.m_SupportedTransports;
1211  		if (!transports) return false;
1212  		auto addresses1 = GetAddresses (), addresses2 = other.GetAddresses ();;
1213  		for (int i = 0; i < eNumTransports; i++)
1214  			if (i != eNTCP2V6MeshIdx && (transports & (1 << i)))
1215  			{
1216  				auto addr1 = (*addresses1)[i], addr2 = (*addresses2)[i];
1217  				if (addr1 && addr2 && !addr1->host.is_unspecified () && !addr2->host.is_unspecified ())
1218  					return addr1->IsSameSubnet (*addr2); // first adddess with IPs
1219  			}
1220  		return false;
1221  	}
1222  
1223  	void LocalRouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
1224  	{
1225  		RefreshTimestamp ();
1226  		std::stringstream s;
1227  		uint8_t ident[1024];
1228  		auto identLen = privateKeys.GetPublic ()->ToBuffer (ident, 1024);
1229  		auto signatureLen = privateKeys.GetPublic ()->GetSignatureLen ();
1230  		s.write ((char *)ident, identLen);
1231  		WriteToStream (s);
1232  		size_t len = s.str ().size ();
1233  		if (len + signatureLen < MAX_RI_BUFFER_SIZE)
1234  		{
1235  			UpdateBuffer ((const uint8_t *)s.str ().c_str (), len);
1236  			// signature
1237  			privateKeys.Sign (GetBuffer (), len, GetBufferPointer (len));
1238  			SetBufferLen (len + signatureLen);
1239  		}
1240  		else
1241  			LogPrint (eLogError, "RouterInfo: Our RouterInfo is too long ", len + signatureLen);
1242  	}
1243  
1244  	void LocalRouterInfo::UpdateCaps (uint8_t caps)
1245  	{
1246  		SetCaps (caps);
1247  		UpdateCapsProperty ();
1248  	}
1249  
1250  	void LocalRouterInfo::UpdateCapsProperty ()
1251  	{
1252  		std::string caps;
1253  		uint8_t c = GetCaps ();
1254  		if (c & eFloodfill)
1255  		{
1256  			if (c & eExtraBandwidth) caps += (c & eHighBandwidth) ?
1257  				CAPS_FLAG_EXTRA_BANDWIDTH2 : // 'X'
1258  				CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P'
1259  			else
1260  				caps += CAPS_FLAG_HIGH_BANDWIDTH; // 'O'
1261  			caps += CAPS_FLAG_FLOODFILL; // floodfill
1262  		}
1263  		else
1264  		{
1265  			if (c & eExtraBandwidth)
1266  				caps += (c & eHighBandwidth) ? CAPS_FLAG_EXTRA_BANDWIDTH2 /* 'X' */ : CAPS_FLAG_EXTRA_BANDWIDTH1; /*'P' */
1267  			else
1268  				caps += (c & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth
1269  		}
1270  		if (c & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden
1271  		if (c & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
1272  		if (c & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
1273  
1274  		switch (GetCongestion ())
1275  		{
1276  			case eMediumCongestion:
1277  				caps += CAPS_FLAG_MEDIUM_CONGESTION;
1278  			break;
1279  			case eHighCongestion:
1280  				caps += CAPS_FLAG_HIGH_CONGESTION;
1281  			break;
1282  			case eRejectAll:
1283  				caps += CAPS_FLAG_REJECT_ALL_CONGESTION;
1284  			break;
1285  			default: ;
1286  		};
1287  
1288  		SetProperty ("caps", caps);
1289  	}
1290  
1291  	bool LocalRouterInfo::UpdateCongestion (Congestion c)
1292  	{
1293  		if (c != GetCongestion ())
1294  		{
1295  			SetCongestion (c);
1296  			UpdateCapsProperty ();
1297  			return true;
1298  		}
1299  		return false;
1300   	}
1301  
1302  	void LocalRouterInfo::WriteToStream (std::ostream& s) const
1303  	{
1304  		auto addresses = GetAddresses ();
1305  		if (!addresses) return;
1306  
1307  		uint64_t ts = htobe64 (GetTimestamp ());
1308  		s.write ((const char *)&ts, sizeof (ts));
1309  		// addresses
1310  		uint8_t numAddresses = 0;
1311  		for (size_t idx = 0; idx < addresses->size(); idx++)
1312  		{
1313  			auto addr_ptr = (*addresses)[idx];
1314  			if (!addr_ptr) continue;
1315  			if (idx == eNTCP2V6Idx && addr_ptr == (*addresses)[eNTCP2V4Idx]) continue;
1316  			if (idx == eSSU2V6Idx && addr_ptr == (*addresses)[eSSU2V4Idx]) continue;
1317  			numAddresses++;
1318  		}
1319  		s.write ((char *)&numAddresses, sizeof (numAddresses));
1320  		for (size_t idx = 0; idx < addresses->size(); idx++)
1321  		{
1322  			auto addr_ptr = (*addresses)[idx];
1323  			if (!addr_ptr) continue;
1324  			if (idx == eNTCP2V6Idx && addr_ptr == (*addresses)[eNTCP2V4Idx]) continue;
1325  			if (idx == eSSU2V6Idx && addr_ptr == (*addresses)[eSSU2V4Idx]) continue;
1326  			const Address& address = *addr_ptr;
1327  			// calculate cost
1328  			uint8_t cost = 0x7f;
1329  			if (address.transportStyle == eTransportNTCP2)
1330  				cost = address.published ? COST_NTCP2_PUBLISHED : COST_NTCP2_NON_PUBLISHED;
1331  			else if (address.transportStyle == eTransportSSU2)
1332  				cost = address.published ? COST_SSU2_DIRECT : COST_SSU2_NON_PUBLISHED;
1333  			else
1334  				continue; // skip unknown address
1335  			s.write ((const char *)&cost, sizeof (cost));
1336  			s.write ((const char *)&address.date, sizeof (address.date));
1337  			std::stringstream properties;
1338  			bool isPublished = address.published && !address.host.is_unspecified () && address.port;
1339  			if (address.transportStyle == eTransportNTCP2)
1340  			{
1341  				WriteString ("NTCP2", s);
1342  				// caps
1343  				if (!isPublished)
1344  				{
1345  					WriteString ("caps", properties);
1346  					properties << '=';
1347  					std::string caps;
1348  					if (address.IsV4 ()) caps += CAPS_FLAG_V4;
1349  					if (address.IsV6 () || address.host.is_v6 ()) caps += CAPS_FLAG_V6; // we set 6 for unspecified ipv6
1350  					if (caps.empty ()) caps += CAPS_FLAG_V4;
1351  					WriteString (caps, properties);
1352  					properties << ';';
1353  				}
1354  			}
1355  			else if (address.transportStyle == eTransportSSU2)
1356  			{
1357  				WriteString ("SSU2", s);
1358  				// caps
1359  				std::string caps;
1360  				if (isPublished)
1361  				{
1362  					if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU2_TESTING;
1363  					if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU2_INTRODUCER;
1364  				}
1365  				else
1366  				{
1367  					if (address.IsV4 ()) caps += CAPS_FLAG_V4;
1368  					if (address.IsV6 () || address.host.is_v6 ()) caps += CAPS_FLAG_V6; // we set 6 for unspecified ipv6
1369  					if (caps.empty ()) caps += CAPS_FLAG_V4;
1370  				}
1371  				if (!caps.empty ())
1372  				{
1373  					WriteString ("caps", properties);
1374  					properties << '=';
1375  					WriteString (caps, properties);
1376  					properties << ';';
1377  				}
1378  			}
1379  			else
1380  				WriteString ("", s);
1381  
1382  			if (isPublished && !address.host.is_unspecified ())
1383  			{
1384  				WriteString ("host", properties);
1385  				properties << '=';
1386  				WriteString (address.host.to_string (), properties);
1387  				properties << ';';
1388  			}
1389  			if ((address.IsNTCP2 () && isPublished) || address.IsSSU2 ())
1390  			{
1391  				// publish i for NTCP2 or SSU2
1392  				WriteString ("i", properties); properties << '=';
1393  				size_t len = address.IsSSU2 () ? 32 : 16;
1394  				WriteString (address.i.ToBase64 (len), properties); properties << ';';
1395  			}
1396  			if (address.transportStyle == eTransportSSU2)
1397  			{
1398  				// write introducers if any
1399  				if (address.ssu && !address.ssu->introducers.empty())
1400  				{
1401  					int i = 0;
1402  					for (const auto& introducer: address.ssu->introducers)
1403  					{
1404  						if (!introducer.iTag) continue;
1405  						if (introducer.iExp) // expiration is specified
1406  						{
1407  							WriteString ("iexp" + std::to_string(i), properties);
1408  							properties << '=';
1409  							WriteString (std::to_string(introducer.iExp), properties);
1410  							properties << ';';
1411  						}
1412  						i++;
1413  					}
1414  					i = 0;
1415  					for (const auto& introducer: address.ssu->introducers)
1416  					{
1417  						if (!introducer.iTag) continue;
1418  						WriteString ("ih" + std::to_string(i), properties);
1419  						properties << '=';
1420  						auto value = ByteStreamToBase64 (introducer.iH, 32);
1421  						WriteString (value, properties);
1422  						properties << ';';
1423  						i++;
1424  					}
1425  					i = 0;
1426  					for (const auto& introducer: address.ssu->introducers)
1427  					{
1428  						if (!introducer.iTag) continue;
1429  						WriteString ("itag" + std::to_string(i), properties);
1430  						properties << '=';
1431  						WriteString (std::to_string(introducer.iTag), properties);
1432  						properties << ';';
1433  						i++;
1434  					}
1435  				}
1436  			}
1437  
1438  			if (address.IsSSU2 ())
1439  			{
1440  				// write mtu
1441  				if (address.ssu && address.ssu->mtu)
1442  				{
1443  					WriteString ("mtu", properties);
1444  					properties << '=';
1445  					WriteString (std::to_string(address.ssu->mtu), properties);
1446  					properties << ';';
1447  				}
1448  			}
1449  			if (isPublished && address.port)
1450  			{
1451  				WriteString ("port", properties);
1452  				properties << '=';
1453  				WriteString (std::to_string(address.port), properties);
1454  				properties << ';';
1455  			}
1456  			if (address.v >= 3 && address.v <= 5 && address.IsNTCP2 ()) // post quantum
1457  			{
1458                  WriteString ("pq", properties); properties << '=';
1459                  WriteString (std::to_string (address.v), properties); properties << ';';
1460  			}
1461  			if (address.IsNTCP2 () || address.IsSSU2 ())
1462  			{
1463  				// publish s and v for NTCP2 or SSU2
1464  				WriteString ("s", properties); properties << '=';
1465  				WriteString (address.s.ToBase64 (), properties); properties << ';';
1466  				WriteString ("v", properties); properties << '=';
1467  				WriteString ("2", properties); properties << ';';
1468  			}
1469  
1470  			uint16_t size = htobe16 (properties.str ().size ());
1471  			s.write ((char *)&size, sizeof (size));
1472  			s.write (properties.str ().c_str (), properties.str ().size ());
1473  		}
1474  
1475  		// peers
1476  		uint8_t numPeers = 0;
1477  		s.write ((char *)&numPeers, sizeof (numPeers));
1478  
1479  		// properties
1480  		std::stringstream properties;
1481  		for (const auto& p : m_Properties)
1482  		{
1483  			WriteString (p.first, properties);
1484  			properties << '=';
1485  			WriteString (p.second, properties);
1486  			properties << ';';
1487  		}
1488  		uint16_t size = htobe16 (properties.str ().size ());
1489  		s.write ((char *)&size, sizeof (size));
1490  		s.write (properties.str ().c_str (), properties.str ().size ());
1491  	}
1492  
1493  	void LocalRouterInfo::SetProperty (std::string_view key, std::string_view value)
1494  	{
1495  		auto [it, inserted] = m_Properties.emplace (key, value);
1496  		if (!inserted)
1497  			it->second = value;
1498  	}
1499  
1500  	void LocalRouterInfo::DeleteProperty (const std::string& key)
1501  	{
1502  		m_Properties.erase (key);
1503  	}
1504  
1505  	std::string LocalRouterInfo::GetProperty (const std::string& key) const
1506  	{
1507  		auto it = m_Properties.find (key);
1508  		if (it != m_Properties.end ())
1509  			return it->second;
1510  		return "";
1511  	}
1512  
1513  	void LocalRouterInfo::UpdateFloodfillProperty (bool floodfill)
1514  	{
1515  		if (floodfill)
1516  		{
1517  			UpdateCaps (GetCaps () | i2p::data::RouterInfo::eFloodfill);
1518  			SetFloodfill ();
1519  		}
1520  		else
1521  		{
1522  			UpdateCaps (GetCaps () & ~i2p::data::RouterInfo::eFloodfill);
1523  			ResetFloodfill ();
1524  		}
1525  	}
1526  
1527  	void LocalRouterInfo::WriteString (const std::string& str, std::ostream& s) const
1528  	{
1529  		uint8_t len = str.size ();
1530  		s.write ((char *)&len, 1);
1531  		s.write (str.c_str (), len);
1532  	}
1533  
1534  	std::shared_ptr<RouterInfo::Buffer> LocalRouterInfo::NewBuffer () const
1535  	{
1536  		return std::make_shared<Buffer> ();
1537  	}
1538  
1539  	std::shared_ptr<RouterInfo::Address> LocalRouterInfo::NewAddress () const
1540  	{
1541  		return std::make_shared<Address> ();
1542  	}
1543  
1544  	RouterInfo::AddressesPtr LocalRouterInfo::NewAddresses () const
1545  	{
1546  		return RouterInfo::AddressesPtr(new RouterInfo::Addresses ());
1547  	}
1548  
1549  	std::shared_ptr<IdentityEx> LocalRouterInfo::NewIdentity (const uint8_t * buf, size_t len) const
1550  	{
1551  		return std::make_shared<IdentityEx> (buf, len);
1552  	}
1553  
1554  	bool LocalRouterInfo::AddSSU2Introducer (const Introducer& introducer, bool v4)
1555  	{
1556  		auto addresses = GetAddresses ();
1557  		if (!addresses) return false;
1558  		auto addr = (*addresses)[v4 ? eSSU2V4Idx : eSSU2V6Idx];
1559  		if (addr)
1560  		{
1561  			for (auto& intro: addr->ssu->introducers)
1562  				if (intro.iTag == introducer.iTag) return false; // already presented
1563  			addr->ssu->introducers.push_back (introducer);
1564  			SetReachableTransports (GetReachableTransports () | ((addr->IsV4 () ? eSSU2V4 : eSSU2V6)));
1565  			return true;
1566  		}
1567  		return false;
1568  	}
1569  
1570  	bool LocalRouterInfo::RemoveSSU2Introducer (const IdentHash& h, bool v4)
1571  	{
1572  		auto addresses = GetAddresses ();
1573  		if (!addresses) return false;
1574  		auto addr = (*addresses)[v4 ? eSSU2V4Idx : eSSU2V6Idx];
1575  		if (addr)
1576  		{
1577  			for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
1578  				if (h == it->iH)
1579  				{
1580  					addr->ssu->introducers.erase (it);
1581  					if (addr->ssu->introducers.empty ())
1582  						SetReachableTransports (GetReachableTransports () & ~(addr->IsV4 () ? eSSU2V4 : eSSU2V6));
1583  					return true;
1584  				}
1585  		}
1586  		return false;
1587  	}
1588  
1589  	bool LocalRouterInfo::UpdateSSU2Introducer (const IdentHash& h, bool v4, uint32_t iTag, uint32_t iExp)
1590  	{
1591  		auto addresses = GetAddresses ();
1592  		if (!addresses) return false;
1593  		auto addr = (*addresses)[v4 ? eSSU2V4Idx : eSSU2V6Idx];
1594  		if (addr)
1595  		{
1596  			for (auto& it: addr->ssu->introducers)
1597  				if (h == it.iH)
1598  				{
1599  					it.iTag = iTag;
1600  					it.iExp = iExp;
1601  					return true;
1602  				}
1603  		}
1604  		return false;
1605  	}
1606  }
1607  }