@@ -317,6 +317,26 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
317317 return true ;
318318}
319319
320+ bool CNetAddr::HasLinkedIPv4 () const
321+ {
322+ return IsRoutable () && (IsIPv4 () || IsRFC6145 () || IsRFC6052 () || IsRFC3964 () || IsRFC4380 ());
323+ }
324+
325+ uint32_t CNetAddr::GetLinkedIPv4 () const
326+ {
327+ if (IsIPv4 () || IsRFC6145 () || IsRFC6052 ()) {
328+ // IPv4, mapped IPv4, SIIT translated IPv4: the IPv4 address is the last 4 bytes of the address
329+ return ReadBE32 (ip + 12 );
330+ } else if (IsRFC3964 ()) {
331+ // 6to4 tunneled IPv4: the IPv4 address is in bytes 2-6
332+ return ReadBE32 (ip + 2 );
333+ } else if (IsRFC4380 ()) {
334+ // Teredo tunneled IPv4: the IPv4 address is in the last 4 bytes of the address, but bitflipped
335+ return ~ReadBE32 (ip + 12 );
336+ }
337+ assert (false );
338+ }
339+
320340uint32_t CNetAddr::GetNetClass () const {
321341 uint32_t net_class = NET_IPV6;
322342 if (IsLocal ()) {
@@ -326,7 +346,7 @@ uint32_t CNetAddr::GetNetClass() const {
326346 net_class = NET_INTERNAL;
327347 } else if (!IsRoutable ()) {
328348 net_class = NET_UNROUTABLE;
329- } else if (IsIPv4 () || IsRFC6145 () || IsRFC6052 () || IsRFC3964 () || IsRFC4380 ()) {
349+ } else if (HasLinkedIPv4 ()) {
330350 net_class = NET_IPV4;
331351 } else if (IsTor ()) {
332352 net_class = NET_ONION;
@@ -340,10 +360,24 @@ uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const {
340360 return 0 ; // Indicates not found, safe because AS0 is reserved per RFC7607.
341361 }
342362 std::vector<bool > ip_bits (128 );
343- for (int8_t byte_i = 0 ; byte_i < 16 ; ++byte_i) {
344- uint8_t cur_byte = GetByte (15 - byte_i);
345- for (uint8_t bit_i = 0 ; bit_i < 8 ; ++bit_i) {
346- ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1 ;
363+ if (HasLinkedIPv4 ()) {
364+ // For lookup, treat as if it was just an IPv4 address (pchIPv4 prefix + IPv4 bits)
365+ for (int8_t byte_i = 0 ; byte_i < 12 ; ++byte_i) {
366+ for (uint8_t bit_i = 0 ; bit_i < 8 ; ++bit_i) {
367+ ip_bits[byte_i * 8 + bit_i] = (pchIPv4[byte_i] >> (7 - bit_i)) & 1 ;
368+ }
369+ }
370+ uint32_t ipv4 = GetLinkedIPv4 ();
371+ for (int i = 0 ; i < 32 ; ++i) {
372+ ip_bits[96 + i] = (ipv4 >> (31 - i)) & 1 ;
373+ }
374+ } else {
375+ // Use all 128 bits of the IPv6 address otherwise
376+ for (int8_t byte_i = 0 ; byte_i < 16 ; ++byte_i) {
377+ uint8_t cur_byte = GetByte (15 - byte_i);
378+ for (uint8_t bit_i = 0 ; bit_i < 8 ; ++bit_i) {
379+ ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1 ;
380+ }
347381 }
348382 }
349383 uint32_t mapped_as = Interpret (asmap, ip_bits);
@@ -379,51 +413,32 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
379413 int nStartByte = 0 ;
380414 int nBits = 16 ;
381415
382- // all local addresses belong to the same group
383- if (IsLocal ())
384- {
416+ if (IsLocal ()) {
417+ // all local addresses belong to the same group
385418 nBits = 0 ;
386- }
387- // all internal-usage addresses get their own group
388- if (IsInternal ())
389- {
419+ } else if (IsInternal ()) {
420+ // all internal-usage addresses get their own group
390421 nStartByte = sizeof (g_internal_prefix);
391422 nBits = (sizeof (ip) - sizeof (g_internal_prefix)) * 8 ;
392- }
393- // all other unroutable addresses belong to the same group
394- else if (!IsRoutable ())
395- {
423+ } else if (!IsRoutable ()) {
424+ // all other unroutable addresses belong to the same group
396425 nBits = 0 ;
397- }
398- // for IPv4 addresses, '1' + the 16 higher-order bits of the IP
399- // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
400- else if (IsIPv4 () || IsRFC6145 () || IsRFC6052 ())
401- {
402- nStartByte = 12 ;
403- }
404- // for 6to4 tunnelled addresses, use the encapsulated IPv4 address
405- else if (IsRFC3964 ())
406- {
407- nStartByte = 2 ;
408- }
409- // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address
410- else if (IsRFC4380 ())
411- {
412- vchRet.push_back (GetByte (3 ) ^ 0xFF );
413- vchRet.push_back (GetByte (2 ) ^ 0xFF );
426+ } else if (HasLinkedIPv4 ()) {
427+ // IPv4 addresses (and mapped IPv4 addresses) use /16 groups
428+ uint32_t ipv4 = GetLinkedIPv4 ();
429+ vchRet.push_back ((ipv4 >> 24 ) & 0xFF );
430+ vchRet.push_back ((ipv4 >> 16 ) & 0xFF );
414431 return vchRet;
415- }
416- else if (IsTor ())
417- {
432+ } else if (IsTor ()) {
418433 nStartByte = 6 ;
419434 nBits = 4 ;
420- }
421- // for he.net, use /36 groups
422- else if (GetByte (15 ) == 0x20 && GetByte (14 ) == 0x01 && GetByte (13 ) == 0x04 && GetByte (12 ) == 0x70 )
435+ } else if (GetByte (15 ) == 0x20 && GetByte (14 ) == 0x01 && GetByte (13 ) == 0x04 && GetByte (12 ) == 0x70 ) {
436+ // for he.net, use /36 groups
423437 nBits = 36 ;
424- // for the rest of the IPv6 network, use /32 groups
425- else
438+ } else {
439+ // for the rest of the IPv6 network, use /32 groups
426440 nBits = 32 ;
441+ }
427442
428443 // push our ip onto vchRet byte by byte...
429444 while (nBits >= 8 )
0 commit comments