aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2020-01-29 15:02:26 -0800
committerPieter Wuille <pieter.wuille@gmail.com>2020-01-31 14:51:37 -0800
commit38c2395d7a905c87dc4630031849fd8e403e61bf (patch)
treef180aea5ac3ce5a4bdf6722a0e5e94878de5f84d
parent6f8c93731203c111f86c39eaf2102f9a825d1706 (diff)
Use ASNs for mapped IPv4 addresses correctly
-rw-r--r--src/netaddress.cpp97
-rw-r--r--src/netaddress.h5
2 files changed, 61 insertions, 41 deletions
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index ce3e17197e..1cac57a817 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -401,6 +401,26 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
return true;
}
+bool CNetAddr::HasLinkedIPv4() const
+{
+ return IsRoutable() && (IsIPv4() || IsRFC6145() || IsRFC6052() || IsRFC3964() || IsRFC4380());
+}
+
+uint32_t CNetAddr::GetLinkedIPv4() const
+{
+ if (IsIPv4() || IsRFC6145() || IsRFC6052()) {
+ // IPv4, mapped IPv4, SIIT translated IPv4: the IPv4 address is the last 4 bytes of the address
+ return ReadBE32(ip + 12);
+ } else if (IsRFC3964()) {
+ // 6to4 tunneled IPv4: the IPv4 address is in bytes 2-6
+ return ReadBE32(ip + 2);
+ } else if (IsRFC4380()) {
+ // Teredo tunneled IPv4: the IPv4 address is in the last 4 bytes of the address, but bitflipped
+ return ~ReadBE32(ip + 12);
+ }
+ assert(false);
+}
+
uint32_t CNetAddr::GetNetClass() const {
uint32_t net_class = NET_IPV6;
if (IsLocal()) {
@@ -410,7 +430,7 @@ uint32_t CNetAddr::GetNetClass() const {
net_class = NET_INTERNAL;
} else if (!IsRoutable()) {
net_class = NET_UNROUTABLE;
- } else if (IsIPv4() || IsRFC6145() || IsRFC6052() || IsRFC3964() || IsRFC4380()) {
+ } else if (HasLinkedIPv4()) {
net_class = NET_IPV4;
} else if (IsTor()) {
net_class = NET_ONION;
@@ -424,10 +444,24 @@ uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const {
return 0; // Indicates not found, safe because AS0 is reserved per RFC7607.
}
std::vector<bool> ip_bits(128);
- for (int8_t byte_i = 0; byte_i < 16; ++byte_i) {
- uint8_t cur_byte = GetByte(15 - byte_i);
- for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
- ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1;
+ if (HasLinkedIPv4()) {
+ // For lookup, treat as if it was just an IPv4 address (pchIPv4 prefix + IPv4 bits)
+ for (int8_t byte_i = 0; byte_i < 12; ++byte_i) {
+ for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
+ ip_bits[byte_i * 8 + bit_i] = (pchIPv4[byte_i] >> (7 - bit_i)) & 1;
+ }
+ }
+ uint32_t ipv4 = GetLinkedIPv4();
+ for (int i = 0; i < 32; ++i) {
+ ip_bits[96 + i] = (ipv4 >> (31 - i)) & 1;
+ }
+ } else {
+ // Use all 128 bits of the IPv6 address otherwise
+ for (int8_t byte_i = 0; byte_i < 16; ++byte_i) {
+ uint8_t cur_byte = GetByte(15 - byte_i);
+ for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
+ ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1;
+ }
}
}
uint32_t mapped_as = Interpret(asmap, ip_bits);
@@ -463,51 +497,32 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
int nStartByte = 0;
int nBits = 16;
- // all local addresses belong to the same group
- if (IsLocal())
- {
+ if (IsLocal()) {
+ // all local addresses belong to the same group
nBits = 0;
- }
- // all internal-usage addresses get their own group
- if (IsInternal())
- {
+ } else if (IsInternal()) {
+ // all internal-usage addresses get their own group
nStartByte = sizeof(g_internal_prefix);
nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8;
- }
- // all other unroutable addresses belong to the same group
- else if (!IsRoutable())
- {
+ } else if (!IsRoutable()) {
+ // all other unroutable addresses belong to the same group
nBits = 0;
- }
- // for IPv4 addresses, '1' + the 16 higher-order bits of the IP
- // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
- else if (IsIPv4() || IsRFC6145() || IsRFC6052())
- {
- nStartByte = 12;
- }
- // for 6to4 tunnelled addresses, use the encapsulated IPv4 address
- else if (IsRFC3964())
- {
- nStartByte = 2;
- }
- // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address
- else if (IsRFC4380())
- {
- vchRet.push_back(GetByte(3) ^ 0xFF);
- vchRet.push_back(GetByte(2) ^ 0xFF);
+ } else if (HasLinkedIPv4()) {
+ // IPv4 addresses (and mapped IPv4 addresses) use /16 groups
+ uint32_t ipv4 = GetLinkedIPv4();
+ vchRet.push_back((ipv4 >> 24) & 0xFF);
+ vchRet.push_back((ipv4 >> 16) & 0xFF);
return vchRet;
- }
- else if (IsTor())
- {
+ } else if (IsTor()) {
nStartByte = 6;
nBits = 4;
- }
- // for he.net, use /36 groups
- else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && GetByte(12) == 0x70)
+ } else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && GetByte(12) == 0x70) {
+ // for he.net, use /36 groups
nBits = 36;
- // for the rest of the IPv6 network, use /32 groups
- else
+ } else {
+ // for the rest of the IPv6 network, use /32 groups
nBits = 32;
+ }
// push our ip onto vchRet byte by byte...
while (nBits >= 8)
diff --git a/src/netaddress.h b/src/netaddress.h
index 078234595c..1270e71606 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -80,6 +80,11 @@ class CNetAddr
bool GetInAddr(struct in_addr* pipv4Addr) const;
uint32_t GetNetClass() const;
+ //! For IPv4, mapped IPv4, SIIT translated IPv4, Teredo, 6to4 tunneled addresses, return the relevant IPv4 address as a uint32.
+ uint32_t GetLinkedIPv4() const;
+ //! Whether this address has a linked IPv4 address (see GetLinkedIPv4()).
+ bool HasLinkedIPv4() const;
+
// The AS on the BGP path to the node we use to diversify
// peers in AddrMan bucketing based on the AS infrastructure.
// The ip->AS mapping depends on how asmap is constructed.