diff --git a/lib/peer.js b/lib/peer.js index a8f4dc96..627ecf4d 100644 --- a/lib/peer.js +++ b/lib/peer.js @@ -217,10 +217,34 @@ Peer.prototype._sendPong = function(nonce) { * Internal function that tries to read a message from the data buffer */ Peer.prototype._readMessage = function() { - var message = this.messages.parseBuffer(this.dataBuffer); - if (message) { - this.emit(message.command, message); - this._readMessage(); + try { + var message = this.messages.parseBuffer(this.dataBuffer); + if (message) { + this.emit(message.command, message); + this._readMessage(); + } + } catch (error) { + if (error.message.indexOf('Unsupported message command:') !== -1) { + this.sendMessage(this.messages.Reject({ + ccode: this.messages.Reject._constructor.CCODE.REJECT_INVALID, + reason: 'Unknown command', + message: 'Unknown command', + data: '' + })); + return; + } + + if (error.message.indexOf('Data still available after parsing') !== -1) { + this.sendMessage(this.messages.Reject({ + ccode: this.messages.Reject._constructor.CCODE.REJECT_MALFORMED, + reason: 'Malformed payload', + message: 'Unknown command', + data: '' + })); + return; + } + + throw error; } }; diff --git a/test/peer.js b/test/peer.js index 406eab62..e8467717 100644 --- a/test/peer.js +++ b/test/peer.js @@ -240,4 +240,40 @@ describe('Peer', function() { }); }); + it('send reject message if unknown command is received', function(done) { + var peer = new Peer({host: 'localhost'}); + peer.sendMessage = function(message) { + message.command.should.equal('reject'); + message.reason.should.equal('Unknown command'); + message.ccode.should.equal(messages.Reject._constructor.CCODE.REJECT_INVALID); + done(); + }; + const rawData = 'f9beb4d9' + // bitcoin mainnet magic number + '6e6f65786973740000000000' + // command (padded to 16 bytes) + '20000000' + // payload length (32) + '31085cf0' + // digest - sha256(sha256(payloadBuf)).slice(0,4) + '177aace029c59e693bb46cbe028a05ed5b8c4615f7ce590626683e2f56a22b2d'; // payload (random bytes here) + peer.dataBuffer.push(new Buffer(rawData, 'hex')); + peer._readMessage(); + }); + + describe('send reject message for malformed payload', function() { + it('declared payload length is lower than actual payload length', function(done) { + var peer = new Peer({host: 'localhost'}); + peer.sendMessage = function(message) { + message.command.should.equal('reject'); + message.reason.should.equal('Malformed payload'); + message.ccode.should.equal(messages.Reject._constructor.CCODE.REJECT_MALFORMED); + done(); + }; + const rawData = 'f9beb4d9' + // bitcoin mainnet magic number + '70696e670000000000000000' + // command (padded to 16 bytes) + '20000000' + // payload length (here we declare 32 but actually it is 34) + '31085cf0' + // digest - sha256(sha256(payloadBuf)).slice(0,4) of the declared payload slice + // payload (random bytes here + added 0e at the end) + '177aace029c59e693bb46cbe028a05ed5b8c4615f7ce590626683e2f56a22b2d0e'; + peer.dataBuffer.push(new Buffer(rawData, 'hex')); + peer._readMessage(); + }); + }); });