peer: avoid compactblock dos.
This commit is contained in:
parent
5dc0202d56
commit
cca763ca95
@ -111,6 +111,7 @@ function Peer(pool) {
|
||||
this.compactMode = -1;
|
||||
this.compactWitness = false;
|
||||
this.compactBlocks = {};
|
||||
this.compactAmount = 0;
|
||||
this.lastMerkle = null;
|
||||
this.waitingTX = 0;
|
||||
this.syncSent = false;
|
||||
@ -866,7 +867,7 @@ Peer.prototype.sendFeeRate = function sendFeeRate(rate) {
|
||||
|
||||
Peer.prototype.destroy = function destroy() {
|
||||
var connected = this.connected;
|
||||
var i, keys, cmd, entry, hash;
|
||||
var i, keys, cmd, entry;
|
||||
|
||||
if (this.destroyed)
|
||||
return;
|
||||
@ -909,14 +910,8 @@ Peer.prototype.destroy = function destroy() {
|
||||
entry.reject(new Error('Peer was destroyed.'));
|
||||
}
|
||||
|
||||
keys = Object.keys(this.compactBlocks);
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
hash = keys[i];
|
||||
entry = this.compactBlocks[hash];
|
||||
delete this.compactBlocks[hash];
|
||||
entry.destroy();
|
||||
}
|
||||
this.compactBlocks = {};
|
||||
this.compactAmount = 0;
|
||||
|
||||
this.locker.destroy();
|
||||
|
||||
@ -1200,9 +1195,11 @@ Peer.prototype.blockType = function blockType() {
|
||||
if (this.options.spv)
|
||||
return invTypes.FILTERED_BLOCK;
|
||||
|
||||
if (this.options.compact && this.compactMode !== -1) {
|
||||
if (!this.options.witness || this.compactWitness)
|
||||
return invTypes.CMPCT_BLOCK;
|
||||
if (this.outbound) {
|
||||
if (this.options.compact && this.compactMode !== -1) {
|
||||
if (!this.options.witness || this.compactWitness)
|
||||
return invTypes.CMPCT_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.haveWitness)
|
||||
@ -2584,7 +2581,14 @@ Peer.prototype.handleCmpctBlock = co(function* handleCmpctBlock(packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.compactAmount >= 10) {
|
||||
this.logger.warning('Compact block DoS attempt (%s).', this.hostname);
|
||||
this.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
this.compactBlocks[hash] = block;
|
||||
this.compactAmount++;
|
||||
|
||||
this.send(new packets.GetBlockTxnPacket(block.toRequest()));
|
||||
|
||||
@ -2652,10 +2656,13 @@ Peer.prototype.handleBlockTxn = co(function* handleBlockTxn(packet) {
|
||||
|
||||
if (!block) {
|
||||
this.logger.debug('Peer sent unsolicited blocktxn (%s).', this.hostname);
|
||||
this.compactBlocks = {};
|
||||
this.compactAmount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
delete this.compactBlocks[res.hash];
|
||||
this.compactAmount--;
|
||||
|
||||
if (!block.fillMissing(res)) {
|
||||
this.increaseBan(100);
|
||||
|
||||
@ -364,7 +364,7 @@ Pool.prototype._close = co(function* close() {
|
||||
for (i = 0; i < hashes.length; i++) {
|
||||
hash = hashes[i];
|
||||
item = this.invMap[hash];
|
||||
item.finish();
|
||||
item.resolve();
|
||||
}
|
||||
|
||||
this.peers.destroy();
|
||||
@ -455,7 +455,7 @@ Pool.prototype.listen = function listen() {
|
||||
this.server = this.createServer();
|
||||
|
||||
this.server.on('connection', function(socket) {
|
||||
self.handleInbound(socket);
|
||||
self.handleSocket(socket);
|
||||
});
|
||||
|
||||
this.server.on('listening', function() {
|
||||
@ -496,11 +496,11 @@ Pool.prototype.unlisten = function unlisten() {
|
||||
* @param {net.Socket} socket
|
||||
*/
|
||||
|
||||
Pool.prototype.handleInbound = function handleInbound(socket) {
|
||||
Pool.prototype.handleSocket = function handleSocket(socket) {
|
||||
var host;
|
||||
|
||||
if (!socket.remoteAddress) {
|
||||
this.logger.debug('Ignoring disconnected leech.');
|
||||
this.logger.debug('Ignoring disconnected peer.');
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
@ -508,13 +508,13 @@ Pool.prototype.handleInbound = function handleInbound(socket) {
|
||||
host = IP.normalize(socket.remoteAddress);
|
||||
|
||||
if (this.peers.inbound >= this.maxInbound) {
|
||||
this.logger.debug('Ignoring leech: too many inbound (%s).', host);
|
||||
this.logger.debug('Ignoring peer: too many inbound (%s).', host);
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.hosts.isBanned(host)) {
|
||||
this.logger.debug('Ignoring banned leech (%s).', host);
|
||||
this.logger.debug('Ignoring banned peer (%s).', host);
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
@ -585,8 +585,6 @@ Pool.prototype.setLoader = function setLoader(peer) {
|
||||
|
||||
peer.sync();
|
||||
|
||||
this.fillOutbound();
|
||||
|
||||
this.emit('loader', peer);
|
||||
};
|
||||
|
||||
@ -1021,7 +1019,7 @@ Pool.prototype.handleBlock = co(function* handleBlock(peer, block) {
|
||||
Pool.prototype.handleTX = co(function* handleTX(peer, tx) {
|
||||
var hash = tx.hash('hex');
|
||||
var requested = this.fulfill(peer, hash);
|
||||
var i, missing;
|
||||
var missing;
|
||||
|
||||
if (!requested) {
|
||||
peer.invFilter.add(tx.hash());
|
||||
@ -2169,7 +2167,7 @@ BroadcastItem.prototype.refresh = function refresh() {
|
||||
|
||||
this.timeout = setTimeout(function() {
|
||||
self.emit('timeout');
|
||||
self.finish(new Error('Timed out.'));
|
||||
self.reject(new Error('Timed out.'));
|
||||
}, this.pool.invTimeout);
|
||||
};
|
||||
|
||||
@ -2192,28 +2190,49 @@ BroadcastItem.prototype.announce = function announce() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Finish the broadcast, potentially with an error.
|
||||
* @param {Error?} err
|
||||
* Finish the broadcast.
|
||||
*/
|
||||
|
||||
BroadcastItem.prototype.finish = function finish(err) {
|
||||
var i, job;
|
||||
|
||||
assert(this.timeout, 'Already finished.');
|
||||
BroadcastItem.prototype.cleanup = function cleanup() {
|
||||
assert(this.timeout != null, 'Already finished.');
|
||||
assert(this.pool.invMap[this.hash], 'Already finished.');
|
||||
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = null;
|
||||
|
||||
delete this.pool.invMap[this.hash];
|
||||
};
|
||||
|
||||
/**
|
||||
* Finish the broadcast, return with an error.
|
||||
* @param {Error} err
|
||||
*/
|
||||
|
||||
BroadcastItem.prototype.reject = function reject(err) {
|
||||
var i, job;
|
||||
|
||||
this.cleanup();
|
||||
|
||||
for (i = 0; i < this.jobs.length; i++) {
|
||||
job = this.jobs[i];
|
||||
if (err) {
|
||||
job.reject(err);
|
||||
continue;
|
||||
}
|
||||
job.resolve();
|
||||
job.reject(err);
|
||||
}
|
||||
|
||||
this.jobs.length = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Finish the broadcast successfully.
|
||||
*/
|
||||
|
||||
BroadcastItem.prototype.resolve = function resolve() {
|
||||
var i, job;
|
||||
|
||||
this.cleanup();
|
||||
|
||||
for (i = 0; i < this.jobs.length; i++) {
|
||||
job = this.jobs[i];
|
||||
job.resolve(false);
|
||||
}
|
||||
|
||||
this.jobs.length = 0;
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
var constants = require('../protocol/constants');
|
||||
var BufferReader = require('../utils/reader');
|
||||
var StaticWriter = require('../utils/staticwriter');
|
||||
var util = require('../utils/util');
|
||||
|
||||
/**
|
||||
* Inv Item
|
||||
|
||||
Loading…
Reference in New Issue
Block a user