Connects to the Tor instance via the control port when the instance starts

This commit is contained in:
Zachary Boyd 2018-05-10 21:17:00 -07:00
parent b3700e0202
commit 4bc4c15dd7
4 changed files with 91 additions and 7 deletions

36
package-lock.json generated
View file

@ -770,6 +770,11 @@
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
}, },
"interpret": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
"integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ="
},
"invert-kv": { "invert-kv": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
@ -5825,6 +5830,11 @@
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
}, },
"path-parse": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
"integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME="
},
"performance-now": { "performance-now": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@ -5890,6 +5900,14 @@
"util-deprecate": "1.0.2" "util-deprecate": "1.0.2"
} }
}, },
"rechoir": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
"requires": {
"resolve": "1.7.1"
}
},
"request": { "request": {
"version": "2.85.0", "version": "2.85.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz",
@ -5930,6 +5948,14 @@
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
}, },
"resolve": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
"integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==",
"requires": {
"path-parse": "1.0.5"
}
},
"rimraf": { "rimraf": {
"version": "2.2.8", "version": "2.2.8",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
@ -5968,6 +5994,16 @@
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
}, },
"shelljs": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz",
"integrity": "sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ==",
"requires": {
"glob": "7.1.2",
"interpret": "1.1.0",
"rechoir": "0.6.2"
}
},
"signal-exit": { "signal-exit": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",

View file

@ -31,6 +31,7 @@
"nanoid": "^1.0.2", "nanoid": "^1.0.2",
"native-dns": "git+https://github.com/znetstar/node-dns.git", "native-dns": "git+https://github.com/znetstar/node-dns.git",
"nconf": "^0.10.0", "nconf": "^0.10.0",
"shelljs": "^0.8.2",
"socks-proxy-agent": "^3.0.1", "socks-proxy-agent": "^3.0.1",
"socksv5": "git+https://github.com/lee-elenbaas/socksv5.git", "socksv5": "git+https://github.com/lee-elenbaas/socksv5.git",
"temp": "^0.8.3", "temp": "^0.8.3",

View file

@ -6,15 +6,21 @@ const getPort = require('get-port');
const del = require('del'); const del = require('del');
const EventEmitter = require('eventemitter2').EventEmitter2; const EventEmitter = require('eventemitter2').EventEmitter2;
const temp = require('temp'); const temp = require('temp');
const { TorController } = require('granax');
const { connect } = require('net');
const shell = require('shelljs');
const crypto = require('crypto');
temp.track(); temp.track();
class TorProcess extends EventEmitter { class TorProcess extends EventEmitter {
constructor(tor_path, config, logger, nconf) { constructor(tor_path, config, logger, nconf, granax_options) {
super(); super();
this.tor_path = tor_path || nconf.get('torPath'); this.tor_path = tor_path || nconf.get('torPath');
this.nconf = nconf; this.nconf = nconf;
this.logger = logger; this.logger = logger;
this.granax_options = granax_options || nconf.get('granaxOptions');
this.control_password = crypto.randomBytes(128).toString('base64');
config.DataDirectory = config.DataDirectory || temp.mkdirSync(); config.DataDirectory = config.DataDirectory || temp.mkdirSync();
@ -45,14 +51,25 @@ class TorProcess extends EventEmitter {
return this._socks_port || null; return this._socks_port || null;
} }
get control_port() {
return this._control_port || null;
}
get controller() {
return this._controller;
}
create(callback) { create(callback) {
async.auto({ async.auto({
dnsPort: (callback) => getPort().then(port => callback(null, port)), dnsPort: (callback) => getPort().then(port => callback(null, port)),
socksPort: (callback) => getPort().then(port => callback(null, port)), socksPort: (callback) => getPort().then(port => callback(null, port)),
configPath: ['dnsPort', 'socksPort', (context, callback) => { controlPort: (callback) => getPort().then(port => callback(null, port)),
configPath: ['dnsPort', 'socksPort', 'controlPort', (context, callback) => {
let options = { let options = {
DNSPort: `127.0.0.1:${context.dnsPort}`, DNSPort: `127.0.0.1:${context.dnsPort}`,
SocksPort: `127.0.0.1:${context.socksPort}`, SocksPort: `127.0.0.1:${context.socksPort}`,
ControlPort: `127.0.0.1:${context.controlPort}`,
HashedControlPassword: shell.exec(`${this.tor_path} --hash-password "${this.control_password}"`, { async: false, silent: true }).stdout.trim()
}; };
let config = _.extend(_.extend({}, this.tor_config), options); let config = _.extend(_.extend({}, this.tor_config), options);
let text = Object.keys(config).map((key) => `${key} ${config[key]}`).join("\n"); let text = Object.keys(config).map((key) => `${key} ${config[key]}`).join("\n");
@ -70,13 +87,14 @@ class TorProcess extends EventEmitter {
this._dns_port = context.dnsPort; this._dns_port = context.dnsPort;
this._socks_port = context.socksPort; this._socks_port = context.socksPort;
this._control_port = context.controlPort;
let tor = spawn(this.tor_path, ['-f', context.configPath], { let tor = spawn(this.tor_path, ['-f', context.configPath], {
stdio: ['ignore', 'pipe', 'pipe'], stdio: ['ignore', 'pipe', 'pipe'],
detached: false, detached: false
shell: '/bin/bash'
}); });
tor.on('close', (code) => { tor.on('close', (code) => {
this.emit('process_exit', code); this.emit('process_exit', code);
if (this.definition && !this.definition.Name) { if (this.definition && !this.definition.Name) {
@ -95,6 +113,22 @@ class TorProcess extends EventEmitter {
this.logger && this.logger.info(`[tor-${this.instance_name}]: tor is ready`); this.logger && this.logger.info(`[tor-${this.instance_name}]: tor is ready`);
}); });
this.on('control_listen', () => {
this._controller = new TorController(connect(this._control_port), _.extend({ authOnConnect: false }, this.granax_options));
this.controller.on('ready', () => {
this.logger && this.logger.debug(`[tor-${this.instance_name}]: connected to tor control port`);
this.controller.authenticate(`"${this.control_password}"`, (err) => {
if (err) {
this.logger && this.logger.error(`[tor-${this.instance_name}]: ${err.stack}`);
this.emit('error', err);
} else {
this.logger && this.logger.debug(`[tor-${this.instance_name}]: authenticated with tor instance via the control port`);
this.emit('controller_ready');
}
});
});
});
tor.stdout.on('data', (data) => { tor.stdout.on('data', (data) => {
let text = Buffer.from(data).toString('utf8'); let text = Buffer.from(data).toString('utf8');
let msg = text.split('] ').pop(); let msg = text.split('] ').pop();
@ -102,17 +136,29 @@ class TorProcess extends EventEmitter {
this.emit('ready'); this.emit('ready');
} }
if (text.indexOf('Opening Control listener on') !== -1) {
this.emit('control_listen');
}
if (text.indexOf('Opening Socks listener on') !== -1) {
this.emit('socks_listen');
}
if (text.indexOf('Opening DNS listener on') !== -1) {
this.emit('dns_listen');
}
if (text.indexOf('[err]') !== -1) { if (text.indexOf('[err]') !== -1) {
this.emit('error', new Error(msg)); this.emit('error', new Error(msg));
this.logger && this.logger.error(`[tor-${tor.pid}]: ${msg}`); this.logger && this.logger.error(`[tor-${this.instance_name}]: ${msg}`);
} }
else if (text.indexOf('[notice]') !== -1) { else if (text.indexOf('[notice]') !== -1) {
this.logger && this.logger.debug(`[tor-${tor.pid}]: ${msg}`); this.logger && this.logger.debug(`[tor-${this.instance_name}]: ${msg}`);
} }
else if (text.indexOf('[warn]') !== -1) { else if (text.indexOf('[warn]') !== -1) {
this.logger && this.logger.warn(`[tor-${tor.pid}]: ${msg}`); this.logger && this.logger.warn(`[tor-${this.instance_name}]: ${msg}`);
} }
}); });

View file

@ -40,4 +40,5 @@ module.exports = {
"options": {}, "options": {},
"timeout": null "timeout": null
}, },
"granaxOptions": null
}; };