Skip to content

Commit e527e04

Browse files
sipafurszy
authored andcommitted
Use ASNs for mapped IPv4 addresses correctly
1 parent 9a28bc0 commit e527e04

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
@@ -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+
320340
uint32_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)

src/netaddress.h

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

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

0 commit comments

Comments
 (0)