Skip to content

Commit e4658aa

Browse files
committed
Return mapped AS in RPC call getpeerinfo
If ASN bucketing is used, return a corresponding AS used in bucketing for a given peer.
1 parent ec45646 commit e4658aa

File tree

5 files changed

+62
-35
lines changed

5 files changed

+62
-35
lines changed

src/net.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,12 +493,13 @@ void CNode::SetAddrLocal(const CService& addrLocalIn) {
493493

494494
#undef X
495495
#define X(name) stats.name = name
496-
void CNode::copyStats(CNodeStats &stats)
496+
void CNode::copyStats(CNodeStats &stats, std::vector<bool> &m_asmap)
497497
{
498498
stats.nodeid = this->GetId();
499499
X(nServices);
500500
X(addr);
501501
X(addrBind);
502+
stats.m_mapped_as = addr.GetMappedAS(m_asmap);
502503
if (m_tx_relay != nullptr) {
503504
LOCK(m_tx_relay->cs_filter);
504505
stats.fRelayTxes = m_tx_relay->fRelayTxes;
@@ -2491,7 +2492,7 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats)
24912492
vstats.reserve(vNodes.size());
24922493
for (CNode* pnode : vNodes) {
24932494
vstats.emplace_back();
2494-
pnode->copyStats(vstats.back());
2495+
pnode->copyStats(vstats.back(), addrman.m_asmap);
24952496
}
24962497
}
24972498

src/net.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ class CNodeStats
606606
CAddress addr;
607607
// Bind address of our side of the connection
608608
CAddress addrBind;
609+
uint32_t m_mapped_as;
609610
};
610611

611612

@@ -982,7 +983,7 @@ class CNode
982983

983984
void CloseSocketDisconnect();
984985

985-
void copyStats(CNodeStats &stats);
986+
void copyStats(CNodeStats &stats, std::vector<bool> &m_asmap);
986987

