version and addr packets.
This commit is contained in:
parent
a71da261ad
commit
10bd983899
@ -139,7 +139,7 @@ Peer.prototype._init = function init() {
|
||||
}
|
||||
|
||||
this._ping.timer = setInterval(function() {
|
||||
self.challenge = self._nonce();
|
||||
self.challenge = utils.nonce();
|
||||
self._write(self.framer.ping({
|
||||
nonce: self.challenge
|
||||
}));
|
||||
@ -430,7 +430,7 @@ Peer.prototype._handleAddr = function handleAddr(addrs) {
|
||||
this.emit('addr', {
|
||||
date: new Date(addr.ts * 1000),
|
||||
ts: addr.ts,
|
||||
service: addr.service,
|
||||
services: addr.services,
|
||||
ipv4: addr.ipv4,
|
||||
ipv6: addr.ipv6,
|
||||
host: addr.ipv4,
|
||||
@ -462,55 +462,44 @@ Peer.prototype._handlePong = function handlePong(data) {
|
||||
};
|
||||
|
||||
Peer.prototype._handleGetAddr = function handleGetAddr() {
|
||||
var used = [];
|
||||
var peers, addrs;
|
||||
|
||||
// NOTE: For IPv6 BTC uses:
|
||||
// '0000:0000:0000:0000:0000:xxxx:xxxx:ffff'
|
||||
var hosts = {};
|
||||
var peers;
|
||||
|
||||
peers = this.pool.peers.all.map(function(peer) {
|
||||
var ip, version, ipv4, ipv6;
|
||||
|
||||
if (!peer.socket || !peer.socket.remoteAddress)
|
||||
return;
|
||||
return {
|
||||
host: peer.socket.remoteAddress,
|
||||
port: peer.socket.remotePort || network.port,
|
||||
ts: peer.ts
|
||||
};
|
||||
}).filter(function(peer) {
|
||||
if (!peer || ~used.indexOf(peer.host))
|
||||
return;
|
||||
used.push(peer.host);
|
||||
return !!peer.host && utils.isIP(peer.host);
|
||||
}).map(function(peer) {
|
||||
var ip = peer.host;
|
||||
var ver = utils.isIP(ip);
|
||||
return {
|
||||
ipv4: ver === 4 ? ip : '127.0.0.1',
|
||||
ipv6: ver === 6 ? ip : '0000:0000:0000:0000:0000:0000:0000:ffff',
|
||||
port: peer.port,
|
||||
ts: peer.ts,
|
||||
ver: ver
|
||||
};
|
||||
});
|
||||
|
||||
addrs = peers.map(function(peer) {
|
||||
if (peer.ver === 6) {
|
||||
while (peer.ipv6.split(':').length < 8)
|
||||
peer.ipv6 = '0000:' + peer.ipv6;
|
||||
if (peer.ipv6.split(':').length > 8)
|
||||
return;
|
||||
ip = peer.socket.remoteAddress;
|
||||
version = utils.isIP(ip);
|
||||
|
||||
if (!version)
|
||||
return;
|
||||
|
||||
if (hosts[ip])
|
||||
return;
|
||||
|
||||
hosts[ip] = true;
|
||||
|
||||
if (version === 4) {
|
||||
ipv4 = utils.ip2array(ip, 4);
|
||||
ipv6 = utils.ip2array(ipv4, 6);
|
||||
} else if (version === 6) {
|
||||
ipv6 = utils.ip2array(ip, 6);
|
||||
ipv4 = utils.ip2array(ipv6, 4);
|
||||
}
|
||||
|
||||
peer.ipv4 = peer.ipv4.split('.').map(function(n) {
|
||||
return +n;
|
||||
});
|
||||
|
||||
peer.ipv6 = utils.toArray(peer.ipv6, 'hex');
|
||||
|
||||
return peer;
|
||||
return {
|
||||
ts: peer.ts,
|
||||
services: peer.version ? peer.version.services : null,
|
||||
ipv4: ipv4,
|
||||
ipv6: ipv6,
|
||||
port: peer.socket.remotePort || network.port
|
||||
};
|
||||
}).filter(Boolean);
|
||||
|
||||
return this._write(this.framer.addr(addrs));
|
||||
return this._write(this.framer.addr(peers));
|
||||
};
|
||||
|
||||
Peer.prototype._handleInv = function handleInv(items) {
|
||||
@ -598,14 +587,6 @@ Peer.prototype.reject = function reject(details) {
|
||||
this._write(this.framer.reject(details));
|
||||
};
|
||||
|
||||
Peer.nonce = new bn(0xffffffff).ushln(32).uor(new bn(0xffffffff));
|
||||
|
||||
Peer.prototype._nonce = function _nonce() {
|
||||
var nonce = Peer.nonce.clone();
|
||||
nonce.imuln(Math.random());
|
||||
return nonce;
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
@ -58,22 +58,58 @@ Framer.prototype.packet = function packet(cmd, payload) {
|
||||
return h.concat(payload);
|
||||
};
|
||||
|
||||
Framer.prototype._addr = function addr(buf, off) {
|
||||
writeU32(buf, 1, off);
|
||||
writeU32(buf, 0, off + 4);
|
||||
writeU32(buf, 0, off + 8);
|
||||
writeU32(buf, 0, off + 12);
|
||||
writeU32(buf, 0xffff0000, off + 16);
|
||||
writeU32(buf, 0, off + 20);
|
||||
buf[off + 24] = 0;
|
||||
buf[off + 25] = 0;
|
||||
return 26;
|
||||
Framer.prototype._addr = function addr(p, off, data, full) {
|
||||
var start = off;
|
||||
|
||||
if (!data)
|
||||
data = {};
|
||||
|
||||
if (!data.ts)
|
||||
data.ts = utils.now() - (process.uptime() | 0);
|
||||
|
||||
if (!data.services)
|
||||
data.services = constants.services.network;
|
||||
|
||||
if (!data.ipv4)
|
||||
data.ipv4 = [];
|
||||
|
||||
if (!data.ipv6)
|
||||
data.ipv6 = [];
|
||||
|
||||
if (!data.port)
|
||||
data.port = network.port;
|
||||
|
||||
// timestamp
|
||||
if (full)
|
||||
off += utils.writeU32(p, data.ts, off);
|
||||
|
||||
// NODE_NETWORK services
|
||||
off += utils.writeU64(p, data.services, off);
|
||||
|
||||
// Empty bytes after services
|
||||
// (services takes the place of ts)
|
||||
if (!full)
|
||||
off += utils.writeU32(p, 0, off);
|
||||
|
||||
// ipv6
|
||||
off += utils.writeU32BE(p, utils.readU32BE(data.ipv6, 0), off);
|
||||
off += utils.writeU32BE(p, utils.readU32BE(data.ipv6, 4), off);
|
||||
off += utils.writeU32BE(p, utils.readU32BE(data.ipv6, 8), off);
|
||||
|
||||
// ipv4
|
||||
if (full)
|
||||
off += utils.writeU32BE(p, utils.readU32BE(data.ipv4, 0), off);
|
||||
|
||||
// port
|
||||
off += utils.writeU16BE(p, data.port, off);
|
||||
|
||||
return off - start;
|
||||
};
|
||||
|
||||
Framer.prototype.version = function version(packet) {
|
||||
var p = new Array(86 + this.agent.length);
|
||||
var off = 0;
|
||||
var ts, i;
|
||||
var i;
|
||||
|
||||
if (!packet)
|
||||
packet = {};
|
||||
@ -82,21 +118,19 @@ Framer.prototype.version = function version(packet) {
|
||||
off += writeU32(p, constants.version, off);
|
||||
|
||||
// Services
|
||||
off += writeU32(p, constants.services.network, off);
|
||||
off += writeU32(p, 0, off);
|
||||
off += utils.writeU64(p, constants.services.network, off);
|
||||
|
||||
// Timestamp
|
||||
ts = utils.now();
|
||||
off += writeU32(p, ts, off);
|
||||
off += writeU32(p, 0, off);
|
||||
off += utils.write64(p, utils.now(), off);
|
||||
|
||||
// Remote and local addresses
|
||||
off += this._addr(p, off);
|
||||
off += this._addr(p, off);
|
||||
// Their address (recv)
|
||||
off += this._addr(p, off, packet.remote || {});
|
||||
|
||||
// Our address (from)
|
||||
off += this._addr(p, off, packet.local || {});
|
||||
|
||||
// Nonce, very dramatic
|
||||
off += writeU32(p, (Math.random() * 0xffffffff) | 0, off);
|
||||
off += writeU32(p, (Math.random() * 0xffffffff) | 0, off);
|
||||
off += utils.writeU64(p, utils.nonce(), off);
|
||||
|
||||
// User-agent
|
||||
assert.equal(off, 80);
|
||||
@ -390,31 +424,20 @@ Framer.prototype.reject = function reject(details) {
|
||||
Framer.prototype.addr = function addr(peers) {
|
||||
var p = [];
|
||||
var off = 0;
|
||||
var start = utils.now() - (process.uptime() | 0);
|
||||
var i, peer;
|
||||
|
||||
// count
|
||||
off += utils.writeIntv(p, peers.length, off);
|
||||
|
||||
for (i = 0; i < peers.length; i++) {
|
||||
peer = peers[i];
|
||||
|
||||
// timestamp
|
||||
off += utils.writeU32(p, peer.ts || start, off);
|
||||
|
||||
// NODE_NETWORK service
|
||||
off += utils.writeU64(p, 1, off);
|
||||
|
||||
// ipv6
|
||||
off += utils.writeU32BE(p, utils.readU32BE(peer.ipv6, 4), off);
|
||||
off += utils.writeU32BE(p, utils.readU32BE(peer.ipv6, 8), off);
|
||||
off += utils.writeU32BE(p, utils.readU32BE(peer.ipv6, 12), off);
|
||||
|
||||
// ipv4
|
||||
off += utils.writeU32BE(p, utils.readU32BE(peer.ipv4, 0), off);
|
||||
|
||||
// port
|
||||
off += utils.writeU16BE(p, peer.port, off);
|
||||
off += this._addr(p, off, {
|
||||
ts: peer.ts,
|
||||
services: 1,
|
||||
ipv6: peer.ipv6,
|
||||
ipv4: peer.ipv4,
|
||||
port: peer.port
|
||||
}, true);
|
||||
}
|
||||
|
||||
return this.packet('addr', p);
|
||||
|
||||
@ -167,7 +167,7 @@ Parser.prototype.parsePong = function parsePong(p) {
|
||||
};
|
||||
|
||||
Parser.prototype.parseVersion = function parseVersion(p) {
|
||||
var v, services, ts, nonce, result, off, agent, height, relay;
|
||||
var v, services, ts, recv, from, nonce, result, off, agent, height, relay;
|
||||
|
||||
if (p.length < 85)
|
||||
return this._error('version packet is too small');
|
||||
@ -178,6 +178,12 @@ Parser.prototype.parseVersion = function parseVersion(p) {
|
||||
// Timestamp
|
||||
ts = utils.read64(p, 12);
|
||||
|
||||
// Our address (recv)
|
||||
recv = this._parseAddr(p, 20);
|
||||
|
||||
// Their Address (from)
|
||||
from = this._parseAddr(p, 46);
|
||||
|
||||
// Nonce, very dramatic
|
||||
nonce = readU64(p, 72);
|
||||
|
||||
@ -194,10 +200,24 @@ Parser.prototype.parseVersion = function parseVersion(p) {
|
||||
// Relay
|
||||
relay = p.length > off ? p[off] === 1 : true;
|
||||
|
||||
try {
|
||||
ts = ts.toNumber();
|
||||
} catch (e) {
|
||||
ts = 0;
|
||||
}
|
||||
|
||||
try {
|
||||
services = services.toNumber();
|
||||
} catch (e) {
|
||||
services = 1;
|
||||
}
|
||||
|
||||
return {
|
||||
v: v,
|
||||
services: services,
|
||||
ts: ts,
|
||||
local: recv,
|
||||
remote: from,
|
||||
nonce: nonce,
|
||||
agent: utils.stringify(agent),
|
||||
height: height,
|
||||
@ -490,50 +510,72 @@ Parser.prototype.parseReject = function parseReject(p) {
|
||||
};
|
||||
};
|
||||
|
||||
Parser.prototype._parseAddr = function _parseAddr(p, off, full) {
|
||||
var ts, services, ip, ipv6, ipv4, port;
|
||||
|
||||
if (!off)
|
||||
off = 0;
|
||||
|
||||
// timestamp - LE
|
||||
if (full) {
|
||||
ts = utils.readU32(p, off);
|
||||
off += 4;
|
||||
} else {
|
||||
ts = 0;
|
||||
}
|
||||
|
||||
// NODE_NETWORK services - LE
|
||||
services = utils.readU64(p, off);
|
||||
off += 8;
|
||||
|
||||
// Empty bytes after services
|
||||
// (services takes the place of ts)
|
||||
if (!full)
|
||||
off += 4;
|
||||
|
||||
// ipv6 - BE
|
||||
ipv6 = utils.toArray(p.slice(off, off + 12));
|
||||
off += 12;
|
||||
|
||||
// ipv4 - BE
|
||||
if (full) {
|
||||
ipv4 = utils.toArray(p.slice(off, off + 4));
|
||||
off += 4;
|
||||
}
|
||||
|
||||
// port - BE
|
||||
port = utils.readU16BE(p, off);
|
||||
off += 2;
|
||||
|
||||
try {
|
||||
services = services.toNumber();
|
||||
} catch (e) {
|
||||
services = 1;
|
||||
}
|
||||
|
||||
return {
|
||||
ts: ts,
|
||||
services: services,
|
||||
ipv6: utils.array2ip(ipv6, 6),
|
||||
ipv4: utils.array2ip(ipv4 || ipv6, 4),
|
||||
port: port
|
||||
};
|
||||
};
|
||||
|
||||
Parser.prototype.parseAddr = function parseAddr(p) {
|
||||
if (p.length < 31)
|
||||
return this._error('Invalid addr size');
|
||||
|
||||
var addrs = [];
|
||||
var i, len, off, count, ts, service, ipv6, ipv4, port;
|
||||
var i, off, count;
|
||||
|
||||
// count
|
||||
len = utils.readIntv(p, 0);
|
||||
off = len.off;
|
||||
count = len.r;
|
||||
count = utils.readIntv(p, 0);
|
||||
off = count.off;
|
||||
count = count.r;
|
||||
|
||||
p = p.slice(off);
|
||||
|
||||
for (i = 0; i < count && p.length; i++) {
|
||||
// timestamp - LE
|
||||
ts = utils.readU32(p, 0);
|
||||
|
||||
// NODE_NETWORK service - LE
|
||||
service = utils.readU64(p, 4);
|
||||
|
||||
// ipv6 - BE
|
||||
ipv6 = utils.toHex(p.slice(12, 24));
|
||||
ipv6 = '::' + ipv6.replace(/(.{4})/g, '$1:').slice(0, -1);
|
||||
|
||||
// ipv4 - BE
|
||||
ipv4 = utils.readU32BE(p, 24);
|
||||
ipv4 = ((ipv4 >> 24) & 0xff)
|
||||
+ '.' + ((ipv4 >> 16) & 0xff)
|
||||
+ '.' + ((ipv4 >> 8) & 0xff)
|
||||
+ '.' + ((ipv4 >> 0) & 0xff);
|
||||
|
||||
// port - BE
|
||||
port = utils.readU16BE(p, 28);
|
||||
|
||||
addrs.push({
|
||||
ts: ts,
|
||||
service: service,
|
||||
ipv6: ipv6,
|
||||
ipv4: ipv4,
|
||||
port: port
|
||||
});
|
||||
|
||||
p = p.slice(30);
|
||||
for (i = 0; i < count && off < p.length; i++) {
|
||||
addrs.push(this._parseAddr(p, off, true));
|
||||
off += 30;
|
||||
}
|
||||
|
||||
return addrs;
|
||||
|
||||
@ -532,15 +532,97 @@ utils.isIP = function isIP(ip) {
|
||||
if (typeof ip !== 'string')
|
||||
return 0;
|
||||
|
||||
if (ip.indexOf('.') !== -1)
|
||||
if (/^\d+\.\d+\.\d+\.\d+$/.test(ip))
|
||||
return 4;
|
||||
|
||||
if (ip.indexOf(':') !== -1)
|
||||
if (/:[0-9a-f]{1,4}/i.test(ip))
|
||||
return 6;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
utils.ip2array = function ip2array(ip, version) {
|
||||
if (Array.isArray(ip)) {
|
||||
ip = ip.slice();
|
||||
|
||||
utils.assert(version === 4 || version === 6);
|
||||
|
||||
if (version === 4) {
|
||||
ip = ip.slice(-4);
|
||||
|
||||
while (ip.length < 4)
|
||||
ip.unshift(0);
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
if (version === 6) {
|
||||
while (ip.length < 4)
|
||||
ip.unshift(0);
|
||||
|
||||
while (ip.length < 6)
|
||||
ip.unshift(0xff);
|
||||
|
||||
while (ip.length < 16)
|
||||
ip.unshift(0);
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
version = utils.isIP(ip);
|
||||
|
||||
if (!version)
|
||||
return ip;
|
||||
|
||||
if (version === 4) {
|
||||
ip = ip.split('.').map(function(n) {
|
||||
return +n;
|
||||
});
|
||||
utils.assert(ip.length <= 4);
|
||||
return utils.ip2array(ip, 4);
|
||||
}
|
||||
|
||||
if (version === 6) {
|
||||
ip = utils.toArray(ip.replace(/:/g, ''), 'hex');
|
||||
utils.assert(ip.length <= 16);
|
||||
return utils.ip2array(ip, 6);
|
||||
}
|
||||
};
|
||||
|
||||
utils.array2ip = function array2ip(ip, version) {
|
||||
var out, i, hi, lo;
|
||||
|
||||
if (!Array.isArray(ip))
|
||||
return ip;
|
||||
|
||||
utils.assert(version === 4 || version === 6);
|
||||
utils.assert(ip.length <= 16);
|
||||
|
||||
ip = utils.ip2array(ip, version);
|
||||
|
||||
if (version === 4)
|
||||
return ip.join('.');
|
||||
|
||||
if (version === 6) {
|
||||
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(':');
|
||||
}
|
||||
};
|
||||
|
||||
utils.isArrayLike = function isArrayLike(msg) {
|
||||
return msg
|
||||
&& !Array.isArray(msg)
|
||||
@ -737,6 +819,14 @@ utils.hash = function hash(obj, enc) {
|
||||
throw new Error('Cannot get hash of object');
|
||||
};
|
||||
|
||||
utils.U64 = new bn(0xffffffff).ushln(32).uor(new bn(0xffffffff));
|
||||
|
||||
utils.nonce = function nonce() {
|
||||
var nonce = utils.U64.clone();
|
||||
nonce.imuln(Math.random());
|
||||
return nonce;
|
||||
};
|
||||
|
||||
//
|
||||
// Integer Functions
|
||||
//
|
||||
@ -1011,7 +1101,7 @@ utils.write32BE = function write32BE(dst, num, off) {
|
||||
};
|
||||
|
||||
utils.write64 = function write64(dst, num, off) {
|
||||
var i;
|
||||
var i, bytes;
|
||||
|
||||
if (!(num instanceof bn)) {
|
||||
num = +num;
|
||||
@ -1026,22 +1116,22 @@ utils.write64 = function write64(dst, num, off) {
|
||||
|
||||
off = off >>> 0;
|
||||
|
||||
num = num.maskn(64).toArray();
|
||||
bytes = num.maskn(64).toArray();
|
||||
|
||||
while (num.length < 8)
|
||||
num.unshift(0);
|
||||
while (bytes.length < 8)
|
||||
bytes.unshift(0);
|
||||
|
||||
if (num.isNeg())
|
||||
num[0] |= 0x80;
|
||||
bytes[0] |= 0x80;
|
||||
|
||||
for (i = num.length - 1; i >= 0; i--)
|
||||
dst[off++] = num[i] & 0xff;
|
||||
for (i = bytes.length - 1; i >= 0; i--)
|
||||
dst[off++] = bytes[i] & 0xff;
|
||||
|
||||
return 8;
|
||||
};
|
||||
|
||||
utils.write64BE = function write64BE(dst, num, off) {
|
||||
var i;
|
||||
var i, bytes;
|
||||
|
||||
if (!(num instanceof bn)) {
|
||||
num = +num;
|
||||
@ -1056,16 +1146,16 @@ utils.write64BE = function write64BE(dst, num, off) {
|
||||
|
||||
off = off >>> 0;
|
||||
|
||||
num = num.maskn(64).toArray();
|
||||
bytes = num.maskn(64).toArray();
|
||||
|
||||
while (num.length < 8)
|
||||
num.unshift(0);
|
||||
while (bytes.length < 8)
|
||||
bytes.unshift(0);
|
||||
|
||||
if (num.isNeg())
|
||||
num[0] |= 0x80;
|
||||
bytes[0] |= 0x80;
|
||||
|
||||
for (i = 0; i < num.length; i++)
|
||||
dst[off++] = num[i] & 0xff;
|
||||
for (i = 0; i < bytes.length; i++)
|
||||
dst[off++] = bytes[i] & 0xff;
|
||||
|
||||
return 8;
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user