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 inherits = require('inherits');
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
var net = require('net');
|
||||||
|
var os = require('os');
|
||||||
|
|
||||||
var bcoin = require('../bcoin');
|
var bcoin = require('../bcoin');
|
||||||
var utils = bcoin.utils;
|
var utils = bcoin.utils;
|
||||||
@ -276,6 +278,8 @@ Peer.prototype._onPacket = function onPacket(packet) {
|
|||||||
return this._handlePing(payload);
|
return this._handlePing(payload);
|
||||||
else if (cmd === 'pong')
|
else if (cmd === 'pong')
|
||||||
return this._handlePong(payload);
|
return this._handlePong(payload);
|
||||||
|
else if (cmd === 'getaddr')
|
||||||
|
return this._handleGetAddr();
|
||||||
|
|
||||||
if (cmd === 'merkleblock' || cmd === 'block') {
|
if (cmd === 'merkleblock' || cmd === 'block') {
|
||||||
payload = bcoin.block(payload, cmd);
|
payload = bcoin.block(payload, cmd);
|
||||||
@ -334,6 +338,122 @@ Peer.prototype._handlePong = function handlePong() {
|
|||||||
// No-op for now
|
// 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) {
|
Peer.prototype._handleInv = function handleInv(items) {
|
||||||
// Always request advertised TXs
|
// Always request advertised TXs
|
||||||
var txs = items.filter(function(item) {
|
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.
|
// merkleblock here if we have them, as per the offical bitcoin client.
|
||||||
return this.packet(Framer.block(block, 'merkleblock'));
|
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;
|
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) {
|
utils.writeU32 = function writeU32(dst, num, off) {
|
||||||
if (!off)
|
if (!off)
|
||||||
off = 0;
|
off = 0;
|
||||||
@ -168,6 +176,70 @@ utils.writeU32 = function writeU32(dst, num, off) {
|
|||||||
return 4;
|
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) {
|
utils.readU16BE = function readU16BE(arr, off) {
|
||||||
if (!off)
|
if (!off)
|
||||||
off = 0;
|
off = 0;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user