mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-13 17:15:11 +01:00
Add 2 outbound block-relay-only connections
Transaction relay is primarily optimized for balancing redundancy/robustness with bandwidth minimization -- as a result transaction relay leaks information that adversaries can use to infer the network topology. Network topology is better kept private for (at least) two reasons: (a) Knowledge of the network graph can make it easier to find the source IP of a given transaction. (b) Knowledge of the network graph could be used to split a target node or nodes from the honest network (eg by knowing which peers to attack in order to achieve a network split). We can eliminate the risks of (b) by separating block relay from transaction relay; inferring network connectivity from the relay of blocks/block headers is much more expensive for an adversary. After this commit, bitcoind will make 2 additional outbound connections that are only used for block relay. (In the future, we might consider rotating our transaction-relay peers to help limit the effects of (a).)
This commit is contained in:
42
src/net.cpp
42
src/net.cpp
@@ -352,7 +352,7 @@ static CAddress GetBindAddress(SOCKET sock)
|
||||
return addr_bind;
|
||||
}
|
||||
|
||||
CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, bool manual_connection)
|
||||
CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, bool manual_connection, bool block_relay_only)
|
||||
{
|
||||
if (pszDest == nullptr) {
|
||||
if (IsLocal(addrConnect))
|
||||
@@ -442,7 +442,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
||||
NodeId id = GetNewNodeId();
|
||||
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
|
||||
CAddress addr_bind = GetBindAddress(hSocket);
|
||||
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false);
|
||||
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false, block_relay_only);
|
||||
pnode->AddRef();
|
||||
|
||||
return pnode;
|
||||
@@ -905,7 +905,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
|
||||
SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
|
||||
CAddress addr;
|
||||
int nInbound = 0;
|
||||
int nMaxInbound = nMaxConnections - (nMaxOutbound + nMaxFeeler);
|
||||
int nMaxInbound = nMaxConnections - m_max_outbound;
|
||||
|
||||
if (hSocket != INVALID_SOCKET) {
|
||||
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) {
|
||||
@@ -1666,7 +1666,7 @@ int CConnman::GetExtraOutboundCount()
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::max(nOutbound - nMaxOutbound, 0);
|
||||
return std::max(nOutbound - m_max_outbound_full_relay - m_max_outbound_block_relay, 0);
|
||||
}
|
||||
|
||||
void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
||||
@@ -1726,7 +1726,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
||||
CAddress addrConnect;
|
||||
|
||||
// Only connect out to one peer per network group (/16 for IPv4).
|
||||
int nOutbound = 0;
|
||||
int nOutboundFullRelay = 0;
|
||||
int nOutboundBlockRelay = 0;
|
||||
std::set<std::vector<unsigned char> > setConnected;
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
@@ -1738,7 +1739,11 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
||||
// also have the added issue that they're attacker controlled and could be used
|
||||
// to prevent us from connecting to particular hosts if we used them here.
|
||||
setConnected.insert(pnode->addr.GetGroup());
|
||||
nOutbound++;
|
||||
if (pnode->m_tx_relay == nullptr) {
|
||||
nOutboundBlockRelay++;
|
||||
} else if (!pnode->fFeeler) {
|
||||
nOutboundFullRelay++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1757,7 +1762,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
||||
//
|
||||
bool fFeeler = false;
|
||||
|
||||
if (nOutbound >= nMaxOutbound && !GetTryNewOutboundPeer()) {
|
||||
if (nOutboundFullRelay >= m_max_outbound_full_relay && nOutboundBlockRelay >= m_max_outbound_block_relay && !GetTryNewOutboundPeer()) {
|
||||
int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds).
|
||||
if (nTime > nNextFeeler) {
|
||||
nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);
|
||||
@@ -1831,7 +1836,14 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
||||
LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString());
|
||||
}
|
||||
|
||||
OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, nullptr, false, fFeeler);
|
||||
// Open this connection as block-relay-only if we're already at our
|
||||
// full-relay capacity, but not yet at our block-relay peer limit.
|
||||
// (It should not be possible for fFeeler to be set if we're not
|
||||
// also at our block-relay peer limit, but check against that as
|
||||
// well for sanity.)
|
||||
bool block_relay_only = nOutboundBlockRelay < m_max_outbound_block_relay && !fFeeler && nOutboundFullRelay >= m_max_outbound_full_relay;
|
||||
|
||||
OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, nullptr, false, fFeeler, false, block_relay_only);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1918,7 +1930,7 @@ void CConnman::ThreadOpenAddedConnections()
|
||||
}
|
||||
|
||||
// if successful, this moves the passed grant to the constructed node
|
||||
void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool manual_connection)
|
||||
void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool manual_connection, bool block_relay_only)
|
||||
{
|
||||
//
|
||||
// Initiate outbound network connection
|
||||
@@ -1937,7 +1949,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
|
||||
} else if (FindNode(std::string(pszDest)))
|
||||
return;
|
||||
|
||||
CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, manual_connection);
|
||||
CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, manual_connection, block_relay_only);
|
||||
|
||||
if (!pnode)
|
||||
return;
|
||||
@@ -2240,7 +2252,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
||||
|
||||
if (semOutbound == nullptr) {
|
||||
// initialize semaphore
|
||||
semOutbound = MakeUnique<CSemaphore>(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));
|
||||
semOutbound = MakeUnique<CSemaphore>(std::min(m_max_outbound, nMaxConnections));
|
||||
}
|
||||
if (semAddnode == nullptr) {
|
||||
// initialize semaphore
|
||||
@@ -2318,7 +2330,7 @@ void CConnman::Interrupt()
|
||||
InterruptSocks5(true);
|
||||
|
||||
if (semOutbound) {
|
||||
for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) {
|
||||
for (int i=0; i<m_max_outbound; i++) {
|
||||
semOutbound->post();
|
||||
}
|
||||
}
|
||||
@@ -2628,7 +2640,7 @@ int CConnman::GetBestHeight() const
|
||||
|
||||
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
|
||||
|
||||
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)
|
||||
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, bool block_relay_only)
|
||||
: nTimeConnected(GetSystemTimeInSeconds()),
|
||||
addr(addrIn),
|
||||
addrBind(addrBindIn),
|
||||
@@ -2643,7 +2655,9 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
|
||||
hSocket = hSocketIn;
|
||||
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
|
||||
hashContinue = uint256();
|
||||
m_tx_relay = MakeUnique<TxRelay>();
|
||||
if (!block_relay_only) {
|
||||
m_tx_relay = MakeUnique<TxRelay>();
|
||||
}
|
||||
|
||||
for (const std::string &msg : getAllNetMessageTypes())
|
||||
mapRecvBytesPerMsgCmd[msg] = 0;
|
||||
|
||||
Reference in New Issue
Block a user