mirror of
https://github.com/SChernykh/p2pool.git
synced 2024-12-23 03:49:23 +00:00
Rate limit peer list requests
Send an empty response if the request comes too soon
This commit is contained in:
parent
375bf56e2e
commit
e5bf27030d
2 changed files with 31 additions and 39 deletions
|
@ -38,6 +38,7 @@ static const char* seed_nodes_mini[] = { "seeds-mini.p2pool.io", "" };
|
||||||
|
|
||||||
static constexpr int DEFAULT_BACKLOG = 16;
|
static constexpr int DEFAULT_BACKLOG = 16;
|
||||||
static constexpr uint64_t DEFAULT_BAN_TIME = 600;
|
static constexpr uint64_t DEFAULT_BAN_TIME = 600;
|
||||||
|
static constexpr uint64_t PEER_REQUEST_DELAY = 60;
|
||||||
|
|
||||||
namespace p2pool {
|
namespace p2pool {
|
||||||
|
|
||||||
|
@ -373,7 +374,7 @@ void P2PServer::update_peer_list()
|
||||||
void P2PServer::send_peer_list_request(P2PClient* client, uint64_t cur_time)
|
void P2PServer::send_peer_list_request(P2PClient* client, uint64_t cur_time)
|
||||||
{
|
{
|
||||||
// Send peer list requests at random intervals (60-120 seconds)
|
// Send peer list requests at random intervals (60-120 seconds)
|
||||||
client->m_nextOutgoingPeerListRequest = cur_time + (60 + (get_random64() % 61));
|
client->m_nextOutgoingPeerListRequest = cur_time + (PEER_REQUEST_DELAY + (get_random64() % (PEER_REQUEST_DELAY + 1)));
|
||||||
|
|
||||||
const bool result = send(client,
|
const bool result = send(client,
|
||||||
[client](uint8_t* buf, size_t buf_size)
|
[client](uint8_t* buf, size_t buf_size)
|
||||||
|
@ -1227,8 +1228,7 @@ P2PServer::P2PClient::P2PClient()
|
||||||
, m_handshakeComplete(false)
|
, m_handshakeComplete(false)
|
||||||
, m_handshakeInvalid(false)
|
, m_handshakeInvalid(false)
|
||||||
, m_listenPort(-1)
|
, m_listenPort(-1)
|
||||||
, m_fastPeerListRequestCount(0)
|
, m_prevPeersSent(0)
|
||||||
, m_prevIncomingPeerListRequest(0)
|
|
||||||
, m_nextOutgoingPeerListRequest(0)
|
, m_nextOutgoingPeerListRequest(0)
|
||||||
, m_lastPeerListRequestTime{}
|
, m_lastPeerListRequestTime{}
|
||||||
, m_peerListPendingRequests(0)
|
, m_peerListPendingRequests(0)
|
||||||
|
@ -1329,8 +1329,7 @@ void P2PServer::P2PClient::reset()
|
||||||
m_handshakeComplete = false;
|
m_handshakeComplete = false;
|
||||||
m_handshakeInvalid = false;
|
m_handshakeInvalid = false;
|
||||||
m_listenPort = -1;
|
m_listenPort = -1;
|
||||||
m_fastPeerListRequestCount = 0;
|
m_prevPeersSent = 0;
|
||||||
m_prevIncomingPeerListRequest = 0;
|
|
||||||
m_nextOutgoingPeerListRequest = 0;
|
m_nextOutgoingPeerListRequest = 0;
|
||||||
m_lastPeerListRequestTime = {};
|
m_lastPeerListRequestTime = {};
|
||||||
m_peerListPendingRequests = 0;
|
m_peerListPendingRequests = 0;
|
||||||
|
@ -2118,46 +2117,40 @@ bool P2PServer::P2PClient::on_peer_list_request(const uint8_t*)
|
||||||
P2PServer* server = static_cast<P2PServer*>(m_owner);
|
P2PServer* server = static_cast<P2PServer*>(m_owner);
|
||||||
server->check_event_loop_thread(__func__);
|
server->check_event_loop_thread(__func__);
|
||||||
|
|
||||||
const uint64_t cur_time = seconds_since_epoch();
|
|
||||||
const bool first = (m_prevIncomingPeerListRequest == 0);
|
|
||||||
|
|
||||||
// Allow peer list requests no more than once every 30 seconds
|
|
||||||
if (cur_time - m_prevIncomingPeerListRequest < 30) {
|
|
||||||
++m_fastPeerListRequestCount;
|
|
||||||
if (m_fastPeerListRequestCount >= 3) {
|
|
||||||
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " is sending PEER_LIST_REQUEST too often");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_prevIncomingPeerListRequest = cur_time;
|
|
||||||
|
|
||||||
Peer peers[PEER_LIST_RESPONSE_MAX_PEERS];
|
Peer peers[PEER_LIST_RESPONSE_MAX_PEERS];
|
||||||
uint32_t num_selected_peers = 0;
|
uint32_t num_selected_peers = 0;
|
||||||
|
|
||||||
// Send every 4th peer on average, selected at random
|
const uint64_t cur_time = seconds_since_epoch();
|
||||||
const uint32_t peers_to_send_target = std::min<uint32_t>(PEER_LIST_RESPONSE_MAX_PEERS, std::max<uint32_t>(1, server->m_numConnections / 4));
|
const bool first = (m_prevPeersSent == 0);
|
||||||
uint32_t n = 0;
|
|
||||||
|
|
||||||
for (P2PClient* client = static_cast<P2PClient*>(server->m_connectedClientsList->m_next); client != server->m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
// Rate limit peer list requests (send an empty response if the request comes too soon)
|
||||||
if (!client->is_good() || (client->m_addr == m_addr)) {
|
if (first || (cur_time >= m_prevPeersSent + PEER_REQUEST_DELAY)) {
|
||||||
continue;
|
m_prevPeersSent = cur_time;
|
||||||
}
|
|
||||||
|
|
||||||
const Peer p{ client->m_isV6, client->m_addr, client->m_listenPort, 0, 0 };
|
// Send every 4th peer on average, selected at random
|
||||||
++n;
|
const uint32_t peers_to_send_target = std::min<uint32_t>(PEER_LIST_RESPONSE_MAX_PEERS, std::max<uint32_t>(1, server->m_numConnections / 4));
|
||||||
|
uint32_t n = 0;
|
||||||
|
|
||||||
// Use https://en.wikipedia.org/wiki/Reservoir_sampling algorithm
|
for (P2PClient* client = static_cast<P2PClient*>(server->m_connectedClientsList->m_next); client != server->m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
||||||
if (num_selected_peers < peers_to_send_target) {
|
if (!client->is_good() || (client->m_addr == m_addr)) {
|
||||||
peers[num_selected_peers++] = p;
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t k;
|
const Peer p{ client->m_isV6, client->m_addr, client->m_listenPort, 0, 0 };
|
||||||
umul128(server->get_random64(), n, &k);
|
++n;
|
||||||
|
|
||||||
if (k < peers_to_send_target) {
|
// Use https://en.wikipedia.org/wiki/Reservoir_sampling algorithm
|
||||||
peers[k] = p;
|
if (num_selected_peers < peers_to_send_target) {
|
||||||
|
peers[num_selected_peers++] = p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t k;
|
||||||
|
umul128(server->get_random64(), n, &k);
|
||||||
|
|
||||||
|
if (k < peers_to_send_target) {
|
||||||
|
peers[k] = p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,8 +131,7 @@ public:
|
||||||
bool m_handshakeInvalid;
|
bool m_handshakeInvalid;
|
||||||
int m_listenPort;
|
int m_listenPort;
|
||||||
|
|
||||||
uint32_t m_fastPeerListRequestCount;
|
uint64_t m_prevPeersSent;
|
||||||
uint64_t m_prevIncomingPeerListRequest;
|
|
||||||
uint64_t m_nextOutgoingPeerListRequest;
|
uint64_t m_nextOutgoingPeerListRequest;
|
||||||
std::chrono::high_resolution_clock::time_point m_lastPeerListRequestTime;
|
std::chrono::high_resolution_clock::time_point m_lastPeerListRequestTime;
|
||||||
int m_peerListPendingRequests;
|
int m_peerListPendingRequests;
|
||||||
|
|
Loading…
Reference in a new issue