Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 1,165 Lines • ▼ Show 20 Lines | unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) { | ||||
return nEvicted; | return nEvicted; | ||||
} | } | ||||
/** | /** | ||||
* Increment peer's misbehavior score. If the new value >= | * Increment peer's misbehavior score. If the new value >= | ||||
* DISCOURAGEMENT_THRESHOLD, mark the node to be discouraged, meaning the peer | * DISCOURAGEMENT_THRESHOLD, mark the node to be discouraged, meaning the peer | ||||
* might be disconnected and added to the discouragement filter. | * might be disconnected and added to the discouragement filter. | ||||
*/ | */ | ||||
void Misbehaving(NodeId pnode, int howmuch, const std::string &message) { | void Misbehaving(const NodeId pnode, const int howmuch, | ||||
const std::string &message) { | |||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
if (howmuch == 0) { | |||||
return; | |||||
} | |||||
CNodeState *state = State(pnode); | assert(howmuch > 0); | ||||
CNodeState *const state = State(pnode); | |||||
if (state == nullptr) { | if (state == nullptr) { | ||||
return; | return; | ||||
} | } | ||||
state->nMisbehavior += howmuch; | state->nMisbehavior += howmuch; | ||||
std::string message_prefixed = message.empty() ? "" : (": " + message); | const std::string message_prefixed = | ||||
message.empty() ? "" : (": " + message); | |||||
if (state->nMisbehavior >= DISCOURAGEMENT_THRESHOLD && | if (state->nMisbehavior >= DISCOURAGEMENT_THRESHOLD && | ||||
state->nMisbehavior - howmuch < DISCOURAGEMENT_THRESHOLD) { | state->nMisbehavior - howmuch < DISCOURAGEMENT_THRESHOLD) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"%s: %s peer=%d (%d -> %d) BAN THRESHOLD EXCEEDED%s\n", | "Misbehaving: peer=%d (%d -> %d) BAN THRESHOLD EXCEEDED%s\n", | ||||
__func__, state->name, pnode, state->nMisbehavior - howmuch, | pnode, state->nMisbehavior - howmuch, state->nMisbehavior, | ||||
state->nMisbehavior, message_prefixed); | message_prefixed); | ||||
state->m_should_discourage = true; | state->m_should_discourage = true; | ||||
} else { | } else { | ||||
LogPrint(BCLog::NET, "%s: %s peer=%d (%d -> %d)%s\n", __func__, | LogPrint(BCLog::NET, "Misbehaving: peer=%d (%d -> %d)%s\n", pnode, | ||||
state->name, pnode, state->nMisbehavior - howmuch, | state->nMisbehavior - howmuch, state->nMisbehavior, | ||||
state->nMisbehavior, message_prefixed); | message_prefixed); | ||||
} | } | ||||
} | } | ||||
// overloaded variant of above to operate on CNode*s | // overloaded variant of above to operate on CNode*s | ||||
static void Misbehaving(const CNode &node, int howmuch, | static void Misbehaving(const CNode &node, int howmuch, | ||||
const std::string &message) | const std::string &message) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
Misbehaving(node.GetId(), howmuch, message); | Misbehaving(node.GetId(), howmuch, message); | ||||
▲ Show 20 Lines • Show All 752 Lines • ▼ Show 20 Lines | |||||
inline static void SendBlockTransactions(const CBlock &block, | inline static void SendBlockTransactions(const CBlock &block, | ||||
const BlockTransactionsRequest &req, | const BlockTransactionsRequest &req, | ||||
CNode &pfrom, CConnman &connman) { | CNode &pfrom, CConnman &connman) { | ||||
BlockTransactions resp(req); | BlockTransactions resp(req); | ||||
for (size_t i = 0; i < req.indices.size(); i++) { | for (size_t i = 0; i < req.indices.size(); i++) { | ||||
if (req.indices[i] >= block.vtx.size()) { | if (req.indices[i] >= block.vtx.size()) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, 100, | Misbehaving(pfrom, 100, | ||||
strprintf("Peer sent us a getblocktxn with " | "getblocktxn with out-of-bounds tx indices"); | ||||
"out-of-bounds tx indices")); | |||||
return; | return; | ||||
} | } | ||||
resp.txn[i] = block.vtx[req.indices[i]]; | resp.txn[i] = block.vtx[req.indices[i]]; | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
const CNetMsgMaker msgMaker(pfrom.GetSendVersion()); | const CNetMsgMaker msgMaker(pfrom.GetSendVersion()); | ||||
int nSendFlags = 0; | int nSendFlags = 0; | ||||
connman.PushMessage(&pfrom, | connman.PushMessage(&pfrom, | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | const CBlockIndex *pindexLast = nullptr; | ||||
// Set hashLastUnknownBlock for this peer, so that if we eventually | // Set hashLastUnknownBlock for this peer, so that if we eventually | ||||
// get the headers - even from a different peer - we can use this | // get the headers - even from a different peer - we can use this | ||||
// peer to download. | // peer to download. | ||||
UpdateBlockAvailability(pfrom.GetId(), headers.back().GetHash()); | UpdateBlockAvailability(pfrom.GetId(), headers.back().GetHash()); | ||||
if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == | if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == | ||||
0) { | 0) { | ||||
// The peer is sending us many headers we can't connect. | // The peer is sending us many headers we can't connect. | ||||
Misbehaving(pfrom, 20, "too-many-unconnected-headers"); | Misbehaving(pfrom, 20, | ||||
strprintf("%d non-connecting headers", | |||||
nodestate->nUnconnectingHeaders)); | |||||
} | } | ||||
return; | return; | ||||
} | } | ||||
BlockHash hashLastBlock; | BlockHash hashLastBlock; | ||||
for (const CBlockHeader &header : headers) { | for (const CBlockHeader &header : headers) { | ||||
if (!hashLastBlock.IsNull() && | if (!hashLastBlock.IsNull() && | ||||
header.hashPrevBlock != hashLastBlock) { | header.hashPrevBlock != hashLastBlock) { | ||||
▲ Show 20 Lines • Show All 504 Lines • ▼ Show 20 Lines | if (!(pfrom.GetLocalServices() & NODE_BLOOM) && | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
if (msg_type == NetMsgType::VERSION) { | if (msg_type == NetMsgType::VERSION) { | ||||
// Each connection can only send one version message | // Each connection can only send one version message | ||||
if (pfrom.nVersion != 0) { | if (pfrom.nVersion != 0) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, 1, "multiple-version"); | Misbehaving(pfrom, 1, "redundant version message"); | ||||
return; | return; | ||||
} | } | ||||
int64_t nTime; | int64_t nTime; | ||||
CAddress addrMe; | CAddress addrMe; | ||||
CAddress addrFrom; | CAddress addrFrom; | ||||
uint64_t nNonce = 1; | uint64_t nNonce = 1; | ||||
uint64_t nServiceInt; | uint64_t nServiceInt; | ||||
▲ Show 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::VERSION) { | ||||
pfrom.fDisconnect = true; | pfrom.fDisconnect = true; | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
if (pfrom.nVersion == 0) { | if (pfrom.nVersion == 0) { | ||||
// Must have a version message before anything else | // Must have a version message before anything else | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, 10, "missing-version"); | Misbehaving(pfrom, 10, "non-version message before version handshake"); | ||||
return; | return; | ||||
} | } | ||||
// At this point, the outgoing message serialization version can't change. | // At this point, the outgoing message serialization version can't change. | ||||
const CNetMsgMaker msgMaker(pfrom.GetSendVersion()); | const CNetMsgMaker msgMaker(pfrom.GetSendVersion()); | ||||
if (msg_type == NetMsgType::VERACK) { | if (msg_type == NetMsgType::VERACK) { | ||||
pfrom.SetRecvVersion(std::min(pfrom.nVersion.load(), PROTOCOL_VERSION)); | pfrom.SetRecvVersion(std::min(pfrom.nVersion.load(), PROTOCOL_VERSION)); | ||||
Show All 34 Lines | if (msg_type == NetMsgType::VERACK) { | ||||
} | } | ||||
pfrom.fSuccessfullyConnected = true; | pfrom.fSuccessfullyConnected = true; | ||||
return; | return; | ||||
} | } | ||||
if (!pfrom.fSuccessfullyConnected) { | if (!pfrom.fSuccessfullyConnected) { | ||||
// Must have a verack message before anything else | // Must have a verack message before anything else | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, 10, "missing-verack"); | Misbehaving(pfrom, 10, "non-verack message before version handshake"); | ||||
return; | return; | ||||
} | } | ||||
if (msg_type == NetMsgType::ADDR) { | if (msg_type == NetMsgType::ADDR) { | ||||
std::vector<CAddress> vAddr; | std::vector<CAddress> vAddr; | ||||
vRecv >> vAddr; | vRecv >> vAddr; | ||||
if (!pfrom.IsAddrRelayPeer()) { | if (!pfrom.IsAddrRelayPeer()) { | ||||
▲ Show 20 Lines • Show All 699 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::CMPCTBLOCK) { | ||||
PartiallyDownloadedBlock &partialBlock = | PartiallyDownloadedBlock &partialBlock = | ||||
*(*queuedBlockIt)->partialBlock; | *(*queuedBlockIt)->partialBlock; | ||||
ReadStatus status = | ReadStatus status = | ||||
partialBlock.InitData(cmpctblock, vExtraTxnForCompact); | partialBlock.InitData(cmpctblock, vExtraTxnForCompact); | ||||
if (status == READ_STATUS_INVALID) { | if (status == READ_STATUS_INVALID) { | ||||
// Reset in-flight state in case of whitelist | // Reset in-flight state in case of whitelist | ||||
MarkBlockAsReceived(pindex->GetBlockHash()); | MarkBlockAsReceived(pindex->GetBlockHash()); | ||||
Misbehaving(pfrom, 100, | Misbehaving(pfrom, 100, "invalid compact block"); | ||||
strprintf("invalid-cmpctblk: Peer sent us " | |||||
"invalid compact block")); | |||||
return; | return; | ||||
} else if (status == READ_STATUS_FAILED) { | } else if (status == READ_STATUS_FAILED) { | ||||
// Duplicate txindices, the block is now in-flight, so | // Duplicate txindices, the block is now in-flight, so | ||||
// just request it. | // just request it. | ||||
std::vector<CInv> vInv(1); | std::vector<CInv> vInv(1); | ||||
vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); | vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); | ||||
m_connman.PushMessage( | m_connman.PushMessage( | ||||
&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); | &pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); | ||||
▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::BLOCKTXN) { | ||||
PartiallyDownloadedBlock &partialBlock = | PartiallyDownloadedBlock &partialBlock = | ||||
*it->second.second->partialBlock; | *it->second.second->partialBlock; | ||||
ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn); | ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn); | ||||
if (status == READ_STATUS_INVALID) { | if (status == READ_STATUS_INVALID) { | ||||
// Reset in-flight state in case of whitelist. | // Reset in-flight state in case of whitelist. | ||||
MarkBlockAsReceived(resp.blockhash); | MarkBlockAsReceived(resp.blockhash); | ||||
Misbehaving( | Misbehaving( | ||||
pfrom, 100, | pfrom, 100, | ||||
strprintf("invalid-cmpctblk-txns: Peer sent us invalid " | "invalid compact block/non-matching block transactions"); | ||||
"compact block/non-matching block transactions")); | |||||
return; | return; | ||||
} else if (status == READ_STATUS_FAILED) { | } else if (status == READ_STATUS_FAILED) { | ||||
// Might have collided, fall back to getdata now :( | // Might have collided, fall back to getdata now :( | ||||
std::vector<CInv> invs; | std::vector<CInv> invs; | ||||
invs.push_back(CInv(MSG_BLOCK, resp.blockhash)); | invs.push_back(CInv(MSG_BLOCK, resp.blockhash)); | ||||
m_connman.PushMessage(&pfrom, | m_connman.PushMessage(&pfrom, | ||||
msgMaker.Make(NetMsgType::GETDATA, invs)); | msgMaker.Make(NetMsgType::GETDATA, invs)); | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 456 Lines • ▼ Show 20 Lines | |||||
if (msg_type == NetMsgType::FILTERLOAD) { | if (msg_type == NetMsgType::FILTERLOAD) { | ||||
CBloomFilter filter; | CBloomFilter filter; | ||||
vRecv >> filter; | vRecv >> filter; | ||||
if (!filter.IsWithinSizeConstraints()) { | if (!filter.IsWithinSizeConstraints()) { | ||||
// There is no excuse for sending a too-large filter | // There is no excuse for sending a too-large filter | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(pfrom, 100, "oversized-bloom-filter"); | Misbehaving(pfrom, 100, "too-large bloom filter"); | ||||
} else if (pfrom.m_tx_relay != nullptr) { | } else if (pfrom.m_tx_relay != nullptr) { | ||||
LOCK(pfrom.m_tx_relay->cs_filter); | LOCK(pfrom.m_tx_relay->cs_filter); | ||||
pfrom.m_tx_relay->pfilter.reset(new CBloomFilter(filter)); | pfrom.m_tx_relay->pfilter.reset(new CBloomFilter(filter)); | ||||
pfrom.m_tx_relay->pfilter->UpdateEmptyFull(); | pfrom.m_tx_relay->pfilter->UpdateEmptyFull(); | ||||
pfrom.m_tx_relay->fRelayTxes = true; | pfrom.m_tx_relay->fRelayTxes = true; | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
Show All 15 Lines | if (msg_type == NetMsgType::FILTERADD) { | ||||
} else { | } else { | ||||
bad = true; | bad = true; | ||||
} | } | ||||
} | } | ||||
if (bad) { | if (bad) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// The structure of this code doesn't really allow for a good error | // The structure of this code doesn't really allow for a good error | ||||
// code. We'll go generic. | // code. We'll go generic. | ||||
Misbehaving(pfrom, 100, "invalid-filteradd"); | Misbehaving(pfrom, 100, "bad filteradd message"); | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
if (msg_type == NetMsgType::FILTERCLEAR) { | if (msg_type == NetMsgType::FILTERCLEAR) { | ||||
if (pfrom.m_tx_relay == nullptr) { | if (pfrom.m_tx_relay == nullptr) { | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Maybe disconnect a peer and discourage future connections from its address. | * Maybe disconnect a peer and discourage future connections from its address. | ||||
* | * | ||||
* @param[in] pnode The node to check. | * @param[in] pnode The node to check. | ||||
* @return True if the peer was marked for disconnection in this | * @return True if the peer was marked for disconnection in this | ||||
* function | * function | ||||
*/ | */ | ||||
bool PeerLogicValidation::MaybeDiscourageAndDisconnect(CNode &pnode) { | bool PeerLogicValidation::MaybeDiscourageAndDisconnect(CNode &pnode) { | ||||
NodeId peer_id{pnode.GetId()}; | const NodeId peer_id{pnode.GetId()}; | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CNodeState &state = *State(peer_id); | CNodeState &state = *State(peer_id); | ||||
// There's nothing to do if the m_should_discourage flag isn't set | // There's nothing to do if the m_should_discourage flag isn't set | ||||
if (!state.m_should_discourage) { | if (!state.m_should_discourage) { | ||||
return false; | return false; | ||||
} | } | ||||
// Reset m_should_discourage | |||||
state.m_should_discourage = false; | state.m_should_discourage = false; | ||||
} // cs_main | } // cs_main | ||||
if (pnode.HasPermission(PF_NOBAN)) { | if (pnode.HasPermission(PF_NOBAN)) { | ||||
// Peer has the NOBAN permission flag - log but don't disconnect | // We never disconnect or discourage peers for bad behavior if they have | ||||
// the NOBAN permission flag | |||||
LogPrintf("Warning: not punishing noban peer %d!\n", peer_id); | LogPrintf("Warning: not punishing noban peer %d!\n", peer_id); | ||||
return false; | return false; | ||||
} | } | ||||
if (pnode.IsManualConn()) { | if (pnode.IsManualConn()) { | ||||
// Peer is a manual connection - log but don't disconnect | // We never disconnect or discourage manual peers for bad behavior | ||||
LogPrintf("Warning: not punishing manually connected peer %d!\n", | LogPrintf("Warning: not punishing manually connected peer %d!\n", | ||||
peer_id); | peer_id); | ||||
return false; | return false; | ||||
} | } | ||||
if (pnode.addr.IsLocal()) { | if (pnode.addr.IsLocal()) { | ||||
// Peer is on a local address. Disconnect this peer, but don't | // We disconnect local peers for bad behavior but don't discourage | ||||
// discourage the local address | // (since that would discourage all peers on the same local address) | ||||
LogPrintf( | LogPrintf( | ||||
"Warning: disconnecting but not discouraging local peer %d!\n", | "Warning: disconnecting but not discouraging local peer %d!\n", | ||||
peer_id); | peer_id); | ||||
pnode.fDisconnect = true; | pnode.fDisconnect = true; | ||||
return true; | return true; | ||||
} | } | ||||
// Normal case: Disconnect the peer and discourage all nodes sharing the | // Normal case: Disconnect the peer and discourage all nodes sharing the | ||||
▲ Show 20 Lines • Show All 1,085 Lines • Show Last 20 Lines |