mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 10:38:42 +01:00
Merge #10478: rpc: Add listen address to incoming connections in getpeerinfo
3457331
test: Add test for `getpeerinfo` `bindaddr` field (Wladimir J. van der Laan)a7e3c28
rpc: Add listen address to incoming connections in `getpeerinfo` (Wladimir J. van der Laan) Tree-SHA512: bcd58bca2d35fc9698e958e22a7cf8268a6c731a3a309df183f43fc5e725a88ae09f006290fde7aa03cee9a403e2e25772097409677cedbce8f267e01e9040f6
This commit is contained in:
commit
296928eb38
32
src/net.cpp
32
src/net.cpp
@ -340,6 +340,22 @@ bool CConnman::CheckIncomingNonce(uint64_t nonce)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get the bind address for a socket as CAddress */
|
||||||
|
static CAddress GetBindAddress(SOCKET sock)
|
||||||
|
{
|
||||||
|
CAddress addr_bind;
|
||||||
|
struct sockaddr_storage sockaddr_bind;
|
||||||
|
socklen_t sockaddr_bind_len = sizeof(sockaddr_bind);
|
||||||
|
if (sock != INVALID_SOCKET) {
|
||||||
|
if (!getsockname(sock, (struct sockaddr*)&sockaddr_bind, &sockaddr_bind_len)) {
|
||||||
|
addr_bind.SetSockAddr((const struct sockaddr*)&sockaddr_bind);
|
||||||
|
} else {
|
||||||
|
LogPrint(BCLog::NET, "Warning: getsockname failed\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addr_bind;
|
||||||
|
}
|
||||||
|
|
||||||
CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure)
|
CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure)
|
||||||
{
|
{
|
||||||
if (pszDest == NULL) {
|
if (pszDest == NULL) {
|
||||||
@ -393,7 +409,8 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
|||||||
// Add node
|
// Add node
|
||||||
NodeId id = GetNewNodeId();
|
NodeId id = GetNewNodeId();
|
||||||
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
|
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
|
||||||
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false);
|
CAddress addr_bind = GetBindAddress(hSocket);
|
||||||
|
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false);
|
||||||
pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);
|
pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);
|
||||||
pnode->AddRef();
|
pnode->AddRef();
|
||||||
|
|
||||||
@ -635,6 +652,7 @@ void CNode::copyStats(CNodeStats &stats)
|
|||||||
stats.nodeid = this->GetId();
|
stats.nodeid = this->GetId();
|
||||||
X(nServices);
|
X(nServices);
|
||||||
X(addr);
|
X(addr);
|
||||||
|
X(addrBind);
|
||||||
{
|
{
|
||||||
LOCK(cs_filter);
|
LOCK(cs_filter);
|
||||||
X(fRelayTxes);
|
X(fRelayTxes);
|
||||||
@ -1036,9 +1054,11 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
|
|||||||
int nInbound = 0;
|
int nInbound = 0;
|
||||||
int nMaxInbound = nMaxConnections - (nMaxOutbound + nMaxFeeler);
|
int nMaxInbound = nMaxConnections - (nMaxOutbound + nMaxFeeler);
|
||||||
|
|
||||||
if (hSocket != INVALID_SOCKET)
|
if (hSocket != INVALID_SOCKET) {
|
||||||
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
|
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) {
|
||||||
LogPrintf("Warning: Unknown socket family\n");
|
LogPrintf("Warning: Unknown socket family\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr);
|
bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr);
|
||||||
{
|
{
|
||||||
@ -1092,8 +1112,9 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
|
|||||||
|
|
||||||
NodeId id = GetNewNodeId();
|
NodeId id = GetNewNodeId();
|
||||||
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
|
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
|
||||||
|
CAddress addr_bind = GetBindAddress(hSocket);
|
||||||
|
|
||||||
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, "", true);
|
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true);
|
||||||
pnode->AddRef();
|
pnode->AddRef();
|
||||||
pnode->fWhitelisted = whitelisted;
|
pnode->fWhitelisted = whitelisted;
|
||||||
GetNodeSignals().InitializeNode(pnode, *this);
|
GetNodeSignals().InitializeNode(pnode, *this);
|
||||||
@ -2639,9 +2660,10 @@ int CConnman::GetBestHeight() const
|
|||||||
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
|
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
|
||||||
unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; }
|
unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; }
|
||||||
|
|
||||||
CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string& addrNameIn, bool fInboundIn) :
|
CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string& addrNameIn, bool fInboundIn) :
|
||||||
nTimeConnected(GetSystemTimeInSeconds()),
|
nTimeConnected(GetSystemTimeInSeconds()),
|
||||||
addr(addrIn),
|
addr(addrIn),
|
||||||
|
addrBind(addrBindIn),
|
||||||
fInbound(fInboundIn),
|
fInbound(fInboundIn),
|
||||||
nKeyedNetGroup(nKeyedNetGroupIn),
|
nKeyedNetGroup(nKeyedNetGroupIn),
|
||||||
addrKnown(5000, 0.001),
|
addrKnown(5000, 0.001),
|
||||||
|
10
src/net.h
10
src/net.h
@ -504,8 +504,12 @@ public:
|
|||||||
double dPingTime;
|
double dPingTime;
|
||||||
double dPingWait;
|
double dPingWait;
|
||||||
double dMinPing;
|
double dMinPing;
|
||||||
|
// Our address, as reported by the peer
|
||||||
std::string addrLocal;
|
std::string addrLocal;
|
||||||
|
// Address of this peer
|
||||||
CAddress addr;
|
CAddress addr;
|
||||||
|
// Bind address of our side of the connection
|
||||||
|
CAddress addrBind;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -586,7 +590,10 @@ public:
|
|||||||
std::atomic<int64_t> nLastRecv;
|
std::atomic<int64_t> nLastRecv;
|
||||||
const int64_t nTimeConnected;
|
const int64_t nTimeConnected;
|
||||||
std::atomic<int64_t> nTimeOffset;
|
std::atomic<int64_t> nTimeOffset;
|
||||||
|
// Address of this peer
|
||||||
const CAddress addr;
|
const CAddress addr;
|
||||||
|
// Bind address of our side of the connection
|
||||||
|
const CAddress addrBind;
|
||||||
std::atomic<int> nVersion;
|
std::atomic<int> nVersion;
|
||||||
// strSubVer is whatever byte array we read from the wire. However, this field is intended
|
// strSubVer is whatever byte array we read from the wire. However, this field is intended
|
||||||
// to be printed out, displayed to humans in various forms and so on. So we sanitize it and
|
// to be printed out, displayed to humans in various forms and so on. So we sanitize it and
|
||||||
@ -676,7 +683,7 @@ public:
|
|||||||
CAmount lastSentFeeFilter;
|
CAmount lastSentFeeFilter;
|
||||||
int64_t nextSendTimeFeeFilter;
|
int64_t nextSendTimeFeeFilter;
|
||||||
|
|
||||||
CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string &addrNameIn = "", bool fInboundIn = false);
|
CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn = "", bool fInboundIn = false);
|
||||||
~CNode();
|
~CNode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -695,6 +702,7 @@ private:
|
|||||||
mutable CCriticalSection cs_addrName;
|
mutable CCriticalSection cs_addrName;
|
||||||
std::string addrName;
|
std::string addrName;
|
||||||
|
|
||||||
|
// Our address, as reported by the peer
|
||||||
CService addrLocal;
|
CService addrLocal;
|
||||||
mutable CCriticalSection cs_addrLocal;
|
mutable CCriticalSection cs_addrLocal;
|
||||||
public:
|
public:
|
||||||
|
@ -76,7 +76,8 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
|
|||||||
" {\n"
|
" {\n"
|
||||||
" \"id\": n, (numeric) Peer index\n"
|
" \"id\": n, (numeric) Peer index\n"
|
||||||
" \"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"
|
||||||
" \"addrlocal\":\"ip:port\", (string) local address\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"
|
||||||
" \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
|
" \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
|
||||||
" \"relaytxes\":true|false, (boolean) Whether peer has asked us to relay transactions to it\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"
|
" \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n"
|
||||||
@ -133,6 +134,8 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
|
|||||||
obj.push_back(Pair("addr", stats.addrName));
|
obj.push_back(Pair("addr", stats.addrName));
|
||||||
if (!(stats.addrLocal.empty()))
|
if (!(stats.addrLocal.empty()))
|
||||||
obj.push_back(Pair("addrlocal", stats.addrLocal));
|
obj.push_back(Pair("addrlocal", stats.addrLocal));
|
||||||
|
if (stats.addrBind.IsValid())
|
||||||
|
obj.push_back(Pair("addrbind", stats.addrBind.ToString()));
|
||||||
obj.push_back(Pair("services", strprintf("%016x", stats.nServices)));
|
obj.push_back(Pair("services", strprintf("%016x", stats.nServices)));
|
||||||
obj.push_back(Pair("relaytxes", stats.fRelayTxes));
|
obj.push_back(Pair("relaytxes", stats.fRelayTxes));
|
||||||
obj.push_back(Pair("lastsend", stats.nLastSend));
|
obj.push_back(Pair("lastsend", stats.nLastSend));
|
||||||
|
@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
|
|||||||
|
|
||||||
connman->ClearBanned();
|
connman->ClearBanned();
|
||||||
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
|
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
|
||||||
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, "", true);
|
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", true);
|
||||||
dummyNode1.SetSendVersion(PROTOCOL_VERSION);
|
dummyNode1.SetSendVersion(PROTOCOL_VERSION);
|
||||||
GetNodeSignals().InitializeNode(&dummyNode1, *connman);
|
GetNodeSignals().InitializeNode(&dummyNode1, *connman);
|
||||||
dummyNode1.nVersion = 1;
|
dummyNode1.nVersion = 1;
|
||||||
@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
|
|||||||
BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
|
BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
|
||||||
|
|
||||||
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
|
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
|
||||||
CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, "", true);
|
CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", true);
|
||||||
dummyNode2.SetSendVersion(PROTOCOL_VERSION);
|
dummyNode2.SetSendVersion(PROTOCOL_VERSION);
|
||||||
GetNodeSignals().InitializeNode(&dummyNode2, *connman);
|
GetNodeSignals().InitializeNode(&dummyNode2, *connman);
|
||||||
dummyNode2.nVersion = 1;
|
dummyNode2.nVersion = 1;
|
||||||
@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
|
|||||||
connman->ClearBanned();
|
connman->ClearBanned();
|
||||||
ForceSetArg("-banscore", "111"); // because 11 is my favorite number
|
ForceSetArg("-banscore", "111"); // because 11 is my favorite number
|
||||||
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
|
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
|
||||||
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, "", true);
|
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, CAddress(), "", true);
|
||||||
dummyNode1.SetSendVersion(PROTOCOL_VERSION);
|
dummyNode1.SetSendVersion(PROTOCOL_VERSION);
|
||||||
GetNodeSignals().InitializeNode(&dummyNode1, *connman);
|
GetNodeSignals().InitializeNode(&dummyNode1, *connman);
|
||||||
dummyNode1.nVersion = 1;
|
dummyNode1.nVersion = 1;
|
||||||
@ -109,7 +109,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
|||||||
SetMockTime(nStartTime); // Overrides future calls to GetTime()
|
SetMockTime(nStartTime); // Overrides future calls to GetTime()
|
||||||
|
|
||||||
CAddress addr(ip(0xa0b0c001), NODE_NONE);
|
CAddress addr(ip(0xa0b0c001), NODE_NONE);
|
||||||
CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, "", true);
|
CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", true);
|
||||||
dummyNode.SetSendVersion(PROTOCOL_VERSION);
|
dummyNode.SetSendVersion(PROTOCOL_VERSION);
|
||||||
GetNodeSignals().InitializeNode(&dummyNode, *connman);
|
GetNodeSignals().InitializeNode(&dummyNode, *connman);
|
||||||
dummyNode.nVersion = 1;
|
dummyNode.nVersion = 1;
|
||||||
|
@ -175,12 +175,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
|||||||
bool fInboundIn = false;
|
bool fInboundIn = false;
|
||||||
|
|
||||||
// Test that fFeeler is false by default.
|
// Test that fFeeler is false by default.
|
||||||
std::unique_ptr<CNode> pnode1(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, pszDest, fInboundIn));
|
std::unique_ptr<CNode> pnode1(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, fInboundIn));
|
||||||
BOOST_CHECK(pnode1->fInbound == false);
|
BOOST_CHECK(pnode1->fInbound == false);
|
||||||
BOOST_CHECK(pnode1->fFeeler == false);
|
BOOST_CHECK(pnode1->fFeeler == false);
|
||||||
|
|
||||||
fInboundIn = true;
|
fInboundIn = true;
|
||||||
std::unique_ptr<CNode> pnode2(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, pszDest, fInboundIn));
|
std::unique_ptr<CNode> pnode2(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, fInboundIn));
|
||||||
BOOST_CHECK(pnode2->fInbound == true);
|
BOOST_CHECK(pnode2->fInbound == true);
|
||||||
BOOST_CHECK(pnode2->fFeeler == false);
|
BOOST_CHECK(pnode2->fFeeler == false);
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ class NetTest(BitcoinTestFramework):
|
|||||||
self._test_getnettotals()
|
self._test_getnettotals()
|
||||||
self._test_getnetworkinginfo()
|
self._test_getnetworkinginfo()
|
||||||
self._test_getaddednodeinfo()
|
self._test_getaddednodeinfo()
|
||||||
|
self._test_getpeerinfo()
|
||||||
|
|
||||||
def _test_connection_count(self):
|
def _test_connection_count(self):
|
||||||
# connect_nodes_bi connects each node to the other
|
# connect_nodes_bi connects each node to the other
|
||||||
@ -88,6 +89,12 @@ class NetTest(BitcoinTestFramework):
|
|||||||
assert_raises_jsonrpc(-24, "Node has not been added",
|
assert_raises_jsonrpc(-24, "Node has not been added",
|
||||||
self.nodes[0].getaddednodeinfo, '1.1.1.1')
|
self.nodes[0].getaddednodeinfo, '1.1.1.1')
|
||||||
|
|
||||||
|
def _test_getpeerinfo(self):
|
||||||
|
peer_info = [x.getpeerinfo() for x in self.nodes]
|
||||||
|
# check both sides of bidirectional connection between nodes
|
||||||
|
# the address bound to on one side will be the source address for the other node
|
||||||
|
assert_equal(peer_info[0][0]['addrbind'], peer_info[1][0]['addr'])
|
||||||
|
assert_equal(peer_info[1][0]['addrbind'], peer_info[0][0]['addr'])
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
NetTest().main()
|
NetTest().main()
|
||||||
|
Loading…
Reference in New Issue
Block a user