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 #ifndef ROUTER_INFO_H__ 10 #define ROUTER_INFO_H__ 11 12 #include <inttypes.h> 13 #include <string> 14 #include <map> 15 #include <vector> 16 #include <iostream> 17 #include <boost/asio.hpp> 18 #include <boost/shared_ptr.hpp> 19 #include "Identity.h" 20 #include "Profiling.h" 21 22 namespace i2p 23 { 24 namespace data 25 { 26 const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets"; 27 const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters"; 28 const char ROUTER_INFO_PROPERTY_NETID[] = "netId"; 29 const char ROUTER_INFO_PROPERTY_VERSION[] = "router.version"; 30 const char ROUTER_INFO_PROPERTY_FAMILY[] = "family"; 31 const char ROUTER_INFO_PROPERTY_FAMILY_SIG[] = "family.sig"; 32 33 const char CAPS_FLAG_FLOODFILL = 'f'; 34 const char CAPS_FLAG_HIDDEN = 'H'; 35 const char CAPS_FLAG_REACHABLE = 'R'; 36 const char CAPS_FLAG_UNREACHABLE = 'U'; 37 /* bandwidth flags */ 38 const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; /* < 12 KBps */ 39 const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L'; /* 12-48 KBps */ 40 const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M'; /* 48-64 KBps */ 41 const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N'; /* 64-128 KBps */ 42 const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */ 43 const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */ 44 const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */ 45 46 const char CAPS_FLAG_V4 = '4'; 47 const char CAPS_FLAG_V6 = '6'; 48 const char CAPS_FLAG_SSU_TESTING = 'B'; 49 const char CAPS_FLAG_SSU_INTRODUCER = 'C'; 50 51 const uint8_t COST_NTCP2_PUBLISHED = 3; 52 const uint8_t COST_NTCP2_NON_PUBLISHED = 14; 53 const uint8_t COST_SSU_DIRECT = 9; 54 const uint8_t COST_SSU_THROUGH_INTRODUCERS = 11; 55 56 const int MAX_RI_BUFFER_SIZE = 2048; // if RouterInfo exceeds 2048 we consider it as malformed, might be changed later 57 class RouterInfo: public RoutingDestination 58 { 59 public: 60 61 enum SupportedTransports 62 { 63 eNTCP2V4 = 0x01, 64 eNTCP2V6 = 0x02, 65 eSSUV4 = 0x04, 66 eSSUV6 = 0x08, 67 eNTCP2V6Mesh = 0x10, 68 eAllTransports = 0xFF 69 }; 70 typedef uint8_t CompatibleTransports; 71 72 enum Caps 73 { 74 eFloodfill = 0x01, 75 eHighBandwidth = 0x02, 76 eExtraBandwidth = 0x04, 77 eReachable = 0x08, 78 eHidden = 0x10, 79 eUnreachable = 0x20 80 }; 81 82 enum AddressCaps 83 { 84 eV4 = 0x01, 85 eV6 = 0x02, 86 eSSUTesting = 0x04, 87 eSSUIntroducer = 0x08 88 }; 89 90 enum TransportStyle 91 { 92 eTransportUnknown = 0, 93 eTransportNTCP, 94 eTransportSSU 95 }; 96 97 typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey 98 struct Introducer 99 { IntroducerIntroducer100 Introducer (): iPort (0), iExp (0) {}; 101 boost::asio::ip::address iHost; 102 int iPort; 103 IntroKey iKey; 104 uint32_t iTag; 105 uint32_t iExp; 106 }; 107 108 struct SSUExt 109 { 110 int mtu; 111 IntroKey key; // intro key for SSU 112 std::vector<Introducer> introducers; 113 }; 114 115 struct NTCP2Ext 116 { 117 Tag<32> staticKey; 118 Tag<16> iv; 119 }; 120 121 struct Address 122 { 123 TransportStyle transportStyle; 124 boost::asio::ip::address host; 125 int port; 126 uint64_t date; 127 uint8_t caps; 128 bool published = false; 129 std::unique_ptr<SSUExt> ssu; // not null for SSU 130 std::unique_ptr<NTCP2Ext> ntcp2; // not null for NTCP2 131 IsCompatibleAddress132 bool IsCompatible (const boost::asio::ip::address& other) const 133 { 134 return (IsV4 () && other.is_v4 ()) || 135 (IsV6 () && other.is_v6 ()); 136 } 137 138 bool operator==(const Address& other) const 139 { 140 return transportStyle == other.transportStyle && IsNTCP2 () == other.IsNTCP2 () && 141 host == other.host && port == other.port; 142 } 143 144 bool operator!=(const Address& other) const 145 { 146 return !(*this == other); 147 } 148 IsNTCP2Address149 bool IsNTCP2 () const { return (bool)ntcp2; }; IsPublishedNTCP2Address150 bool IsPublishedNTCP2 () const { return IsNTCP2 () && published; }; IsReachableSSUAddress151 bool IsReachableSSU () const { return (bool)ssu && (published || !ssu->introducers.empty ()); }; UsesIntroducerAddress152 bool UsesIntroducer () const { return (bool)ssu && !ssu->introducers.empty (); }; 153 IsIntroducerAddress154 bool IsIntroducer () const { return caps & eSSUIntroducer; }; IsPeerTestingAddress155 bool IsPeerTesting () const { return caps & eSSUTesting; }; 156 IsV4Address157 bool IsV4 () const { return (caps & AddressCaps::eV4) || (host.is_v4 () && !host.is_unspecified ()); }; IsV6Address158 bool IsV6 () const { return (caps & AddressCaps::eV6) || (host.is_v6 () && !host.is_unspecified ()); }; 159 }; 160 typedef std::vector<std::shared_ptr<Address> > Addresses; 161 162 RouterInfo (); 163 RouterInfo (const std::string& fullPath); 164 RouterInfo (const RouterInfo& ) = default; 165 RouterInfo& operator=(const RouterInfo& ) = default; 166 RouterInfo (const uint8_t * buf, int len); 167 ~RouterInfo (); 168 GetRouterIdentity()169 std::shared_ptr<const IdentityEx> GetRouterIdentity () const { return m_RouterIdentity; }; 170 void SetRouterIdentity (std::shared_ptr<const IdentityEx> identity); GetIdentHashBase64()171 std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); }; GetTimestamp()172 uint64_t GetTimestamp () const { return m_Timestamp; }; GetVersion()173 int GetVersion () const { return m_Version; }; GetAddresses()174 Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr 175 std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey (const uint8_t * key) const; 176 std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const; 177 std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const; 178 std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const; 179 std::shared_ptr<const Address> GetSSUV6Address () const; 180 std::shared_ptr<const Address> GetYggdrasilAddress () const; 181 182 void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0); 183 void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv, 184 const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0); 185 bool AddIntroducer (const Introducer& introducer); 186 bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); 187 void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only 188 void DeleteProperty (const std::string& key); // called from RouterContext only 189 std::string GetProperty (const std::string& key) const; // called from RouterContext only ClearProperties()190 void ClearProperties () { m_Properties.clear (); }; 191 void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps 192 void UpdateSupportedTransports (); IsFloodfill()193 bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; }; IsReachable()194 bool IsReachable () const { return m_Caps & Caps::eReachable; }; IsECIES()195 bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; }; 196 bool IsSSU (bool v4only = true) const; 197 bool IsSSUV6 () const; 198 bool IsNTCP2 (bool v4only = true) const; 199 bool IsNTCP2V6 () const; 200 bool IsV6 () const; 201 bool IsV4 () const; 202 bool IsMesh () const; 203 void EnableV6 (); 204 void DisableV6 (); 205 void EnableV4 (); 206 void DisableV4 (); 207 void EnableMesh (); 208 void DisableMesh (); IsCompatible(const RouterInfo & other)209 bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; IsReachableFrom(const RouterInfo & other)210 bool IsReachableFrom (const RouterInfo& other) const { return m_ReachableTransports & other.m_SupportedTransports; }; IsReachableBy(CompatibleTransports transports)211 bool IsReachableBy (CompatibleTransports transports) const { return m_ReachableTransports & transports; }; GetCompatibleTransports(bool incoming)212 CompatibleTransports GetCompatibleTransports (bool incoming) const { return incoming ? m_ReachableTransports : m_SupportedTransports; }; HasValidAddresses()213 bool HasValidAddresses () const { return m_SupportedTransports; }; IsHidden()214 bool IsHidden () const { return m_Caps & eHidden; }; IsHighBandwidth()215 bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; }; IsExtraBandwidth()216 bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; }; 217 bool IsEligibleFloodfill () const; 218 bool IsPeerTesting (bool v4) const; 219 bool IsIntroducer (bool v4) const; 220 GetCaps()221 uint8_t GetCaps () const { return m_Caps; }; 222 void SetCaps (uint8_t caps); 223 void SetCaps (const char * caps); 224 SetUnreachable(bool unreachable)225 void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; IsUnreachable()226 bool IsUnreachable () const { return m_IsUnreachable; }; 227 GetBuffer()228 const uint8_t * GetBuffer () const { return m_Buffer; }; 229 const uint8_t * LoadBuffer (const std::string& fullPath); // load if necessary GetBufferLen()230 int GetBufferLen () const { return m_BufferLen; }; 231 void CreateBuffer (const PrivateKeys& privateKeys); 232 IsUpdated()233 bool IsUpdated () const { return m_IsUpdated; }; SetUpdated(bool updated)234 void SetUpdated (bool updated) { m_IsUpdated = updated; }; 235 bool SaveToFile (const std::string& fullPath); 236 237 std::shared_ptr<RouterProfile> GetProfile () const; SaveProfile()238 void SaveProfile () { if (m_Profile) m_Profile->Save (GetIdentHash ()); }; 239 240 void Update (const uint8_t * buf, size_t len); DeleteBuffer()241 void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; }; 242 bool IsNewer (const uint8_t * buf, size_t len) const; 243 244 /** return true if we are in a router family and the signature is valid */ 245 bool IsFamily(const std::string & fam) const; 246 247 // implements RoutingDestination GetIdentity()248 std::shared_ptr<const IdentityEx> GetIdentity () const { return m_RouterIdentity; }; 249 void Encrypt (const uint8_t * data, uint8_t * encrypted) const; 250 IsDestination()251 bool IsDestination () const { return false; }; 252 253 private: 254 255 bool LoadFile (const std::string& fullPath); 256 void ReadFromFile (const std::string& fullPath); 257 void ReadFromStream (std::istream& s); 258 void ReadFromBuffer (bool verifySignature); 259 void WriteToStream (std::ostream& s) const; 260 size_t ReadString (char* str, size_t len, std::istream& s) const; 261 void WriteString (const std::string& str, std::ostream& s) const; 262 void ExtractCaps (const char * value); 263 uint8_t ExtractAddressCaps (const char * value) const; 264 template<typename Filter> 265 std::shared_ptr<const Address> GetAddress (Filter filter) const; 266 void UpdateCapsProperty (); 267 268 private: 269 270 std::string m_Family; 271 std::shared_ptr<const IdentityEx> m_RouterIdentity; 272 uint8_t * m_Buffer; 273 size_t m_BufferLen; 274 uint64_t m_Timestamp; 275 boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9 276 std::map<std::string, std::string> m_Properties; 277 bool m_IsUpdated, m_IsUnreachable; 278 CompatibleTransports m_SupportedTransports, m_ReachableTransports; 279 uint8_t m_Caps; 280 int m_Version; 281 mutable std::shared_ptr<RouterProfile> m_Profile; 282 }; 283 } 284 } 285 286 #endif 287