From 05c38853d7f50fb4ad87e28fa7b46017f78e2955 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Wed, 4 Jul 2018 12:56:11 -0700 Subject: [PATCH] net: add more aggressive dos prevention. --- lib/net/common.js | 32 ++++++++++++++++++++++++++++++++ lib/net/packets.js | 8 ++++---- lib/net/peer.js | 6 ++++++ lib/net/pool.js | 32 +++++++++++++++++++++++--------- 4 files changed, 65 insertions(+), 13 deletions(-) diff --git a/lib/net/common.js b/lib/net/common.js index c5342cde..447854df 100644 --- a/lib/net/common.js +++ b/lib/net/common.js @@ -195,3 +195,35 @@ exports.ZERO_SIG = Buffer.alloc(64, 0x00); */ exports.ZERO_NONCE = Buffer.alloc(8, 0x00); + +/** + * Maximum inv/getdata size. + * @const {Number} + * @default + */ + +exports.MAX_INV = 50000; + +/** + * Maximum number of requests. + * @const {Number} + * @default + */ + +exports.MAX_REQUEST = 5000; + +/** + * Maximum number of block requests. + * @const {Number} + * @default + */ + +exports.MAX_BLOCK_REQUEST = 50000 + 1000; + +/** + * Maximum number of tx requests. + * @const {Number} + * @default + */ + +exports.MAX_TX_REQUEST = 10000; diff --git a/lib/net/packets.js b/lib/net/packets.js index a4b3a63a..d0190981 100644 --- a/lib/net/packets.js +++ b/lib/net/packets.js @@ -811,7 +811,7 @@ class InvPacket extends Packet { */ toWriter(bw) { - assert(this.items.length <= 50000); + assert(this.items.length <= common.MAX_INV); bw.writeVarint(this.items.length); @@ -840,7 +840,7 @@ class InvPacket extends Packet { fromReader(br) { const count = br.readVarint(); - assert(count <= 50000, 'Inv item count too high.'); + assert(count <= common.MAX_INV, 'Inv item count too high.'); for (let i = 0; i < count; i++) this.items.push(InvItem.fromReader(br)); @@ -1012,7 +1012,7 @@ class GetBlocksPacket extends Packet { */ toWriter(bw) { - assert(this.locator.length <= 50000, 'Too many block hashes.'); + assert(this.locator.length <= common.MAX_INV, 'Too many block hashes.'); bw.writeU32(this.version); bw.writeVarint(this.locator.length); @@ -1046,7 +1046,7 @@ class GetBlocksPacket extends Packet { const count = br.readVarint(); - assert(count <= 50000, 'Too many block hashes.'); + assert(count <= common.MAX_INV, 'Too many block hashes.'); for (let i = 0; i < count; i++) this.locator.push(br.readHash('hex')); diff --git a/lib/net/peer.js b/lib/net/peer.js index 97d4aed1..804ef397 100644 --- a/lib/net/peer.js +++ b/lib/net/peer.js @@ -1293,7 +1293,13 @@ class Peer extends EventEmitter { if (!entry) { entry = new RequestEntry(); + this.responseMap.set(type, entry); + + if (this.responseMap.size >= common.MAX_REQUEST) { + this.destroy(); + return; + } } entry.setTimeout(timeout); diff --git a/lib/net/pool.js b/lib/net/pool.js index b3597d65..33e54d1c 100644 --- a/lib/net/pool.js +++ b/lib/net/pool.js @@ -865,7 +865,7 @@ class Pool extends EventEmitter { items.push(node.hash); - if (items.length === 50000) + if (items.length === common.MAX_INV) break; } @@ -1586,7 +1586,7 @@ class Pool extends EventEmitter { async _handleInv(peer, packet) { const items = packet.items; - if (items.length > 50000) { + if (items.length > common.MAX_INV) { peer.increaseBan(100); return; } @@ -1738,7 +1738,7 @@ class Pool extends EventEmitter { async handleGetData(peer, packet) { const items = packet.items; - if (items.length > 50000) { + if (items.length > common.MAX_INV) { this.logger.warning( 'Peer sent inv with >50k items (%s).', peer.hostname()); @@ -2802,12 +2802,10 @@ class Pool extends EventEmitter { return; } - if (this.options.blockMode === 1) { - if (peer.compactBlocks.size >= 15) { - this.logger.warning('Compact block DoS attempt (%s).', peer.hostname()); - peer.destroy(); - return; - } + if (peer.compactBlocks.size >= 15) { + this.logger.warning('Compact block DoS attempt (%s).', peer.hostname()); + peer.destroy(); + return; } block.now = Date.now(); @@ -3349,6 +3347,14 @@ class Pool extends EventEmitter { if (items.length === 0) return; + if (peer.blockMap.size >= common.MAX_BLOCK_REQUEST) { + this.logger.warning( + 'Peer advertised too many blocks (%s).', + peer.hostname()); + peer.destroy(); + return; + } + this.logger.debug( 'Requesting %d/%d blocks from peer with getdata (%s).', items.length, @@ -3393,6 +3399,14 @@ class Pool extends EventEmitter { if (items.length === 0) return; + if (peer.txMap.size >= common.MAX_TX_REQUEST) { + this.logger.warning( + 'Peer advertised too many txs (%s).', + peer.hostname()); + peer.destroy(); + return; + } + this.logger.debug( 'Requesting %d/%d txs from peer with getdata (%s).', items.length,