mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-07-02 11:41:18 +02:00
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:
@ -493,12 +493,13 @@ void CNode::SetAddrLocal(const CService& addrLocalIn) {
|
|||||||
|
|
||||||
#undef X
|
#undef X
|
||||||
#define X(name) stats.name = name
|
#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();
|
stats.nodeid = this->GetId();
|
||||||
X(nServices);
|
X(nServices);
|
||||||
X(addr);
|
X(addr);
|
||||||
X(addrBind);
|
X(addrBind);
|
||||||
|
stats.m_mapped_as = addr.GetMappedAS(m_asmap);
|
||||||
if (m_tx_relay != nullptr) {
|
if (m_tx_relay != nullptr) {
|
||||||
LOCK(m_tx_relay->cs_filter);
|
LOCK(m_tx_relay->cs_filter);
|
||||||
stats.fRelayTxes = m_tx_relay->fRelayTxes;
|
stats.fRelayTxes = m_tx_relay->fRelayTxes;
|
||||||
@ -2491,7 +2492,7 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats)
|
|||||||
vstats.reserve(vNodes.size());
|
vstats.reserve(vNodes.size());
|
||||||
for (CNode* pnode : vNodes) {
|
for (CNode* pnode : vNodes) {
|
||||||
vstats.emplace_back();
|
vstats.emplace_back();
|
||||||
pnode->copyStats(vstats.back());
|
pnode->copyStats(vstats.back(), addrman.m_asmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,6 +606,7 @@ public:
|
|||||||
CAddress addr;
|
CAddress addr;
|
||||||
// Bind address of our side of the connection
|
// Bind address of our side of the connection
|
||||||
CAddress addrBind;
|
CAddress addrBind;
|
||||||
|
uint32_t m_mapped_as;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -982,7 +983,7 @@ public:
|
|||||||
|
|
||||||
void CloseSocketDisconnect();
|
void CloseSocketDisconnect();
|
||||||
|
|
||||||
void copyStats(CNodeStats &stats);
|
void copyStats(CNodeStats &stats, std::vector<bool> &m_asmap);
|
||||||
|
|
||||||
ServiceFlags GetLocalServices() const
|
ServiceFlags GetLocalServices() const
|
||||||
{
|
{
|
||||||
|
@ -401,6 +401,39 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
|
|||||||
return true;
|
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
|
* 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> CNetAddr::GetGroup(const std::vector<bool> &asmap) const
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> vchRet;
|
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 nStartByte = 0;
|
||||||
int nBits = 16;
|
int nBits = 16;
|
||||||
|
|
||||||
// all local addresses belong to the same group
|
// all local addresses belong to the same group
|
||||||
if (IsLocal())
|
if (IsLocal())
|
||||||
{
|
{
|
||||||
nClass = 255;
|
|
||||||
nBits = 0;
|
nBits = 0;
|
||||||
}
|
}
|
||||||
// all internal-usage addresses get their own group
|
// all internal-usage addresses get their own group
|
||||||
if (IsInternal())
|
if (IsInternal())
|
||||||
{
|
{
|
||||||
nClass = NET_INTERNAL;
|
|
||||||
nStartByte = sizeof(g_internal_prefix);
|
nStartByte = sizeof(g_internal_prefix);
|
||||||
nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8;
|
nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8;
|
||||||
}
|
}
|
||||||
// all other unroutable addresses belong to the same group
|
// all other unroutable addresses belong to the same group
|
||||||
else if (!IsRoutable())
|
else if (!IsRoutable())
|
||||||
{
|
{
|
||||||
nClass = NET_UNROUTABLE;
|
|
||||||
nBits = 0;
|
nBits = 0;
|
||||||
}
|
}
|
||||||
// for IPv4 addresses, '1' + the 16 higher-order bits of the IP
|
// for IPv4 addresses, '1' + the 16 higher-order bits of the IP
|
||||||
// includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
|
// includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
|
||||||
else if (IsIPv4() || IsRFC6145() || IsRFC6052())
|
else if (IsIPv4() || IsRFC6145() || IsRFC6052())
|
||||||
{
|
{
|
||||||
nClass = NET_IPV4;
|
|
||||||
nStartByte = 12;
|
nStartByte = 12;
|
||||||
}
|
}
|
||||||
// for 6to4 tunnelled addresses, use the encapsulated IPv4 address
|
// for 6to4 tunnelled addresses, use the encapsulated IPv4 address
|
||||||
else if (IsRFC3964())
|
else if (IsRFC3964())
|
||||||
{
|
{
|
||||||
nClass = NET_IPV4;
|
|
||||||
nStartByte = 2;
|
nStartByte = 2;
|
||||||
}
|
}
|
||||||
// for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address
|
// for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address
|
||||||
else if (IsRFC4380())
|
else if (IsRFC4380())
|
||||||
{
|
{
|
||||||
vchRet.push_back(NET_IPV4);
|
|
||||||
vchRet.push_back(GetByte(3) ^ 0xFF);
|
vchRet.push_back(GetByte(3) ^ 0xFF);
|
||||||
vchRet.push_back(GetByte(2) ^ 0xFF);
|
vchRet.push_back(GetByte(2) ^ 0xFF);
|
||||||
return vchRet;
|
return vchRet;
|
||||||
}
|
}
|
||||||
else if (IsTor())
|
else if (IsTor())
|
||||||
{
|
{
|
||||||
nClass = NET_ONION;
|
|
||||||
nStartByte = 6;
|
nStartByte = 6;
|
||||||
nBits = 4;
|
nBits = 4;
|
||||||
}
|
}
|
||||||
@ -471,29 +509,6 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
|
|||||||
else
|
else
|
||||||
nBits = 32;
|
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...
|
// push our ip onto vchRet byte by byte...
|
||||||
while (nBits >= 8)
|
while (nBits >= 8)
|
||||||
{
|
{
|
||||||
|
@ -78,8 +78,14 @@ class CNetAddr
|
|||||||
unsigned int GetByte(int n) const;
|
unsigned int GetByte(int n) const;
|
||||||
uint64_t GetHash() const;
|
uint64_t GetHash() const;
|
||||||
bool GetInAddr(struct in_addr* pipv4Addr) const;
|
bool GetInAddr(struct in_addr* pipv4Addr) const;
|
||||||
std::vector<unsigned char> GetGroup(const std::vector<bool> &asmap) 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;
|
int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const;
|
||||||
|
|
||||||
explicit CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);
|
explicit CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);
|
||||||
|
@ -83,6 +83,7 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
|
|||||||
" \"addr\":\"host:port\", (string) The IP address and port of the peer\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"
|
" \"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"
|
" \"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"
|
" \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
|
||||||
" \"servicesnames\":[ (array) the services offered, in human-readable form\n"
|
" \"servicesnames\":[ (array) the services offered, in human-readable form\n"
|
||||||
" \"SERVICE_NAME\", (string) the service name if it is recognised\n"
|
" \"SERVICE_NAME\", (string) the service name if it is recognised\n"
|
||||||
@ -152,6 +153,9 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
|
|||||||
obj.pushKV("addrlocal", stats.addrLocal);
|
obj.pushKV("addrlocal", stats.addrLocal);
|
||||||
if (stats.addrBind.IsValid())
|
if (stats.addrBind.IsValid())
|
||||||
obj.pushKV("addrbind", stats.addrBind.ToString());
|
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("services", strprintf("%016x", stats.nServices));
|
||||||
obj.pushKV("servicesnames", GetServicesNames(stats.nServices));
|
obj.pushKV("servicesnames", GetServicesNames(stats.nServices));
|
||||||
obj.pushKV("relaytxes", stats.fRelayTxes);
|
obj.pushKV("relaytxes", stats.fRelayTxes);
|
||||||
|
Reference in New Issue
Block a user