@@ -401,6 +401,26 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
401
401
return true ;
402
402
}
403
403
404
+ bool CNetAddr::HasLinkedIPv4 () const
405
+ {
406
+ return IsRoutable () && (IsIPv4 () || IsRFC6145 () || IsRFC6052 () || IsRFC3964 () || IsRFC4380 ());
407
+ }
408
+
409
+ uint32_t CNetAddr::GetLinkedIPv4 () const
410
+ {
411
+ if (IsIPv4 () || IsRFC6145 () || IsRFC6052 ()) {
412
+ // IPv4, mapped IPv4, SIIT translated IPv4: the IPv4 address is the last 4 bytes of the address
413
+ return ReadBE32 (ip + 12 );
414
+ } else if (IsRFC3964 ()) {
415
+ // 6to4 tunneled IPv4: the IPv4 address is in bytes 2-6
416
+ return ReadBE32 (ip + 2 );
417
+ } else if (IsRFC4380 ()) {
418
+ // Teredo tunneled IPv4: the IPv4 address is in the last 4 bytes of the address, but bitflipped
419
+ return ~ReadBE32 (ip + 12 );
420
+ }
421
+ assert (false );
422
+ }
423
+
404
424
uint32_t CNetAddr::GetNetClass () const {
405
425
uint32_t net_class = NET_IPV6;
406
426
if (IsLocal ()) {
@@ -410,7 +430,7 @@ uint32_t CNetAddr::GetNetClass() const {
410
430
net_class = NET_INTERNAL;
411
431
} else if (!IsRoutable ()) {
412
432
net_class = NET_UNROUTABLE;
413
- } else if (IsIPv4 () || IsRFC6145 () || IsRFC6052 () || IsRFC3964 () || IsRFC4380 ()) {
433
+ } else if (HasLinkedIPv4 ()) {
414
434
net_class = NET_IPV4;
415
435
} else if (IsTor ()) {
416
436
net_class = NET_ONION;
@@ -424,10 +444,24 @@ uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const {
424
444
return 0 ; // Indicates not found, safe because AS0 is reserved per RFC7607.
425
445
}
426
446
std::vector<bool > ip_bits (128 );
427
- for (int8_t byte_i = 0 ; byte_i < 16 ; ++byte_i) {
428
- uint8_t cur_byte = GetByte (15 - byte_i);
429
- for (uint8_t bit_i = 0 ; bit_i < 8 ; ++bit_i) {
430
- ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1 ;
447
+ if (HasLinkedIPv4 ()) {
448
+ // For lookup, treat as if it was just an IPv4 address (pchIPv4 prefix + IPv4 bits)
449
+ for (int8_t byte_i = 0 ; byte_i < 12 ; ++byte_i) {
450
+ for (uint8_t bit_i = 0 ; bit_i < 8 ; ++bit_i) {
451
+ ip_bits[byte_i * 8 + bit_i] = (pchIPv4[byte_i] >> (7 - bit_i)) & 1 ;
452
+ }
453
+ }
454
+ uint32_t ipv4 = GetLinkedIPv4 ();
455
+ for (int i = 0 ; i < 32 ; ++i) {
456
+ ip_bits[96 + i] = (ipv4 >> (31 - i)) & 1 ;
457
+ }
458
+ } else {
459
+ // Use all 128 bits of the IPv6 address otherwise
460
+ for (int8_t byte_i = 0 ; byte_i < 16 ; ++byte_i) {
461
+ uint8_t cur_byte = GetByte (15 - byte_i);
462
+ for (uint8_t bit_i = 0 ; bit_i < 8 ; ++bit_i) {
463
+ ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1 ;
464
+ }
431
465
}
432
466
}
433
467
uint32_t mapped_as = Interpret (asmap, ip_bits);
@@ -463,51 +497,32 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
463
497
int nStartByte = 0 ;
464
498
int nBits = 16 ;
465
499
466
- // all local addresses belong to the same group
467
- if (IsLocal ())
468
- {
500
+ if (IsLocal ()) {
501
+ // all local addresses belong to the same group
469
502
nBits = 0 ;
470
- }
471
- // all internal-usage addresses get their own group
472
- if (IsInternal ())
473
- {
503
+ } else if (IsInternal ()) {
504
+ // all internal-usage addresses get their own group
474
505
nStartByte = sizeof (g_internal_prefix);
475
506
nBits = (sizeof (ip) - sizeof (g_internal_prefix)) * 8 ;
476
- }
477
- // all other unroutable addresses belong to the same group
478
- else if (!IsRoutable ())
479
- {
507
+ } else if (!IsRoutable ()) {
508
+ // all other unroutable addresses belong to the same group
480
509
nBits = 0 ;
481
- }
482
- // for IPv4 addresses, '1' + the 16 higher-order bits of the IP
483
- // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
484
- else if (IsIPv4 () || IsRFC6145 () || IsRFC6052 ())
485
- {
486
- nStartByte = 12 ;
487
- }
488
- // for 6to4 tunnelled addresses, use the encapsulated IPv4 address
489
- else if (IsRFC3964 ())
490
- {
491
- nStartByte = 2 ;
492
- }
493
- // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address
494
- else if (IsRFC4380 ())
495
- {
496
- vchRet.push_back (GetByte (3 ) ^ 0xFF );
497
- vchRet.push_back (GetByte (2 ) ^ 0xFF );
510
+ } else if (HasLinkedIPv4 ()) {
511
+ // IPv4 addresses (and mapped IPv4 addresses) use /16 groups
512
+ uint32_t ipv4 = GetLinkedIPv4 ();
513
+ vchRet.push_back ((ipv4 >> 24 ) & 0xFF );
514
+ vchRet.push_back ((ipv4 >> 16 ) & 0xFF );
498
515
return vchRet;
499
- }
500
- else if (IsTor ())
501
- {
516
+ } else if (IsTor ()) {
502
517
nStartByte = 6 ;
503
518
nBits = 4 ;
504
- }
505
- // for he.net, use /36 groups
506
- else if (GetByte (15 ) == 0x20 && GetByte (14 ) == 0x01 && GetByte (13 ) == 0x04 && GetByte (12 ) == 0x70 )
519
+ } else if (GetByte (15 ) == 0x20 && GetByte (14 ) == 0x01 && GetByte (13 ) == 0x04 && GetByte (12 ) == 0x70 ) {
520
+ // for he.net, use /36 groups
507
521
nBits = 36 ;
508
- // for the rest of the IPv6 network, use /32 groups
509
- else
522
+ } else {
523
+ // for the rest of the IPv6 network, use /32 groups
510
524
nBits = 32 ;
525
+ }
511
526
512
527
// push our ip onto vchRet byte by byte...
513
528
while (nBits >= 8 )
0 commit comments