peer: implement response to getaddr.
Signed-off-by: Fedor Indutny <fedor@indutny.com>
This commit is contained in:
parent
d617edf3ab
commit
d0b14008d0
@ -1,5 +1,7 @@
|
||||
var inherits = require('inherits');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var net = require('net');
|
||||
var os = require('os');
|
||||
|
||||
var bcoin = require('../bcoin');
|
||||
var utils = bcoin.utils;
|
||||
@ -276,6 +278,8 @@ Peer.prototype._onPacket = function onPacket(packet) {
|
||||
return this._handlePing(payload);
|
||||
else if (cmd === 'pong')
|
||||
return this._handlePong(payload);
|
||||
else if (cmd === 'getaddr')
|
||||
return this._handleGetAddr();
|
||||
|
||||
if (cmd === 'merkleblock' || cmd === 'block') {
|
||||
payload = bcoin.block(payload, cmd);
|
||||
@ -334,6 +338,122 @@ Peer.prototype._handlePong = function handlePong() {
|
||||
// No-op for now
|
||||
};
|
||||
|
||||
Peer.prototype._handleGetAddr = function handleGetAddr() {
|
||||
var used = [];
|
||||
var own = this._getOwnIP();
|
||||
var peers = [].concat(
|
||||
this.pool.peers.pending,
|
||||
this.pool.peers.block,
|
||||
this.pool.peers.load
|
||||
).filter(Boolean);
|
||||
|
||||
// NOTE: For IPv6 BTC uses:
|
||||
// '0000:0000:0000:0000:0000:xxxx:xxxx:ffff'
|
||||
|
||||
peers = peers.map(function(peer) {
|
||||
if (!peer.socket || !peer.socket.remoteAddress) return;
|
||||
return {
|
||||
host: peer.socket.remoteAddress,
|
||||
port: peer.socket.remotePort || 8333
|
||||
};
|
||||
}).filter(function(peer) {
|
||||
if (~used.indexOf(peer.host)) return;
|
||||
used.push(peer.host);
|
||||
return !!peer.host && net.isIP(peer.host);
|
||||
}).map(function(peer) {
|
||||
var ip = peer.host;
|
||||
var ver = net.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,
|
||||
ver: ver
|
||||
};
|
||||
});
|
||||
|
||||
if (own) peers.push(own);
|
||||
|
||||
peers = 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;
|
||||
}
|
||||
}
|
||||
|
||||
peer.ipv4 = peer.ipv4.split('.').map(function(n) {
|
||||
return +n;
|
||||
});
|
||||
|
||||
peer.ipv6 = peer.ipv6.split(':').slice(5).map(function(n) {
|
||||
return parseInt(n, 16);
|
||||
});
|
||||
|
||||
peer.ipv4 = utils.readU32BE(peer.ipv4, 0);
|
||||
|
||||
peer.ipv6 = utils.readU32BE(peer.ipv6, 0)
|
||||
* 0x10000 + utils.readU16BE(peer.ipv6, 4);
|
||||
|
||||
return peer;
|
||||
}).filter(Boolean);
|
||||
|
||||
return this._write(this.framer.addr(peers));
|
||||
};
|
||||
|
||||
Peer.prototype._getOwnIP = function getOwnIP() {
|
||||
var interfaces = os.networkInterfaces()
|
||||
, eth
|
||||
, ipv4
|
||||
, ipv6
|
||||
, ip
|
||||
, p4
|
||||
, p6
|
||||
, l;
|
||||
|
||||
ip = {
|
||||
ipv4: '127.0.0.1',
|
||||
ipv6: '0000:0000:0000:0000:0000:0000:0000:ffff',
|
||||
port: 8333,
|
||||
ver: 0
|
||||
};
|
||||
|
||||
eth = (interfaces.eth0 && interfaces.eth0.length >= 2 && interfaces.eth0)
|
||||
|| (interfaces.wlan0 && interfaces.wlan0.length >= 2 && interfaces.wlan0)
|
||||
|| interfaces[Object.keys(interfaces).pop()]
|
||||
|| [{ address: '127.0.0.1' }, { address: '::1' }];
|
||||
|
||||
ipv4 = eth[0] ? eth[0].address : '127.0.0.1';
|
||||
ipv6 = eth[1] ? eth[1].address : '0000:0000:0000:0000:0000:0000:0000:ffff';
|
||||
|
||||
p4 = ipv4.split('.').map(function(n) { return +n; });
|
||||
p6 = ipv6.split(':').map(function(n) {
|
||||
return parseInt(n, 16);
|
||||
}).reduce(function(out, n) {
|
||||
out.push((n >> 8) & 0xff);
|
||||
out.push(n & 0xff);
|
||||
return out;
|
||||
}, []);
|
||||
l = p6.length;
|
||||
|
||||
// Try to figure out if we're behind a NAT or not public for some reason.
|
||||
if ((p4[0] !== 127 && p4[1] !== 0 && p4[2] !== 0)
|
||||
&& (p4[0] !== 10 && p4[1] !== 0)
|
||||
&& (p4[0] !== 168 && p4[1] !== 0)) {
|
||||
ip.ipv4 = ipv4;
|
||||
ip.ver = 4;
|
||||
} else if ((p6[0] !== 0 && p6[1] !== 0 && p6[2] !== 1)
|
||||
&& (p6[l-1] !== 0xff && p6[l-2] !== 0xff && p6[l-3] !== 0xff)) {
|
||||
ip.ipv6 = ipv6;
|
||||
ip.ver = 6;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ip;
|
||||
};
|
||||
|
||||
Peer.prototype._handleInv = function handleInv(items) {
|
||||
// Always request advertised TXs
|
||||
var txs = items.filter(function(item) {
|
||||
|
||||
@ -319,3 +319,48 @@ Framer.prototype.merkleBlock = function merkleBlock(block) {
|
||||
// merkleblock here if we have them, as per the offical bitcoin client.
|
||||
return this.packet(Framer.block(block, 'merkleblock'));
|
||||
};
|
||||
|
||||
Framer.prototype.addr = function addr(peers) {
|
||||
var p = [];
|
||||
var i = 0;
|
||||
var c = 0;
|
||||
var peer;
|
||||
|
||||
// count
|
||||
if (peers.length < 0xfd) {
|
||||
p[c++] = peers.length;
|
||||
} else if (peers.length <= 0xffff) {
|
||||
p[c++] = 0xfd;
|
||||
c += utils.writeU16(p, peers.length, c);
|
||||
} else if (peers.length <= 0xffffffff) {
|
||||
p[c++] = 0xfe;
|
||||
c += utils.writeU32(p, peers.length, c);
|
||||
} else if (peers.length <= 0xffffffffffffffff) {
|
||||
p[c++] = 0xff;
|
||||
c += utils.writeU64(p, peers.length, c);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
for (; i < peers.length; i++) {
|
||||
peer = peers[i];
|
||||
|
||||
// date
|
||||
c += utils.writeU32(p, Date.now() / 1000 | 0, c);
|
||||
|
||||
// NODE_NETWORK service
|
||||
c += utils.writeU64(p, 1, c);
|
||||
|
||||
// ipv6
|
||||
c += utils.writeU32BE(p, utils.readU32BE(peer.ipv6, 0), c);
|
||||
c += utils.writeU16BE(p, utils.readU16BE(peer.ipv6, 4), c);
|
||||
|
||||
// ipv4
|
||||
c += utils.writeU32BE(p, peer.ipv4, c);
|
||||
|
||||
// port
|
||||
c += utils.writeU16BE(peer.port, c);
|
||||
}
|
||||
|
||||
return this.packet('addr', p);
|
||||
};
|
||||
|
||||
@ -158,6 +158,14 @@ utils.readU64 = function readU64(arr, off) {
|
||||
return utils.readU32(arr, off) + utils.readU32(arr, off + 4) * 0x100000000;
|
||||
};
|
||||
|
||||
utils.writeU16 = function writeU16(dst, num, off) {
|
||||
if (!off)
|
||||
off = 0;
|
||||
dst[off] = num & 0xff;
|
||||
dst[off + 1] = (num >>> 8) & 0xff;
|
||||
return 2;
|
||||
};
|
||||
|
||||
utils.writeU32 = function writeU32(dst, num, off) {
|
||||
if (!off)
|
||||
off = 0;
|
||||
@ -168,6 +176,70 @@ utils.writeU32 = function writeU32(dst, num, off) {
|
||||
return 4;
|
||||
};
|
||||
|
||||
utils.writeU64 = function writeU64(dst, num, off) {
|
||||
if (!off)
|
||||
off = 0;
|
||||
|
||||
var n = new bn(num);
|
||||
var left = n.shrn(32);
|
||||
//var right = n.andln(0xffffffff);
|
||||
var right = ((n.words[1] & 0xff) << 24) | n.words[0];
|
||||
if (right < 0) right += 0x100000000;
|
||||
|
||||
dst[off] = right & 0xff;
|
||||
dst[off + 1] = (right >>> 8) & 0xff;
|
||||
dst[off + 2] = (right >>> 16) & 0xff;
|
||||
dst[off + 3] = (right >>> 24) & 0xff;
|
||||
|
||||
dst[off + 4] = left & 0xff;
|
||||
dst[off + 5] = (left >>> 8) & 0xff;
|
||||
dst[off + 6] = (left >>> 16) & 0xff;
|
||||
dst[off + 7] = (left >>> 24) & 0xff;
|
||||
|
||||
return 8;
|
||||
};
|
||||
|
||||
utils.writeU16BE = function writeU16BE(dst, num, off) {
|
||||
if (!off)
|
||||
off = 0;
|
||||
dst[off] = (num >>> 8) & 0xff;
|
||||
dst[off + 1] = num & 0xff;
|
||||
return 2;
|
||||
};
|
||||
|
||||
utils.writeU32BE = function writeU32BE(dst, num, off) {
|
||||
if (!off)
|
||||
off = 0;
|
||||
dst[off] = (num >>> 24) & 0xff;
|
||||
dst[off + 1] = (num >>> 16) & 0xff;
|
||||
dst[off + 2] = (num >>> 8) & 0xff;
|
||||
dst[off + 3] = num & 0xff;
|
||||
return 4;
|
||||
};
|
||||
|
||||
utils.writeU64BE = function writeU64BE(dst, num, off) {
|
||||
if (!off)
|
||||
off = 0;
|
||||
|
||||
var n = new bn(num);
|
||||
var left = n.shrn(32);
|
||||
//var right = n.andln(0xffffffff);
|
||||
var right = ((n.words[1] & 0xff) << 24) | n.words[0];
|
||||
if (right < 0) right += 0x100000000;
|
||||
|
||||
dst[off] = (left >>> 24) & 0xff;
|
||||
dst[off + 1] = (left >>> 16) & 0xff;
|
||||
dst[off + 2] = (left >>> 8) & 0xff;
|
||||
dst[off + 3] = left & 0xff;
|
||||
|
||||
dst[off + 4] = (right >>> 24) & 0xff;
|
||||
dst[off + 5] = (right >>> 16) & 0xff;
|
||||
dst[off + 6] = (right >>> 8) & 0xff;
|
||||
dst[off + 7] = right & 0xff;
|
||||
|
||||
return 8;
|
||||
};
|
||||
|
||||
utils.readU16BE = function readU16BE(arr, off) {
|
||||
if (!off)
|
||||
off = 0;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user