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; return;
} }
if (!IP.isRoutable(raw) || IP.isTor(raw)) { if (!IP.isRoutable(raw) || IP.isOnion(raw)) {
this.log( this.log(
'Client is trying to connect to a bad ip: %s (%s).', 'Client is trying to connect to a bad ip: %s (%s).',
host, state.host); host, state.host);

View File

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

View File

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

View File

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

View File

@ -7,6 +7,7 @@
'use strict'; 'use strict';
var dns = require('dns'); var dns = require('dns');
var socks = require('./socks');
var options = { var options = {
family: 4, family: 4,
@ -14,7 +15,10 @@ var options = {
all: true 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) { return new Promise(function(resolve, reject) {
dns.resolve(host, 'A', function(err, result) { dns.resolve(host, 'A', function(err, result) {
if (err) { 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) { return new Promise(function(resolve, reject) {
var addrs = []; var addrs = [];
var i, addr; var i, addr;

View File

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

View File

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

View File

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

View File

@ -8,9 +8,12 @@
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var net = require('net'); var net = require('net');
var socks = require('./socks');
var tcp = exports; var tcp = exports;
tcp.createSocket = function createSocket(port, host, proxy) { tcp.createSocket = function createSocket(port, host, proxy) {
if (proxy)
return socks.connect(proxy, port, host);
return net.connect(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.bip151 = bool(data.bip151);
options.bip150 = bool(data.bip150); options.bip150 = bool(data.bip150);
options.identityKey = key(data.identitykey); 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.seeds = list(data.seeds);
options.nodes = list(data.nodes); options.nodes = list(data.nodes);
options.maxOutbound = num(data.maxoutbound); options.maxOutbound = num(data.maxoutbound);

View File

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

View File

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

View File

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

View File

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