Skip to content

Commit

Permalink
Return mapped AS in RPC call getpeerinfo
Browse files Browse the repository at this point in the history
If ASN bucketing is used, return a corresponding AS
used in bucketing for a given peer.

Cherry-picked from: e4658aa
  • Loading branch information
naumenkogs authored and xanimo committed Jun 28, 2023
1 parent 5630e66 commit 881cf0e
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 37 deletions.
12 changes: 8 additions & 4 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,14 +624,18 @@ void CNode::SetAddrLocal(const CService& addrLocalIn) {

#undef X
#define X(name) stats.name = name
void CNode::copyStats(CNodeStats &stats)
void CNode::copyStats(CNodeStats &stats, std::vector<bool> &m_asmap)
{
stats.nodeid = this->GetId();
X(nServices);
X(addr);
{
// TODO addrBind
stats.m_mapped_as = addr.GetMappedAS(m_asmap);
if (fRelayTxes != NULL) {
LOCK(cs_filter);
X(fRelayTxes);
stats.fRelayTxes = fRelayTxes;
} else {
stats.fRelayTxes = false;
}
X(nLastSend);
X(nLastRecv);
Expand Down Expand Up @@ -2543,7 +2547,7 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats)
for(std::vector<CNode*>::iterator it = vNodes.begin(); it != vNodes.end(); ++it) {
CNode* pnode = *it;
vstats.emplace_back();
pnode->copyStats(vstats.back());
pnode->copyStats(vstats.back(), addrman.m_asmap);
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,9 @@ class CNodeStats
CAmount minFeeFilter;
uint64_t nProcessedAddrs;
uint64_t nRatelimitedAddrs;
// Bind address of our side of the connection
CAddress addrBind;
uint32_t m_mapped_as;
};


Expand Down Expand Up @@ -832,7 +835,7 @@ class CNode

void CloseSocketDisconnect();

void copyStats(CNodeStats &stats);
void copyStats(CNodeStats &stats, std::vector<bool> &m_asmap);

ServiceFlags GetLocalServices() const
{
Expand Down
77 changes: 47 additions & 30 deletions src/netaddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,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_TOR;
}
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
*
Expand All @@ -338,53 +371,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_TOR;
nStartByte = 6;
nBits = 4;
}
Expand All @@ -395,28 +433,7 @@ 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)
{
vchRet.push_back(GetByte(15 - nStartByte));
Expand Down
7 changes: 7 additions & 0 deletions src/netaddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ class CNetAddr
unsigned int GetByte(int n) const;
uint64_t GetHash() const;
bool GetInAddr(struct in_addr* pipv4Addr) const;
uint32_t GetNetClass() 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.
uint32_t GetMappedAS(const std::vector<bool> &asmap) const;

std::vector<unsigned char> GetGroup(const std::vector<bool> &asmap) const;

int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const;
Expand Down
11 changes: 9 additions & 2 deletions src/rpc/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,10 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
"[\n"
" {\n"
" \"id\": n, (numeric) Peer index\n"
" \"addr\":\"host:port\", (string) The ip address and port of the peer\n"
" \"addrlocal\":\"ip:port\", (string) local address\n"
" \"addr\":\"host:port\", (string) The IP address and port of the peer\n"
" \"addrbind\":\"ip:port\", (string) Bind address of the connection to the peer\n"
" \"addrlocal\":\"ip:port\", (string) Local address as reported by the peer\n"
" \"mapped_as\":\"mapped_as\", (string) The AS in the BGP route to the peer used for diversifying peer selection\n"
" \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
" \"relaytxes\":true|false, (boolean) Whether peer has asked us to relay transactions to it\n"
" \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n"
Expand Down Expand Up @@ -171,6 +173,11 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
obj.pushKV("addr", stats.addrName);
if (!(stats.addrLocal.empty()))
obj.pushKV("addrlocal", stats.addrLocal);
if (stats.addrBind.IsValid())
obj.pushKV("addrbind", stats.addrBind.ToString());
if (stats.m_mapped_as != 0) {
obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as));
}
obj.pushKV("services", strprintf("%016x", stats.nServices));
obj.pushKV("relaytxes", stats.fRelayTxes);
obj.pushKV("lastsend", stats.nLastSend);
Expand Down

0 comments on commit 881cf0e

Please sign in to comment.