ip and version.

This commit is contained in:
Christopher Jeffrey 2016-05-23 05:29:12 -07:00
parent ae41e11ff3
commit e8cf4ea8be
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
6 changed files with 198 additions and 208 deletions

View File

@ -244,10 +244,32 @@ Peer.prototype._init = function init() {
// Say hello. // Say hello.
this.write(this.framer.version({ this.write(this.framer.version({
version: constants.VERSION,
services: constants.LOCAL_SERVICES,
ts: bcoin.now(),
remote: {},
local: {
services: constants.LOCAL_SERVICES,
host: this.pool.host,
port: this.pool.port
},
nonce: this.pool.localNonce,
agent: constants.USER_AGENT,
height: this.chain.height, height: this.chain.height,
relay: this.options.relay, relay: this.options.relay,
nonce: this.pool.localNonce
})); }));
// Advertise our address.
if (this.pool.host !== '0.0.0.0'
&& !this.pool.options.selfish
&& this.pool.server) {
this.write(this.framer.addr([{
ts: utils.now() - (process.uptime() | 0),
services: constants.LOCAL_SERVICES,
host: this.pool.host,
port: this.pool.port
}]));
}
}; };
/** /**
@ -1302,26 +1324,23 @@ Peer.prototype._handleGetData = function handleGetData(items) {
Peer.prototype._handleAddr = function handleAddr(addrs) { Peer.prototype._handleAddr = function handleAddr(addrs) {
var now = utils.now(); var now = utils.now();
var i, addr, ts, host; var i, addr, ts;
for (i = 0; i < addrs.length; i++) { for (i = 0; i < addrs.length; i++) {
addr = addrs[i]; addr = addrs[i];
ts = addr.ts; ts = addr.ts;
host = addr.ipv4 !== '0.0.0.0'
? addr.ipv4
: addr.ipv6;
if (ts <= 100000000 || ts > now + 10 * 60) if (ts <= 100000000 || ts > now + 10 * 60)
ts = now - 5 * 24 * 60 * 60; ts = now - 5 * 24 * 60 * 60;
this.addrFilter.add(host, 'ascii'); this.addrFilter.add(addr.host, 'ascii');
this.emit('addr', { this.emit('addr', {
version: addr.version, version: addr.version,
ts: ts, ts: ts,
services: addr.services, services: addr.services,
host: host, host: addr.host,
port: addr.port || this.network.port port: addr.port || this.network.port
}); });
} }
@ -1375,7 +1394,7 @@ Peer.prototype._handleGetAddr = function handleGetAddr() {
var hosts = {}; var hosts = {};
var items = []; var items = [];
var ts = utils.now() - (process.uptime() | 0); var ts = utils.now() - (process.uptime() | 0);
var i, seed, version, peer; var i, seed, peer;
if (this.pool.options.selfish) if (this.pool.options.selfish)
return; return;
@ -1383,9 +1402,8 @@ Peer.prototype._handleGetAddr = function handleGetAddr() {
for (i = 0; i < this.pool.seeds.length; i++) { for (i = 0; i < this.pool.seeds.length; i++) {
seed = utils.parseHost(this.pool.seeds[i]); seed = utils.parseHost(this.pool.seeds[i]);
seed = this.pool.getPeer(seed.host) || seed; seed = this.pool.getPeer(seed.host) || seed;
version = utils.isIP(seed.host);
if (!version) if (!utils.isIP(seed.host))
continue; continue;
if (hosts[seed.host]) if (hosts[seed.host])
@ -1397,11 +1415,9 @@ Peer.prototype._handleGetAddr = function handleGetAddr() {
continue; continue;
items.push({ items.push({
network: this.network,
ts: seed.ts || ts, ts: seed.ts || ts,
services: seed.version ? seed.version.services : null, services: seed.version ? seed.version.services : 0,
ipv4: version === 4 ? seed.host : null, host: seed.host,
ipv6: version === 6 ? seed.host : null,
port: seed.port || this.network.port port: seed.port || this.network.port
}); });

View File

@ -108,6 +108,8 @@ function Pool(options) {
this.seeds = []; this.seeds = [];
this.hosts = {}; this.hosts = {};
this.setSeeds([]); this.setSeeds([]);
this.host = '0.0.0.0';
this.port = this.network.port;
this.server = null; this.server = null;
this.destroyed = false; this.destroyed = false;
@ -194,20 +196,7 @@ function Pool(options) {
interval: options.invInterval || 3000 interval: options.invInterval || 3000
}; };
function done(err) { this._init();
if (err)
return self.emit('error', err);
self.loaded = true;
self.emit('open');
self._init();
}
if (this.mempool)
this.mempool.open(done);
else
this.chain.open(done);
} }
utils.inherits(Pool, EventEmitter); utils.inherits(Pool, EventEmitter);
@ -316,6 +305,29 @@ Pool.prototype._init = function _init() {
self.emit('full'); self.emit('full');
bcoin.debug('Chain is fully synced (height=%d).', self.chain.height); bcoin.debug('Chain is fully synced (height=%d).', self.chain.height);
}); });
function done(err) {
if (err)
return self.emit('error', err);
self.loaded = true;
self.emit('open');
}
this.getIP(function(err, ip) {
if (err)
bcoin.error(err);
if (ip) {
self.host = ip;
bcoin.debug('External IP found: %s.', ip);
}
if (self.mempool)
self.mempool.open(done);
else
self.chain.open(done);
});
}; };
/** /**
@ -2088,6 +2100,62 @@ Pool.prototype.reject = function reject(peer, obj, code, reason, score) {
peer.setMisbehavior(score); peer.setMisbehavior(score);
}; };
/**
* Attempt to retrieve external IP from icanhazip.com.
* @param {Function} callback
*/
Pool.prototype.getIP = function getIP(callback) {
var self = this;
var request = require('./http/request');
var ip;
if (utils.isBrowser)
return callback(new Error('Could not find IP.'));
request({
method: 'GET',
uri: 'http://icanhazip.com',
expect: 'text'
}, function(err, res, body) {
if (err)
return self.getIP2(callback);
ip = body.trim();
if (!utils.isIP(ip))
return self.getIP2(callback);
return callback(null, ip);
});
};
/**
* Attempt to retrieve external IP from dyndns.org.
* @param {Function} callback
*/
Pool.prototype.getIP2 = function getIP2(callback) {
var request = require('./http/request');
var ip;
request({
method: 'GET',
uri: 'http://checkip.dyndns.org',
expect: 'html'
}, function(err, res, body) {
if (err)
return callback(err);
ip = /IP Address:\s*([0-9.:]+)/i.exec(body);
if (!ip || !utils.isIP(ip[1]))
return callback(new Error('Could not find IP.'));
return callback(null, ip[1]);
});
};
/** /**
* Represents an in-flight block or transaction. * Represents an in-flight block or transaction.
* @exports LoadRequest * @exports LoadRequest

View File

@ -17,8 +17,6 @@ var DUMMY = new Buffer([]);
* @exports Framer * @exports Framer
* @constructor * @constructor
* @param {Object} options * @param {Object} options
* @param {String} options.USER_AGENT - User agent string.
* @property {Buffer} agent
*/ */
function Framer(options) { function Framer(options) {
@ -30,8 +28,6 @@ function Framer(options) {
this.options = options; this.options = options;
this.network = bcoin.network.get(options.network); this.network = bcoin.network.get(options.network);
this.agent = options.agent || constants.USER_AGENT;
} }
/** /**
@ -94,12 +90,6 @@ Framer.prototype.packet = function packet(cmd, payload, checksum) {
*/ */
Framer.prototype.version = function version(options) { Framer.prototype.version = function version(options) {
if (!options)
options = {};
options.agent = this.agent;
options.network = this.network;
return this.packet('version', Framer.version(options)); return this.packet('version', Framer.version(options));
}; };
@ -409,7 +399,8 @@ Framer.prototype.addr = function addr(peers) {
*/ */
Framer.prototype.alert = function alert(options) { Framer.prototype.alert = function alert(options) {
return this.packet('alert', Framer.alert(options, this.network)); options.network = this.network;
return this.packet('alert', Framer.alert(options));
}; };
/** /**
@ -432,7 +423,6 @@ Framer.prototype.feeFilter = function feeFilter(options) {
Framer.address = function address(data, full, writer) { Framer.address = function address(data, full, writer) {
var p = new BufferWriter(writer); var p = new BufferWriter(writer);
var network = bcoin.network.get(data.network);
if (full) { if (full) {
if (!data.ts) if (!data.ts)
@ -442,22 +432,8 @@ Framer.address = function address(data, full, writer) {
} }
p.writeU64(data.services || 0); p.writeU64(data.services || 0);
p.writeBytes(utils.ip2array(data.host));
if (data.ipv6) { p.writeU16BE(data.port || 0);
p.writeBytes(utils.ip2array(data.ipv6, 6));
} else {
// We don't have an ipv6 address: convert
// ipv4 to ipv4-mapped ipv6 address.
p.writeU32BE(0x00000000);
p.writeU32BE(0x00000000);
p.writeU32BE(0x0000ffff);
if (data.ipv4)
p.writeBytes(utils.ip2array(data.ipv4, 4));
else
p.writeU32BE(0x00000000);
}
p.writeU16BE(data.port || network.port);
if (!writer) if (!writer)
p = p.render(); p = p.render();
@ -475,15 +451,13 @@ Framer.address = function address(data, full, writer) {
Framer.version = function version(options, writer) { Framer.version = function version(options, writer) {
var p = new BufferWriter(writer); var p = new BufferWriter(writer);
var agent = options.agent || constants.USER_AGENT; var agent = options.agent || constants.USER_AGENT;
var services = options.services;
var remote = options.remote || {}; var remote = options.remote || {};
var local = options.local || {}; var local = options.local || {};
var nonce = options.nonce; var nonce = options.nonce;
if (local.network == null) if (services == null)
local.network = options.network; services = constants.LOCAL_SERVICES;
if (remote.network == null)
remote.network = options.network;
if (local.services == null) if (local.services == null)
local.services = constants.LOCAL_SERVICES; local.services = constants.LOCAL_SERVICES;
@ -491,9 +465,9 @@ Framer.version = function version(options, writer) {
if (!nonce) if (!nonce)
nonce = utils.nonce(); nonce = utils.nonce();
p.write32(constants.VERSION); p.write32(options.version || constants.VERSION);
p.writeU64(constants.LOCAL_SERVICES); p.writeU64(services);
p.write64(utils.now()); p.write64(options.ts || bcoin.now());
Framer.address(remote, false, p); Framer.address(remote, false, p);
Framer.address(local, false, p); Framer.address(local, false, p);
p.writeU64(nonce); p.writeU64(nonce);
@ -1189,28 +1163,19 @@ Framer.reject = function reject(details, writer) {
/** /**
* Create an addr packet (without a header). * Create an addr packet (without a header).
* @param {InvItem[]} peers * @param {NetworkAddress[]} hosts
* @param {BufferWriter?} writer - A buffer writer to continue writing from. * @param {BufferWriter?} writer - A buffer writer to continue writing from.
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in. * @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
*/ */
Framer.addr = function addr(peers, writer) { Framer.addr = function addr(hosts, writer) {
var p = new BufferWriter(writer); var p = new BufferWriter(writer);
var i, peer; var i;
p.writeVarint(peers.length); p.writeVarint(hosts.length);
for (i = 0; i < peers.length; i++) { for (i = 0; i < hosts.length; i++)
peer = peers[i]; Framer.address(hosts[i], true, p);
Framer.address({
network: peer.network,
ts: peer.ts,
services: peer.services,
ipv6: peer.ipv6,
ipv4: peer.ipv4,
port: peer.port
}, true, p);
}
if (!writer) if (!writer)
p = p.render(); p = p.render();
@ -1221,16 +1186,14 @@ Framer.addr = function addr(peers, writer) {
/** /**
* Create an alert packet (without a header). * Create an alert packet (without a header).
* @param {AlertPacket} data * @param {AlertPacket} data
* @param {Network|NetworkType} network
* @param {BufferWriter?} writer - A buffer writer to continue writing from. * @param {BufferWriter?} writer - A buffer writer to continue writing from.
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in. * @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
*/ */
Framer.alert = function alert(data, network, writer) { Framer.alert = function alert(data, writer) {
var p, i, payload; var network = bcoin.network.get(data.network);
var key = data.key; var key = data.key;
var p, i, payload;
network = bcoin.network.get(network);
if (!key && network.alertPrivateKey) if (!key && network.alertPrivateKey)
key = network.alertPrivateKey; key = network.alertPrivateKey;
@ -1470,7 +1433,7 @@ Framer.filterClear = function filterClear() {
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in. * @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
*/ */
Framer.feeFilter = function feeFilter(data, network, writer) { Framer.feeFilter = function feeFilter(data, writer) {
var p = new BufferWriter(writer); var p = new BufferWriter(writer);
p.write64(data.rate); p.write64(data.rate);

View File

@ -1198,8 +1198,7 @@ Parser.parseAddress = function parseAddress(p, full) {
return { return {
ts: ts, ts: ts,
services: services, services: services,
ipv6: utils.array2ip(ip, 6), host: utils.array2ip(ip),
ipv4: utils.array2ip(ip, 4),
port: port port: port
}; };
}; };

View File

@ -258,8 +258,7 @@
* @typedef {Object} NetworkAddress * @typedef {Object} NetworkAddress
* @property {Number?} ts - Timestamp. * @property {Number?} ts - Timestamp.
* @property {Number?} services - Service bits. * @property {Number?} services - Service bits.
* @property {Buffer?} ipv4 - IPv4 address. * @property {String?} host - IP address (IPv6 or IPv4).
* @property {Buffer?} ipv6 - IPv6 address.
* @property {Number?} port - Port. * @property {Number?} port - Port.
* @global * @global
*/ */

View File

@ -899,159 +899,104 @@ utils.isIP = function isIP(ip) {
}; };
/** /**
* Cast an IPv6 or IPv4 to IPv4 or IPv6 respectively * Test whether a buffer is an ipv4-mapped ipv6 address.
* (if possible using ipv4-mapped ipv6 addresses). * @returns {Boolean}
* @param {Buffer} ip
* @param {Number} version - 4 or 6.
* @returns {Buffer} IP address.
*/ */
utils.ip2version = function ip2version(ip, version) { utils.isMapped = function isMapped(ip, version) {
var b, i, j; var i;
assert(Buffer.isBuffer(ip)); if (!Buffer.isBuffer(ip))
assert(version === 4 || version === 6, 'Bad IP version.'); return false;
if (version === 4) { for (i = 0; i < ip.length - 6; i++) {
// Check to see if this an if (ip[i] !== 0)
// ipv4-mapped ipv6 address. return false;
if (ip.length > 4) {
i = 0;
while (ip[i] === 0)
i++;
// Found an ipv4 address
if (ip.length - i === 6 && ip[i] === 0xff && ip[i + 1] === 0xff)
return utils.copy(ip.slice(-4));
// No ipv4 address
return new Buffer([0, 0, 0, 0]);
}
// Pad to 4 bytes
if (ip.length < 4) {
b = new Buffer(4);
i = ip.length;
j = b.length;
b.fill(0);
while (i)
b[--j] = ip[--i];
ip = b;
}
return ip;
} }
if (version === 6) { if (ip[10] !== 0xff && ip[11] !== 0xff)
// Pad to 4 bytes return false;
if (ip.length < 4) {
b = new Buffer(4);
i = ip.length;
j = b.length;
b.fill(0);
while (i)
b[--j] = ip[--i];
ip = b;
}
// Try to convert ipv4 address to return true;
// ipv4-mapped ipv6 address.
if (ip.length === 4) {
b = new Buffer(6);
i = ip.length;
j = b.length;
b.fill(0xff);
while (i)
b[--j] = ip[--i];
ip = b;
}
// Pad to 16 bytes
if (ip.length < 16) {
b = new Buffer(16);
i = ip.length;
j = b.length;
b.fill(0);
while (i)
b[--j] = ip[--i];
ip = b;
}
return ip;
}
}; };
/** /**
* Convert an IP string to a buffer. * Convert an IP string to a buffer.
* @param {String} ip * @param {String} ip
* @param {Number} version - 4 or 6.
* @returns {Buffer} * @returns {Buffer}
*/ */
utils.ip2array = function ip2array(ip, version) { utils.ip2array = function ip2array(ip) {
var type = utils.isIP(ip); var version, parts, out;
var parts;
assert(version === 4 || version === 6, 'Bad IP version.'); if (Buffer.isBuffer(ip)) {
assert(ip.length === 16);
if (type === 0) { return ip;
if (!Buffer.isBuffer(ip))
ip = new Buffer([0, 0, 0, 0]);
} else if (type === 4) {
parts = ip.split('.');
ip = new Buffer(4);
ip[0] = +parts[0];
ip[1] = +parts[1];
ip[2] = +parts[2];
ip[3] = +parts[3];
} else if (type === 6) {
ip = new Buffer(ip.replace(/:/g, ''), 'hex');
assert(ip.length <= 16);
} }
return utils.ip2version(ip, version); version = utils.isIP(ip);
if (version === 0)
return ip2array('0.0.0.0');
if (version === 4) {
parts = ip.split('.');
assert(parts.length === 4);
out = new Buffer(16);
out.fill(0);
out[10] = 0xff;
out[11] = 0xff;
out[12] = +parts[0];
out[13] = +parts[1];
out[14] = +parts[2];
out[15] = +parts[3];
return out;
}
if (version === 6) {
ip = new Buffer(ip.replace(/:/g, ''), 'hex');
assert(ip.length === 16);
return ip;
}
assert(false, 'Bad IP.');
}; };
/** /**
* Convert a buffer to an ip string. * Convert a buffer to an ip string.
* @param {Buffer} ip * @param {Buffer} ip
* @param {Number} version - 4 or 6.
* @returns {String} * @returns {String}
*/ */
utils.array2ip = function array2ip(ip, version) { utils.array2ip = function array2ip(ip) {
var out, i, hi, lo; var i, out, hi, lo;
if (!Buffer.isBuffer(ip)) { if (typeof ip === 'string') {
if (utils.isIP(ip)) assert(utils.isIP(ip) !== 0);
ip = utils.ip2array(ip, version); return ip;
else
ip = new Buffer([0, 0, 0, 0]);
} }
assert(version === 4 || version === 6, 'Bad IP version.'); if (!Buffer.isBuffer(ip))
assert(ip.length <= 16); return '0.0.0.0';
ip = utils.ip2version(ip, version); assert(ip.length === 16);
if (version === 4) if (utils.isMapped(ip))
return ip[0] + '.' + ip[1] + '.' + ip[2] + '.' + ip[3]; return ip[12] + '.' + ip[13] + '.' + ip[14] + '.' + ip[15];
if (version === 6) { out = [];
out = [];
for (i = 0; i < ip.length; i += 2) { for (i = 0; i < ip.length; i += 2) {
hi = ip[i].toString(16); hi = ip[i].toString(16);
if (hi.length < 2) if (hi.length < 2)
hi = '0' + hi; hi = '0' + hi;
lo = ip[i + 1].toString(16); lo = ip[i + 1].toString(16);
if (lo.length < 2) if (lo.length < 2)
lo = '0' + lo; lo = '0' + lo;
out.push(hi + lo); out.push(hi + lo);
}
return out.join(':');
} }
return out.join(':');
}; };
/** /**