987988
ServiceFlags GetLocalServices() const
988989
{

src/netaddress.cpp

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

404+
uint32_t CNetAddr::GetNetClass() const {
405+
uint32_t net_class = NET_IPV6;
406+
if (IsLocal()) {
407+
net_class = 255;
408+
}
409+
if (IsInternal()) {
410+
net_class = NET_INTERNAL;
411+
} else if (!IsRoutable()) {
412+
net_class = NET_UNROUTABLE;
413+
} else if (IsIPv4() || IsRFC6145() || IsRFC6052() || IsRFC3964() || IsRFC4380()) {
414+
net_class = NET_IPV4;
415+
} else if (IsTor()) {
416+
net_class = NET_ONION;
417+
}
418+
return net_class;
419+
}
420+
421+
uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const {
422+
uint32_t net_class = GetNetClass();
423+
if (asmap.size() == 0 || (net_class != NET_IPV4 && net_class != NET_IPV6)) {
424+
return 0; // Indicates not found, safe because AS0 is reserved per RFC7607.
425+
}
426+
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;
431+
}
432+
}
433+
uint32_t mapped_as = Interpret(asmap, ip_bits);
434+
return mapped_as;
435+
}
436+
404437
/**
405438
* Get the canonical identifier of our network group
406439
*
@@ -414,53 +447,58 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
414447
std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) const
415448
{
416449
std::vector<unsigned char> vchRet;
417-
int nClass = NET_IPV6;
450+
uint32_t net_class = GetNetClass();
451+
// If non-empty asmap is supplied and the address is IPv4/IPv6,
452+
// return ASN to be used for bucketing.
453+
uint32_t asn = GetMappedAS(asmap);
454+
if (asn != 0) { // Either asmap was empty, or address has non-asmappable net class (e.g. TOR).
455+
vchRet.push_back(NET_IPV6); // IPv4 and IPv6 with same ASN should be in the same bucket
456+
for (int i = 0; i < 4; i++) {
457+
vchRet.push_back((asn >> (8 * i)) & 0xFF);
458+
}
459+
return vchRet;
460+
}
461+
462+
vchRet.push_back(net_class);
418463
int nStartByte = 0;
419464
int nBits = 16;
420465

421466
// all local addresses belong to the same group
422467
if (IsLocal())
423468
{
424-
nClass = 255;
425469
nBits = 0;
426470
}
427471
// all internal-usage addresses get their own group
428472
if (IsInternal())
429473
{
430-
nClass = NET_INTERNAL;
431474
nStartByte = sizeof(g_internal_prefix);
432475
nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8;
433476
}
434477
// all other unroutable addresses belong to the same group
435478
else if (!IsRoutable())
436479
{
437-
nClass = NET_UNROUTABLE;
438480
nBits = 0;
439481
}
440482
// for IPv4 addresses, '1' + the 16 higher-order bits of the IP
441483
// includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
442484
else if (IsIPv4() || IsRFC6145() || IsRFC6052())
443485
{
444-
nClass = NET_IPV4;
445486
nStartByte = 12;
446487
}
447488
// for 6to4 tunnelled addresses, use the encapsulated IPv4 address
448489
else if (IsRFC3964())
449490
{
450-
nClass = NET_IPV4;
451491
nStartByte = 2;
452492
}
453493
// for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address
454494
else if (IsRFC4380())
455495
{
456-
vchRet.push_back(NET_IPV4);
457496
vchRet.push_back(GetByte(3) ^ 0xFF);
458497
vchRet.push_back(GetByte(2) ^ 0xFF);
459498
return vchRet;
460499
}
461500
else if (IsTor())
462501
{
463-
nClass = NET_ONION;
464502
nStartByte = 6;
465503
nBits = 4;
466504
}
@@ -471,29 +509,6 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
471509
else
472510
nBits = 32;
473511

474-
// If asmap is supplied and the address is IPv4/IPv6,
475-
// ignore nBits and use 32/128 bits to obtain ASN from asmap.
476-
// ASN is then returned to be used for bucketing.
477-
if (asmap.size() != 0 && (nClass == NET_IPV4 || nClass == NET_IPV6)) {
478-
nClass = NET_IPV6;
479-
std::vector<bool> ip_bits(128);
480-
for (int8_t byte_i = 0; byte_i < 16; ++byte_i) {
481-
uint8_t cur_byte = GetByte(15 - byte_i);
482-
for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
483-
ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1;
484-
}
485-
}
486-
487-
uint32_t asn = Interpret(asmap, ip_bits);
488-
vchRet.push_back(nClass);
489-
for (int i = 0; i < 4; i++) {
490-
vchRet.push_back((asn >> (8 * i)) & 0xFF);
491-
}
492-
return vchRet;
493-
}
494-
495-
vchRet.push_back(nClass);
496-
497512
// push our ip onto vchRet byte by byte...
498513
while (nBits >= 8)
499514
{

src/netaddress.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,14 @@ class CNetAddr
7878
unsigned int GetByte(int n) const;
7979
uint64_t GetHash() const;
8080
bool GetInAddr(struct in_addr* pipv4Addr) const;
81-
std::vector<unsigned char> GetGroup(const std::vector<bool> &asmap) const;
81+
uint32_t GetNetClass() const;
82+
83+
// The AS on the BGP path to the node we use to diversify
84+
// peers in AddrMan bucketing based on the AS infrastructure.
85+
// The ip->AS mapping depends on how asmap is constructed.
86+
uint32_t GetMappedAS(const std::vector<bool> &asmap) const;
8287

88+
std::vector<unsigned char> GetGroup(const std::vector<bool> &asmap) const;
8389
int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const;
8490

8591
explicit CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);

src/rpc/net.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
8383
" \"addr\":\"host:port\", (string) The IP address and port of the peer\n"
8484
" \"addrbind\":\"ip:port\", (string) Bind address of the connection to the peer\n"
8585
" \"addrlocal\":\"ip:port\", (string) Local address as reported by the peer\n"
86+
" \"mapped_as\":\"mapped_as\", (string) The AS in the BGP route to the peer used for diversifying peer selection\n"
8687
" \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
8788
" \"servicesnames\":[ (array) the services offered, in human-readable form\n"
8889
" \"SERVICE_NAME\", (string) the service name if it is recognised\n"
@@ -152,6 +153,9 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
152153
obj.pushKV("addrlocal", stats.addrLocal);
153154
if (stats.addrBind.IsValid())
154155
obj.pushKV("addrbind", stats.addrBind.ToString());
156+
if (stats.m_mapped_as != 0) {
157+
obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as));
158+
}
155159
obj.pushKV("services", strprintf("%016x", stats.nServices));
156160
obj.pushKV("servicesnames", GetServicesNames(stats.nServices));
157161
obj.pushKV("relaytxes", stats.fRelayTxes);

0 commit comments

Comments
 (0)