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.
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,
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) {
var now = utils.now();
var i, addr, ts, host;
var i, addr, ts;
for (i = 0; i < addrs.length; i++) {
addr = addrs[i];
ts = addr.ts;
host = addr.ipv4 !== '0.0.0.0'
? addr.ipv4
: addr.ipv6;
if (ts <= 100000000 || ts > now + 10 * 60)
ts = now - 5 * 24 * 60 * 60;
this.addrFilter.add(host, 'ascii');
this.addrFilter.add(addr.host, 'ascii');
this.emit('addr', {
version: addr.version,
ts: ts,
services: addr.services,
host: host,
host: addr.host,
port: addr.port || this.network.port
});
}
@ -1375,7 +1394,7 @@ Peer.prototype._handleGetAddr = function handleGetAddr() {
var hosts = {};
var items = [];
var ts = utils.now() - (process.uptime() | 0);
var i, seed, version, peer;
var i, seed, peer;
if (this.pool.options.selfish)
return;
@ -1383,9 +1402,8 @@ Peer.prototype._handleGetAddr = function handleGetAddr() {
for (i = 0; i < this.pool.seeds.length; i++) {
seed = utils.parseHost(this.pool.seeds[i]);
seed = this.pool.getPeer(seed.host) || seed;
version = utils.isIP(seed.host);
if (!version)
if (!utils.isIP(seed.host))
continue;
if (hosts[seed.host])
@ -1397,11 +1415,9 @@ Peer.prototype._handleGetAddr = function handleGetAddr() {
continue;
items.push({
network: this.network,
ts: seed.ts || ts,
services: seed.version ? seed.version.services : null,
ipv4: version === 4 ? seed.host : null,
ipv6: version === 6 ? seed.host : null,
services: seed.version ? seed.version.services : 0,
host: seed.host,
port: seed.port || this.network.port
});

View File

@ -108,6 +108,8 @@ function Pool(options) {
this.seeds = [];
this.hosts = {};
this.setSeeds([]);
this.host = '0.0.0.0';
this.port = this.network.port;
this.server = null;
this.destroyed = false;
@ -194,20 +196,7 @@ function Pool(options) {
interval: options.invInterval || 3000
};
function done(err) {
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);
this._init();
}
utils.inherits(Pool, EventEmitter);
@ -316,6 +305,29 @@ Pool.prototype._init = function _init() {
self.emit('full');
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);
};
/**
* 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.
* @exports LoadRequest

View File

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

View File

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

View File

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

View File

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