net: tor support for outgoing conns.

This commit is contained in:
Christopher Jeffrey 2017-01-24 18:25:44 -08:00
parent 5288e8a619
commit 5073c1508f
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
14 changed files with 87 additions and 53 deletions

View File

@ -162,7 +162,7 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce
return;
}
if (!IP.isRoutable(raw) || IP.isTor(raw)) {
if (!IP.isRoutable(raw) || IP.isOnion(raw)) {
this.log(
'Client is trying to connect to a bad ip: %s (%s).',
host, state.host);

View File

@ -59,8 +59,9 @@ listen: true
max-outbound: 8
max-inbound: 30
# Websocket Proxy Server (Browser Only)
proxy-server: localhost
# Proxy Server (browser=websockets, node=socks)
# proxy: foo:bar@127.0.0.1:9050
# onion: true
# Custom list of DNS seeds
# seeds: seed.bitcoin.sipa.be

View File

@ -468,7 +468,6 @@ function AuthDB(options) {
this.logger = null;
this.resolve = dns.resolve;
this.proxyServer = null;
this.dnsKnown = [];
this.known = {};
@ -496,11 +495,6 @@ AuthDB.prototype._init = function _init(options) {
this.resolve = options.resolve;
}
if (options.proxyServer != null) {
assert(typeof options.proxyServer === 'string');
this.proxyServer = options.proxyServer;
}
if (options.knownPeers != null) {
assert(typeof options.knownPeers === 'object');
this.setKnown(options.knownPeers);
@ -638,7 +632,7 @@ AuthDB.prototype.populate = co(function* populate(addr, key) {
this.logger.info('Resolving authorized hosts from: %s.', addr.host);
try {
hosts = yield this.resolve(addr.host, this.proxyServer);
hosts = yield this.resolve(addr.host);
} catch (e) {
if (this.logger)
this.logger.error(e);

View File

@ -9,7 +9,7 @@
var ProxySocket = require('./proxysocket');
var socket;
exports.resolve = function resolve(host, proxy) {
exports.resolve = function resolve(host, proxy, onion) {
return new Promise(function(resolve, reject) {
if (!socket)
socket = new ProxySocket(proxy);
@ -30,6 +30,6 @@ exports.resolve = function resolve(host, proxy) {
});
};
exports.lookup = function lookup(host, proxy) {
return exports.resolve(host, proxy);
exports.lookup = function lookup(host, proxy, onion) {
return exports.resolve(host, proxy, onion);
};

View File

@ -7,6 +7,7 @@
'use strict';
var dns = require('dns');
var socks = require('./socks');
var options = {
family: 4,
@ -14,7 +15,10 @@ var options = {
all: true
};
exports.resolve = function resolve(host, proxy) {
exports.resolve = function resolve(host, proxy, onion) {
if (proxy && onion)
return socks.resolve(host, proxy);
return new Promise(function(resolve, reject) {
dns.resolve(host, 'A', function(err, result) {
if (err) {
@ -32,7 +36,10 @@ exports.resolve = function resolve(host, proxy) {
});
};
exports.lookup = function lookup(host, proxy) {
exports.lookup = function lookup(host, proxy, onion) {
if (proxy && onion)
return socks.resolve(host, proxy);
return new Promise(function(resolve, reject) {
var addrs = [];
var i, addr;

View File

@ -32,7 +32,6 @@ function HostList(options) {
this.network = Network.primary;
this.logger = null;
this.address = new NetAddress();
this.proxyServer = null;
this.resolve = dns.resolve;
this.banTime = common.BAN_TIME;
@ -89,11 +88,6 @@ HostList.prototype._initOptions = function initOptions(options) {
this.address = options.address;
}
if (options.proxyServer != null) {
assert(typeof options.proxyServer === 'string');
this.proxyServer = options.proxyServer;
}
if (options.resolve != null) {
assert(typeof options.resolve === 'function');
this.resolve = options.resolve;
@ -804,7 +798,7 @@ HostList.prototype.populate = co(function* populate(target) {
this.logger.info('Resolving host: %s.', target.host);
try {
hosts = yield this.resolve(target.host, this.proxyServer);
hosts = yield this.resolve(target.host);
} catch (e) {
if (this.logger)
this.logger.error(e);

View File

@ -417,12 +417,11 @@ Peer.prototype.accept = function accept(socket) {
*/
Peer.prototype.connect = function connect(addr) {
var proxy = this.options.proxyServer;
var socket;
assert(!this.socket);
socket = this.options.createSocket(addr.port, addr.host, proxy);
socket = this.options.createSocket(addr.port, addr.host);
this.address = addr;
this.ts = util.now();
@ -2156,7 +2155,6 @@ function PeerOptions(options) {
this.network = Network.primary;
this.logger = Logger.global;
this.proxyServer = null;
this.createSocket = tcp.createSocket;
this.version = common.PROTOCOL_VERSION;
this.services = common.LOCAL_SERVICES;
@ -2197,11 +2195,6 @@ PeerOptions.prototype.fromOptions = function fromOptions(options) {
this.logger = options.logger;
}
if (options.proxyServer != null) {
assert(typeof options.proxyServer === 'string');
this.proxyServer = options.proxyServer;
}
if (options.createSocket != null) {
assert(typeof options.createSocket === 'function');
this.createSocket = options.createSocket;

View File

@ -291,7 +291,7 @@ Pool.prototype._connect = co(function* connect() {
yield this.listen();
if (this.address.isNull()) {
if (this.address.isNull() && !this.options.proxy) {
try {
ip = yield this.getIP();
} catch (e) {
@ -1291,6 +1291,9 @@ Pool.prototype.handleAddr = co(function* handleAddr(peer, packet) {
if (!addr.hasServices(services))
continue;
if (!this.options.onion && addr.isOnion())
continue;
if (addr.ts <= 100000000 || addr.ts > now + 10 * 60)
addr.ts = now - 5 * 24 * 60 * 60;
@ -2653,6 +2656,9 @@ Pool.prototype.getHost = function getHost() {
if (!addr.hasServices(services))
continue;
if (!this.options.onion && addr.isOnion())
continue;
if (i < 30 && now - entry.lastAttempt < 600)
continue;
@ -3222,10 +3228,11 @@ function PoolOptions(options) {
this.port = this.network.port;
this.maxOutbound = 8;
this.maxInbound = 8;
this.createSocket = tcp.createSocket;
this.createSocket = this._createSocket;
this.createServer = tcp.createServer;
this.resolve = dns.resolve;
this.proxyServer = null;
this.resolve = this._resolve;
this.proxy = null;
this.onion = false;
this.selfish = false;
this.version = common.PROTOCOL_VERSION;
this.agent = common.USER_AGENT;
@ -3362,9 +3369,14 @@ PoolOptions.prototype.fromOptions = function fromOptions(options) {
this.resolve = options.resolve;
}
if (options.proxyServer) {
assert(typeof options.proxyServer === 'string');
this.proxyServer = options.proxyServer;
if (options.proxy) {
assert(typeof options.proxy === 'string');
this.proxy = options.proxy;
}
if (options.onion) {
assert(typeof options.onion === 'boolean');
this.onion = options.onion;
}
if (options.selfish) {
@ -3454,6 +3466,7 @@ PoolOptions.prototype.fromOptions = function fromOptions(options) {
this.checkpoints = true;
this.compact = false;
this.bip37 = false;
this.listen = false;
}
if (this.selfish) {
@ -3464,6 +3477,9 @@ PoolOptions.prototype.fromOptions = function fromOptions(options) {
if (this.bip37)
this.services |= common.services.BLOOM;
if (this.proxy)
this.listen = false;
if (options.services != null) {
assert(util.isUInt32(options.services));
this.services = options.services;
@ -3576,6 +3592,29 @@ PoolOptions.prototype.getRate = function getRate(hash) {
return entry.getRate();
};
/**
* Default createSocket call.
* @private
* @param {Number} port
* @param {String} host
* @returns {net.Socket}
*/
PoolOptions.prototype._createSocket = function createSocket(port, host) {
return tcp.createSocket(port, host, this.proxy);
};
/**
* Default resolve call.
* @private
* @param {String} name
* @returns {String[]}
*/
PoolOptions.prototype._resolve = function resolve(name) {
return dns.resolve(name, this.proxy, this.onion);
};
/**
* Peer List
* @constructor

View File

@ -8,9 +8,12 @@
var EventEmitter = require('events').EventEmitter;
var net = require('net');
var socks = require('./socks');
var tcp = exports;
tcp.createSocket = function createSocket(port, host, proxy) {
if (proxy)
return socks.connect(proxy, port, host);
return net.connect(port, host);
};

View File

@ -192,7 +192,8 @@ config.parseData = function parseData(data, prefix, dirname) {
options.bip151 = bool(data.bip151);
options.bip150 = bool(data.bip150);
options.identityKey = key(data.identitykey);
options.proxyServer = str(data.proxyserver);
options.proxy = str(data.proxy);
options.onion = bool(data.onion);
options.seeds = list(data.seeds);
options.nodes = list(data.nodes);
options.maxOutbound = num(data.maxoutbound);

View File

@ -110,7 +110,8 @@ function FullNode(options) {
identityKey: this.options.identityKey,
maxOutbound: this.options.maxOutbound,
maxInbound: this.options.maxInbound,
proxyServer: this.options.proxyServer,
proxy: this.options.proxy,
onion: this.options.onion,
seeds: this.options.seeds,
nodes: this.options.nodes,
publicHost: this.options.publicHost,

View File

@ -60,7 +60,8 @@ function SPVNode(options) {
network: this.network,
logger: this.logger,
chain: this.chain,
proxyServer: this.options.proxyServer,
proxy: this.options.proxy,
onion: this.options.onion,
seeds: this.options.seeds,
nodes: this.options.nodes,
bip151: this.options.bip151,

View File

@ -164,8 +164,8 @@ NetAddress.prototype.isRoutable = function isRoutable() {
* @returns {Boolean}
*/
NetAddress.prototype.isTor = function isTor() {
return IP.isTor(this.raw);
NetAddress.prototype.isOnion = function isOnion() {
return IP.isOnion(this.raw);
};
/**

View File

@ -47,7 +47,7 @@ IP.types = {
DNS: -1,
IPV4: 4,
IPV6: 6,
TOR: 10
ONION: 10
};
/**
@ -178,8 +178,8 @@ IP.getStringType = function getStringType(str) {
if (IP.isV6String(str))
return IP.types.IPV6;
if (IP.isTorString(str))
return IP.types.TOR;
if (IP.isOnionString(str))
return IP.types.ONION;
return IP.types.DNS;
};
@ -226,7 +226,7 @@ IP.isV6String = function isV6String(str) {
* @returns {Boolean}
*/
IP.isTorString = function isTorString(str) {
IP.isOnionString = function isOnionString(str) {
assert(typeof str === 'string');
if (str.length < 7)
@ -278,7 +278,7 @@ IP.toBuffer = function toBuffer(str) {
return IP.parseV4(str, raw, 12);
}
if (IP.isTorString(str)) {
if (IP.isOnionString(str)) {
data = TOR_ONION;
data.copy(raw, 0);
data = base32.decode(str.slice(0, -6));
@ -420,7 +420,7 @@ IP.toString = function toString(raw) {
return host;
}
if (IP.isTor(raw)) {
if (IP.isOnion(raw)) {
host = base32.encode(raw.slice(6));
return host + '.onion';
}
@ -466,7 +466,7 @@ IP.isIPv4 = function isIPv4(raw) {
*/
IP.isIPv6 = function isIPv6(raw) {
return !IP.isMapped(raw) && !IP.isTor(raw);
return !IP.isMapped(raw) && !IP.isOnion(raw);
};
/**
@ -482,8 +482,8 @@ IP.getType = function getType(raw) {
if (IP.isIPv6(raw))
return IP.types.IPV6;
if (IP.isTor(raw))
return IP.types.TOR;
if (IP.isOnion(raw))
return IP.types.ONION;
assert(false, 'Unknown type.');
};
@ -727,7 +727,7 @@ IP.isRFC4843 = function isRFC4843(raw) {
* @returns {Boolean}
*/
IP.isTor = function isTor(raw) {
IP.isOnion = function isOnion(raw) {
return IP.hasPrefix(raw, TOR_ONION);
};
@ -815,7 +815,7 @@ IP.isRoutable = function isRoutable(raw) {
if (IP.isRFC5737(raw))
return false;
if (IP.isRFC4193(raw) && !IP.isTor(raw))
if (IP.isRFC4193(raw) && !IP.isOnion(raw))
return false;
if (IP.isRFC4843(raw))