net: refactor host and peer list.

This commit is contained in:
Christopher Jeffrey 2016-12-20 15:40:36 -08:00
parent 127a52aaf1
commit 25101f1784
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
4 changed files with 107 additions and 138 deletions

View File

@ -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,

View File

@ -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;
};
/**

View File

@ -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);
};
/**

View File

@ -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;
}