13
13
#include < compat.h>
14
14
#include < prevector.h>
15
15
#include < serialize.h>
16
+ #include < tinyformat.h>
17
+ #include < util/strencodings.h>
18
+ #include < util/string.h>
16
19
17
20
#include < array>
18
21
#include < cstdint>
22
+ #include < ios>
19
23
#include < string>
20
24
#include < vector>
21
25
26
+ /* *
27
+ * A flag that is ORed into the protocol version to designate that addresses
28
+ * should be serialized in (unserialized from) v2 format (BIP155).
29
+ * Make sure that this does not collide with any of the values in `version.h`
30
+ * or with `SERIALIZE_TRANSACTION_NO_WITNESS`.
31
+ */
32
+ static const int ADDRV2_FORMAT = 0x20000000 ;
33
+
22
34
/* *
23
35
* A network type.
24
36
* @note An address may belong to more than one network, for example `10.0.0.1`
@@ -177,7 +189,11 @@ class CNetAddr
177
189
template <typename Stream>
178
190
void Serialize (Stream& s) const
179
191
{
180
- SerializeV1Stream (s);
192
+ if (s.GetVersion () & ADDRV2_FORMAT) {
193
+ SerializeV2Stream (s);
194
+ } else {
195
+ SerializeV1Stream (s);
196
+ }
181
197
}
182
198
183
199
/* *
@@ -186,17 +202,53 @@ class CNetAddr
186
202
template <typename Stream>
187
203
void Unserialize (Stream& s)
188
204
{
189
- UnserializeV1Stream (s);
205
+ if (s.GetVersion () & ADDRV2_FORMAT) {
206
+ UnserializeV2Stream (s);
207
+ } else {
208
+ UnserializeV1Stream (s);
209
+ }
190
210
}
191
211
192
212
friend class CSubNet ;
193
213
194
214
private:
215
+ /* *
216
+ * BIP155 network ids recognized by this software.
217
+ */
218
+ enum BIP155Network : uint8_t {
219
+ IPV4 = 1 ,
220
+ IPV6 = 2 ,
221
+ TORV2 = 3 ,
222
+ };
223
+
195
224
/* *
196
225
* Size of CNetAddr when serialized as ADDRv1 (pre-BIP155) (in bytes).
197
226
*/
198
227
static constexpr size_t V1_SERIALIZATION_SIZE = ADDR_IPV6_SIZE;
199
228
229
+ /* *
230
+ * Maximum size of an address as defined in BIP155 (in bytes).
231
+ * This is only the size of the address, not the entire CNetAddr object
232
+ * when serialized.
233
+ */
234
+ static constexpr size_t MAX_ADDRV2_SIZE = 512 ;
235
+
236
+ /* *
237
+ * Get the BIP155 network id of this address.
238
+ * Must not be called for IsInternal() objects.
239
+ * @returns BIP155 network id
240
+ */
241
+ BIP155Network GetBIP155Network () const ;
242
+
243
+ /* *
244
+ * Set `m_net` from the provided BIP155 network id and size after validation.
245
+ * @retval true the network was recognized, is valid and `m_net` was set
246
+ * @retval false not recognised (from future?) and should be silently ignored
247
+ * @throws std::ios_base::failure if the network is one of the BIP155 founding
248
+ * networks recognized by this software (id 1..3) and has wrong address size.
249
+ */
250
+ bool SetNetFromBIP155Network (uint8_t possible_bip155_net, size_t address_size);
251
+
200
252
/* *
201
253
* Serialize in pre-ADDRv2/BIP155 format to an array.
202
254
* Some addresses (e.g. TORv3) cannot be serialized in pre-BIP155 format.
@@ -250,6 +302,25 @@ class CNetAddr
250
302
s << serialized;
251
303
}
252
304
305
+ /* *
306
+ * Serialize as ADDRv2 / BIP155.
307
+ */
308
+ template <typename Stream>
309
+ void SerializeV2Stream (Stream& s) const
310
+ {
311
+ if (IsInternal ()) {
312
+ // Serialize NET_INTERNAL as embedded in IPv6. We need to
313
+ // serialize such addresses from addrman.
314
+ s << static_cast <uint8_t >(BIP155Network::IPV6);
315
+ s << COMPACTSIZE (ADDR_IPV6_SIZE);
316
+ SerializeV1Stream (s);
317
+ return ;
318
+ }
319
+
320
+ s << static_cast <uint8_t >(GetBIP155Network ());
321
+ s << m_addr;
322
+ }
323
+
253
324
/* *
254
325
* Unserialize from a pre-ADDRv2/BIP155 format from an array.
255
326
*/
@@ -272,6 +343,65 @@ class CNetAddr
272
343
273
344
UnserializeV1Array (serialized);
274
345
}
346
+
347
+ /* *
348
+ * Unserialize from a ADDRv2 / BIP155 format.
349
+ */
350
+ template <typename Stream>
351
+ void UnserializeV2Stream (Stream& s)
352
+ {
353
+ uint8_t bip155_net;
354
+ s >> bip155_net;
355
+
356
+ size_t address_size;
357
+ s >> COMPACTSIZE (address_size);
358
+
359
+ if (address_size > MAX_ADDRV2_SIZE) {
360
+ throw std::ios_base::failure (strprintf (
361
+ " Address too long: %u > %u" , address_size, MAX_ADDRV2_SIZE));
362
+ }
363
+
364
+ scopeId = 0 ;
365
+
366
+ if (SetNetFromBIP155Network (bip155_net, address_size)) {
367
+ m_addr.resize (address_size);
368
+ s >> MakeSpan (m_addr);
369
+
370
+ if (m_net != NET_IPV6) {
371
+ return ;
372
+ }
373
+
374
+ // Do some special checks on IPv6 addresses.
375
+
376
+ // Recognize NET_INTERNAL embedded in IPv6, such addresses are not
377
+ // gossiped but could be coming from addrman, when unserializing from
378
+ // disk.
379
+ if (HasPrefix (m_addr, INTERNAL_IN_IPV6_PREFIX)) {
380
+ m_net = NET_INTERNAL;
381
+ memmove (m_addr.data (), m_addr.data () + INTERNAL_IN_IPV6_PREFIX.size (),
382
+ ADDR_INTERNAL_SIZE);
383
+ m_addr.resize (ADDR_INTERNAL_SIZE);
384
+ return ;
385
+ }
386
+
387
+ if (!HasPrefix (m_addr, IPV4_IN_IPV6_PREFIX) &&
388
+ !HasPrefix (m_addr, TORV2_IN_IPV6_PREFIX)) {
389
+ return ;
390
+ }
391
+
392
+ // IPv4 and TORv2 are not supposed to be embedded in IPv6 (like in V1
393
+ // encoding). Unserialize as !IsValid(), thus ignoring them.
394
+ } else {
395
+ // If we receive an unknown BIP155 network id (from the future?) then
396
+ // ignore the address - unserialize as !IsValid().
397
+ s.ignore (address_size);
398
+ }
399
+
400
+ // Mimic a default-constructed CNetAddr object which is !IsValid() and thus
401
+ // will not be gossiped, but continue reading next addresses from the stream.
402
+ m_net = NET_IPV6;
403
+ m_addr.assign (ADDR_IPV6_SIZE, 0x0 );
404
+ }
275
405
};
276
406
277
407
class CSubNet
0 commit comments