Return mapped AS in RPC call getpeerinfo

If ASN bucketing is used, return a corresponding AS
used in bucketing for a given peer.
This commit is contained in:
Gleb Naumenko
2019-12-24 13:26:46 -05:00
parent ec45646de9
commit e4658aa8ea
5 changed files with 62 additions and 35 deletions

View File

@@ -401,6 +401,39 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
return true;
}
uint32_t CNetAddr::GetNetClass() const {
uint32_t net_class = NET_IPV6;
if (IsLocal()) {
net_class = 255;
}
if (IsInternal()) {
net_class = NET_INTERNAL;
} else if (!IsRoutable()) {
net_class = NET_UNROUTABLE;
} else if (IsIPv4() || IsRFC6145() || IsRFC6052() || IsRFC3964() || IsRFC4380()) {
net_class = NET_IPV4;
} else if (IsTor()) {
net_class = NET_ONION;
}
return net_class;
}
uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const {
uint32_t net_class = GetNetClass();
if (asmap.size() == 0 || (net_class != NET_IPV4 && net_class != NET_IPV6)) {
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;
}
}
uint32_t mapped_as = Interpret(asmap, ip_bits);
return mapped_as;
}
/**
* Get the canonical identifier of our network group
*
@@ -414,53 +447,58 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) const
{
std::vector<unsigned char> vchRet;
int nClass = NET_IPV6;
uint32_t net_class = GetNetClass();
// If non-empty asmap is supplied and the address is IPv4/IPv6,
// return ASN to be used for bucketing.
uint32_t asn = GetMappedAS(asmap);
if (asn != 0) { // Either asmap was empty, or address has non-asmappable net class (e.g. TOR).
vchRet.push_back(NET_IPV6); // IPv4 and IPv6 with same ASN should be in the same bucket
for (int i = 0; i < 4; i++) {
vchRet.push_back((asn >> (8 * i)) & 0xFF);
}
return vchRet;
}
vchRet.push_back(net_class);
int nStartByte = 0;
int nBits = 16;
// all local addresses belong to the same group
if (IsLocal())
{
nClass = 255;
nBits = 0;
}
// all internal-usage addresses get their own group
if (IsInternal())
{
nClass = NET_INTERNAL;
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())
{
nClass = NET_UNROUTABLE;
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())
{
nClass = NET_IPV4;
nStartByte = 12;
}
// for 6to4 tunnelled addresses, use the encapsulated IPv4 address
else if (IsRFC3964())
{
nClass = NET_IPV4;
nStartByte = 2;
}
// for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address
else if (IsRFC4380())
{
vchRet.push_back(NET_IPV4);
vchRet.push_back(GetByte(3) ^ 0xFF);
vchRet.push_back(GetByte(2) ^ 0xFF);
return vchRet;
}
else if (IsTor())
{
nClass = NET_ONION;
nStartByte = 6;
nBits = 4;
}
@@ -471,29 +509,6 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
else
nBits = 32;
// If asmap is supplied and the address is IPv4/IPv6,
// ignore nBits and use 32/128 bits to obtain ASN from asmap.
// ASN is then returned to be used for bucketing.
if (asmap.size() != 0 && (nClass == NET_IPV4 || nClass == NET_IPV6)) {
nClass = NET_IPV6;
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;
}
}
uint32_t asn = Interpret(asmap, ip_bits);
vchRet.push_back(nClass);
for (int i = 0; i < 4; i++) {
vchRet.push_back((asn >> (8 * i)) & 0xFF);
}
return vchRet;
}
vchRet.push_back(nClass);
// push our ip onto vchRet byte by byte...
while (nBits >= 8)
{