From 25101f1784c0d8f9081bc7351450e21efc67bf50 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Tue, 20 Dec 2016 15:40:36 -0800 Subject: [PATCH] net: refactor host and peer list. --- lib/http/rpc.js | 56 ++++++++--------- lib/net/peer.js | 19 +++--- lib/net/pool.js | 156 ++++++++++++++++++------------------------------ lib/utils/ip.js | 14 ++++- 4 files changed, 107 insertions(+), 138 deletions(-) diff --git a/lib/http/rpc.js b/lib/http/rpc.js index eed3bb46..51b9f816 100644 --- a/lib/http/rpc.js +++ b/lib/http/rpc.js @@ -31,6 +31,7 @@ var Outpoint = require('../primitives/outpoint'); var Output = require('../primitives/output'); var TX = require('../primitives/tx'); var Logger = require('../node/logger'); +var IP = require('../utils/ip'); /** * RPC @@ -388,7 +389,7 @@ RPC.prototype.getnetworkinfo = co(function* getnetworkinfo(args) { }); RPC.prototype.addnode = co(function* addnode(args) { - var i, node, cmd, seed, addr, peer; + var node, cmd, addr, peer; if (args.help || args.length !== 2) throw new RPCError('addnode "node" "add|remove|onetry"'); @@ -399,21 +400,15 @@ RPC.prototype.addnode = co(function* addnode(args) { switch (cmd) { case 'add': - this.pool.seeds.push(addr); + this.pool.hosts.add(addr); break; case 'remove': - for (i = 0; i < this.pool.seeds.length; i++) { - seed = this.pool.seeds[i]; - if (seed.hostname === addr.hostname) { - this.pool.seeds.splice(i, 1); - break; - } - } + this.pool.hosts.remove(addr.hostname); break; case 'onetry': - if (!this.pool.peers.get(addr)) { - peer = this.pool.createPeer(addr); - this.pool.peers.addOutbound(peer); + if (!this.pool.peers.get(addr.hostname)) { + peer = this.pool.createPeer(addr.port, addr.host); + this.pool.peers.add(peer); } break; } @@ -422,15 +417,16 @@ RPC.prototype.addnode = co(function* addnode(args) { }); RPC.prototype.disconnectnode = co(function* disconnectnode(args) { - var node, addr, peer; + var addr, peer; if (args.help || args.length !== 1) throw new RPCError('disconnectnode "node"'); - node = toString(args[0]); - addr = NetAddress.fromHostname(node, this.network); + addr = toString(args[0]); + addr = IP.parseHost(addr, this.network.port); + + peer = this.pool.peers.get(addr.hostname); - peer = this.pool.peers.get(addr); if (peer) peer.destroy(); @@ -439,15 +435,15 @@ RPC.prototype.disconnectnode = co(function* disconnectnode(args) { RPC.prototype.getaddednodeinfo = co(function* getaddednodeinfo(args) { var out = []; - var host, addr, peer; + var addr, peer; if (args.help || args.length < 1 || args.length > 2) throw new RPCError('getaddednodeinfo dummy ( "node" )'); if (args.length === 2) { - host = toString(args[1]); - addr = NetAddress.fromHostname(host, this.network); - peer = this.pool.peers.get(addr); + addr = toString(args[1]); + addr = IP.parseHost(addr, this.network.port); + peer = this.pool.peers.get(addr.hostname); if (!peer) throw new RPCError('Node has not been added.'); return [this._toAddedNode(peer)]; @@ -548,7 +544,7 @@ RPC.prototype.ping = co(function* ping(args) { }); RPC.prototype.setban = co(function* setban(args) { - var host, ip; + var addr, peer; if (args.help || args.length < 2 @@ -557,15 +553,21 @@ RPC.prototype.setban = co(function* setban(args) { + ' "add|remove" (bantime) (absolute)'); } - host = toString(args[0]); - ip = NetAddress.fromHostname(host, this.network); + addr = toString(args[0]); + addr = IP.parseHost(addr, this.network); switch (args[1]) { case 'add': - this.pool.ban(ip); + peer = this.pool.peers.get(addr.hostname); + if (peer) { + this.pool.ban(peer); + break; + } + this.pool.hosts.ban(addr.host); + this.pool.hosts.remove(addr.hostname); break; case 'remove': - this.pool.unban(ip); + this.pool.hosts.unban(addr.host); break; } @@ -579,11 +581,11 @@ RPC.prototype.listbanned = co(function* listbanned(args) { throw new RPCError('listbanned'); banned = []; - keys = Object.keys(this.pool.hosts.misbehaving); + keys = Object.keys(this.pool.hosts.banned); for (i = 0; i < keys.length; i++) { host = keys[i]; - time = this.pool.hosts.misbehaving[host]; + time = this.pool.hosts.banned[host]; banned.push({ address: host, banned_until: time + constants.BAN_TIME, diff --git a/lib/net/peer.js b/lib/net/peer.js index 39bfce92..6a029bc3 100644 --- a/lib/net/peer.js +++ b/lib/net/peer.js @@ -2638,22 +2638,21 @@ Peer.prototype.sendCompact = function sendCompact() { this.send(new packets.SendCmpctPacket(0, version)); }; -/** - * Check whether the peer is banned (banScore >= 100). - * @returns {Boolean} - */ - -Peer.prototype.isBanned = function isBanned() { - return this.pool.hosts.isBanned(this); -}; - /** * Increase banscore on peer. * @param {Number} score */ Peer.prototype.increaseBan = function increaseBan(score) { - return this.pool.increaseBan(this, score); + this.banScore += score; + + if (this.banScore >= constants.BAN_SCORE) { + this.logger.debug('Ban threshold exceeded (%s).', this.hostname); + this.pool.ban(this); + return true; + } + + return false; }; /** diff --git a/lib/net/pool.js b/lib/net/pool.js index 4ca6eba7..27babe6c 100644 --- a/lib/net/pool.js +++ b/lib/net/pool.js @@ -471,7 +471,7 @@ Pool.prototype.unlisten = function unlisten() { */ Pool.prototype.handleInbound = function handleInbound(socket) { - var addr; + var host; if (!socket.remoteAddress) { this.logger.debug('Ignoring disconnected leech.'); @@ -479,27 +479,23 @@ Pool.prototype.handleInbound = function handleInbound(socket) { return; } - addr = NetAddress.fromSocket(socket, this.network); + host = IP.normalize(socket.remoteAddress); if (this.peers.inbound >= this.maxInbound) { - this.logger.debug('Ignoring leech: too many inbound (%s).', addr.hostname); + this.logger.debug('Ignoring leech: too many inbound (%s).', host); socket.destroy(); return; } - if (this.hosts.isBanned(addr)) { - this.logger.debug('Ignoring banned leech (%s).', addr.hostname); + if (this.hosts.isBanned(host)) { + this.logger.debug('Ignoring banned leech (%s).', host); socket.destroy(); return; } - // Some kind of weird port collision - // between inbound ports and outbound ports. - if (this.peers.get(addr)) { - this.logger.debug('Port collision (%s).', addr.hostname); - socket.destroy(); - return; - } + host = IP.hostname(host, socket.remotePort); + + assert(!this.peers.get(host), 'Port collision.'); this.addInbound(socket); }; @@ -610,10 +606,7 @@ Pool.prototype.addLoader = function addLoader() { addr = this.hosts.getHost(); - if (this.peers.get(addr)) - return; - - peer = this.peers.get(addr); + peer = this.peers.get(addr.hostname); if (peer) { this.setLoader(peer); @@ -1524,7 +1517,7 @@ Pool.prototype.addOutbound = function addOutbound() { addr = this.hosts.getHost(); - if (this.peers.get(addr)) + if (this.peers.get(addr.hostname)) return; peer = this.createPeer(addr.port, addr.host); @@ -1930,57 +1923,16 @@ Pool.prototype.setFeeRate = function setFeeRate(rate) { peer.sendFeeRate(rate); }; -/** - * Increase peer's ban score. - * @param {Peer} peer - * @param {Number} score - * @returns {Boolean} Whether the peer was banned. - */ - -Pool.prototype.increaseBan = function increaseBan(peer, score) { - peer.banScore += score; - - if (peer.banScore >= constants.BAN_SCORE) { - this.logger.debug('Ban threshold exceeded (%s).', peer.hostname); - this.ban(peer); - return true; - } - - return false; -}; - /** * Ban a peer. - * @param {NetAddress} addr + * @param {Peer} peer */ -Pool.prototype.ban = function ban(addr) { - var peer = this.peers.get(addr); - - this.logger.debug('Banning peer (%s).', addr.hostname); - this.hosts.ban(addr); - - if (peer) - peer.destroy(); -}; - -/** - * Unban a peer. - * @param {String|NetAddress} addr - */ - -Pool.prototype.unban = function unban(addr) { - this.hosts.unban(addr); -}; - -/** - * Test whether the host is banned. - * @param {NetAddress} addr - * @returns {Boolean} - */ - -Pool.prototype.isBanned = function isBanned(addr) { - return this.hosts.isBanned(addr); +Pool.prototype.ban = function ban(peer) { + this.logger.debug('Banning peer (%s).', peer.hostname); + this.hosts.ban(peer.host); + this.hosts.remove(peer.hostname); + peer.destroy(); }; /** @@ -1988,14 +1940,10 @@ Pool.prototype.isBanned = function isBanned(addr) { * @param {Peer} peer */ -Pool.prototype.ignore = function ignore(addr) { - var peer = this.peers.get(addr); - - this.logger.debug('Ignoring peer (%s).', addr.hostname); - this.hosts.ignore(addr); - - if (peer) - peer.destroy(); +Pool.prototype.ignore = function ignore(peer) { + this.logger.debug('Ignoring peer (%s).', peer.hostname); + this.hosts.ignore(peer.hostname); + peer.destroy(); }; /** @@ -2129,8 +2077,21 @@ PeerList.prototype.repurpose = function repurpose(peer) { this.load = peer; }; -PeerList.prototype.get = function get(addr) { - return this.map[addr.hostname]; +PeerList.prototype.get = function get(hostname) { + return this.map[hostname]; +}; + +PeerList.prototype.getByHost = function getByHost(host) { + var peers = []; + var peer; + + for (peer = this.list.head; peer; peer = peer.next) { + if (peer.host !== host) + continue; + peers.push(peer); + } + + return peers; }; PeerList.prototype.destroy = function destroy() { @@ -2156,7 +2117,6 @@ PeerList.prototype.destroy = function destroy() { function HostList(pool) { this.network = pool.network; this.logger = pool.logger; - this.maxOutbound = pool.maxOutbound; this.proxyServer = pool.proxyServer; this.list = new List(); this.seeds = []; @@ -2242,55 +2202,54 @@ HostList.prototype.add = function add(addr) { /** * Remove host from host list. - * @param {NetAddress} addr + * @param {String} hostname * @returns {Boolean} */ -HostList.prototype.remove = function remove(addr) { - var item = this.map[addr.hostname]; +HostList.prototype.remove = function remove(hostname) { + var addr = this.map[hostname]; - if (!item) + if (!addr) return; - assert(this.list.remove(item)); - delete this.map[item.hostname]; + assert(this.list.remove(addr)); + delete this.map[addr.hostname]; - return item; + return addr; }; /** * Mark a peer as banned. - * @param {NetAddress} addr + * @param {String} host */ -HostList.prototype.ban = function ban(addr) { - this.banned[addr.host] = util.now(); - return this.remove(addr); +HostList.prototype.ban = function ban(host) { + this.banned[host] = util.now(); }; /** * Unban host. - * @param {NetAddress} addr + * @param {String} host */ -HostList.prototype.unban = function unban(addr) { - delete this.banned[addr.host]; +HostList.prototype.unban = function unban(host) { + delete this.banned[host]; }; /** * Test whether the host is banned. - * @param {NetAddress} addr + * @param {String} host * @returns {Boolean} */ -HostList.prototype.isBanned = function isBanned(addr) { - var time = this.banned[addr.host]; +HostList.prototype.isBanned = function isBanned(host) { + var time = this.banned[host]; if (time == null) return false; if (util.now() > time + constants.BAN_TIME) { - delete this.banned[addr.host]; + delete this.banned[host]; return false; } @@ -2299,16 +2258,17 @@ HostList.prototype.isBanned = function isBanned(addr) { /** * Ignore peer. - * @param {NetAddress} addr + * @param {String} hostname */ -HostList.prototype.ignore = function ignore(addr) { - var item = this.map[addr.hostname]; +HostList.prototype.ignore = function ignore(hostname) { + var addr = this.map[hostname]; - if (!item) + if (!addr) return; - this.list.remove(item); + delete this.map[hostname]; + this.list.remove(addr); }; /** diff --git a/lib/utils/ip.js b/lib/utils/ip.js index a6080893..718fe767 100644 --- a/lib/utils/ip.js +++ b/lib/utils/ip.js @@ -30,7 +30,7 @@ var ipv6Regex = */ IP.parseHost = function parseHost(addr, fallback) { - var parts, host, port, version; + var parts, host, port, version, hostname; assert(typeof addr === 'string'); @@ -94,7 +94,14 @@ IP.parseHost = function parseHost(addr, fallback) { if (version !== -1) host = IP.normalize(host); - return new Address(host, port, version); + hostname = host; + + if (version === 6) + hostname = '[' + hostname + ']'; + + hostname += ':' + port; + + return new Address(host, port, version, hostname); }; /** @@ -445,8 +452,9 @@ IP.loopback = function(family) { * Helpers */ -function Address(host, port, version) { +function Address(host, port, version, hostname) { this.host = host; this.port = port; this.version = version; + this.hostname = hostname; }