Skip to content

Commit 38c2395

Browse files
committed
Use ASNs for mapped IPv4 addresses correctly
1 parent 6f8c937 commit 38c2395

File tree

2 files changed

+61
-41
lines changed

2 files changed

+61
-41
lines changed

src/netaddress.cpp

Lines changed: 56 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,26 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
401401
return true;
402402
}
403403

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+
404424
uint32_t CNetAddr::GetNetClass() const {
405425
uint32_t net_class = NET_IPV6;
406426
if (IsLocal()) {
@@ -410,7 +430,7 @@ uint32_t CNetAddr::GetNetClass() const {
410430
net_class = NET_INTERNAL;
411431
} else if (!IsRoutable()) {
412432
net_class = NET_UNROUTABLE;
413-
} else if (IsIPv4() || IsRFC6145() || IsRFC6052() || IsRFC3964() || IsRFC4380()) {
433+
} else if (HasLinkedIPv4()) {
414434
net_class = NET_IPV4;
415435
} else if (IsTor()) {
416436
net_class = NET_ONION;
@@ -424,10 +444,24 @@ uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const {
424444
return 0; // Indicates not found, safe because AS0 is reserved per RFC7607.
425445
}
426446
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+
}
431465
}
432466
}
433467
uint32_t mapped_as = Interpret(asmap, ip_bits);
@@ -463,51 +497,32 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
463497
int nStartByte = 0;
464498
int nBits = 16;
465499

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
469502
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
474505
nStartByte = sizeof(g_internal_prefix);
475506
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
480509
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);
498515
return vchRet;
499-
}
500-
else if (IsTor())
501-
{
516+
} else if (IsTor()) {
502517
nStartByte = 6;
503518
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
507521
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
510524
nBits = 32;
525+
}
511526

512527
// push our ip onto vchRet byte by byte...
513528
while (nBits >= 8)

src/netaddress.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ class CNetAddr
8080
bool GetInAddr(struct in_addr* pipv4Addr) const;
8181
uint32_t GetNetClass() const;
8282

83+
//! For IPv4, mapped IPv4, SIIT translated IPv4, Teredo, 6to4 tunneled addresses, return the relevant IPv4 address as a uint32.
84+
uint32_t GetLinkedIPv4() const;
85+
//! Whether this address has a linked IPv4 address (see GetLinkedIPv4()).
86+
bool HasLinkedIPv4() const;
87+
8388
// The AS on the BGP path to the node we use to diversify
8489
// peers in AddrMan bucketing based on the AS infrastructure.
8590
// The ip->AS mapping depends on how asmap is constructed.

0 commit comments

Comments
 (0)