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