The control server can now accept websocket connections. All servers can be bound to a specific hostname
This commit is contained in:
parent
a571d2caf9
commit
c379350de7
|
@ -3,11 +3,13 @@
|
|||
## [4.0.0] - 2018-09-09
|
||||
|
||||
### Added
|
||||
- All servers (DNS, HTTP, SOCKS and Control) all have a `listen` method which returns a Promise that will resolve when the server is listening.
|
||||
- The control server will accept WebSocket connections if the `--websocketControlHost` or `-w` argument is set. If the argument is used without a hostname it will default to 9078 on all interfaces.
|
||||
- All servers (DNS, HTTP, SOCKS and Control) all have a `listen` method which takes a port and optionally, a host returns a Promise that will resolve when the server is listening.
|
||||
|
||||
### Changes
|
||||
- All "Port" config options (e.g. socksPort) have been replaced with "Host", and can take a full host (e.g. 127.0.0.1:9050) for its value. This allows you to bind Tor Router to a specific hostname. If just a port is given it will bind to all interfaces.
|
||||
- All methods now return promises instead of accepting callbacks. Methods now take advantage of async/await to increase readability.
|
||||
- The `logger` argument to the constructor's of all classes is now optional
|
||||
- The `logger` argument to the constructor of all classes is now optional
|
||||
- The `Config` property of instance definitions will now inherit from `TorPool.default_tor_config`.
|
||||
- The mocha test has been split into individual files all under `test/`
|
||||
|
||||
|
|
19
package-lock.json
generated
19
package-lock.json
generated
|
@ -85,6 +85,11 @@
|
|||
"lodash": "^4.14.0"
|
||||
}
|
||||
},
|
||||
"async-limiter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
|
||||
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
|
@ -1079,11 +1084,11 @@
|
|||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
|
||||
},
|
||||
"jrpc2": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/jrpc2/-/jrpc2-1.0.5.tgz",
|
||||
"integrity": "sha1-dyGptrP6+qz8QE0N0RkOI4ZCCN4=",
|
||||
"version": "git+https://github.com/znetstar/jrpc2.git#f1521bd3f2fa73d716e74bf8f746d08d5e03e7d7",
|
||||
"from": "git+https://github.com/znetstar/jrpc2.git",
|
||||
"requires": {
|
||||
"async": "^1.2",
|
||||
"ws": "^6.0.0",
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -2211,6 +2216,14 @@
|
|||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"ws": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.0.0.tgz",
|
||||
"integrity": "sha512-c2UlYcAZp1VS8AORtpq6y4RJIkJ9dQz18W32SpR/qXGfLDZ2jU4y4wKvvZwqbi7U6gxFQTeE+urMbXU/tsDy4w==",
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"xregexp": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz",
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
"eventemitter3": "^3.1.0",
|
||||
"get-port": "^2.1.0",
|
||||
"granax": "^3.1.3",
|
||||
"jrpc2": "^1.0.5",
|
||||
"jrpc2": "git+https://github.com/znetstar/jrpc2.git",
|
||||
"js-weighted-list": "^0.1.1",
|
||||
"lodash": "^4.17.4",
|
||||
"nanoid": "^1.0.2",
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
const TorPool = require('./TorPool');
|
||||
const SOCKSServer = require('./SOCKSServer');
|
||||
const DNSServer = require('./DNSServer');
|
||||
const HTTPServer = require('./HTTPServer');
|
||||
const rpc = require('jrpc2');
|
||||
|
||||
const SOCKSServer = require('./SOCKSServer');
|
||||
const HTTPServer = require('./HTTPServer');
|
||||
const DNSServer = require('./DNSServer');
|
||||
const TorPool = require('./TorPool');
|
||||
const default_ports = require('./default_ports');
|
||||
|
||||
class ControlServer {
|
||||
constructor(logger, nconf) {
|
||||
this.torPool = new TorPool(nconf.get('torPath'), (() => nconf.get('torConfig')), nconf.get('parentDataDirectory'), nconf.get('loadBalanceMethod'), nconf.get('granaxOptions'), logger);
|
||||
|
@ -118,11 +120,20 @@ class ControlServer {
|
|||
server.expose('signalInstanceByName', this.torPool.signal_by_name.bind(this.torPool));
|
||||
}
|
||||
|
||||
async listen(port) {
|
||||
this.tcpTransport = new rpc.tcpTransport({ port });
|
||||
async listenTcp(port, hostname) {
|
||||
this.tcpTransport = new rpc.tcpTransport({ port, hostname });
|
||||
this.tcpTransport.listen(this.server);
|
||||
this.logger.info(`[control]: control server listening on tcp://${hostname}:${port}`);
|
||||
}
|
||||
|
||||
async listenWs(port, hostname) {
|
||||
this.wsTransport = new rpc.wsTransport({ port, hostname });
|
||||
this.wsTransport.listen(this.server);
|
||||
this.logger.info(`[control]: control server listening on ws://${hostname}:${port}`);
|
||||
}
|
||||
|
||||
async listen(port) { return await this.listenTcp(port); }
|
||||
|
||||
close() {
|
||||
return this.tcpTransport.tcpServer.close();
|
||||
}
|
||||
|
@ -132,24 +143,24 @@ class ControlServer {
|
|||
return this.torPool;
|
||||
}
|
||||
|
||||
async createSOCKSServer(port) {
|
||||
async createSOCKSServer(port, hostname) {
|
||||
this.socksServer = new SOCKSServer(this.torPool, this.logger);
|
||||
await this.socksServer.listen(port || 9050);
|
||||
this.logger.info(`[socks]: Listening on ${port}`);
|
||||
await this.socksServer.listen(port || default_ports.socks, hostname);
|
||||
this.logger.info(`[socks]: listening on socks5://${hostname}:${port}`);
|
||||
this.socksServer;
|
||||
}
|
||||
|
||||
async createHTTPServer(port) {
|
||||
async createHTTPServer(port, hostname) {
|
||||
this.httpServer = new HTTPServer(this.torPool, this.logger);
|
||||
await this.httpServer.listen(port || 9080);
|
||||
this.logger.info(`[http]: Listening on ${port}`);
|
||||
await this.httpServer.listen(port || default_ports.http, hostname);
|
||||
this.logger.info(`[http]: listening on http://${hostname}:${port}`);
|
||||
this.httpServer;
|
||||
}
|
||||
|
||||
async createDNSServer(port) {
|
||||
async createDNSServer(port, hostname) {
|
||||
this.dnsServer = new DNSServer(this.torPool, this.nconf.get('dns:options'), this.nconf.get('dns:timeout'), this.logger);
|
||||
await this.dnsServer.serve(port || 9053);
|
||||
this.logger.info(`[dns]: Listening on ${port}`);
|
||||
await this.dnsServer.serve(port || default_ports.dns, hostname);
|
||||
this.logger.info(`[dns]: listening on dns://${hostname}:${port}`);
|
||||
this.dnsServer;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,11 +3,12 @@ const temp = require('temp');
|
|||
const path = require('path');
|
||||
temp.track();
|
||||
module.exports = {
|
||||
"controlPort": 9077,
|
||||
"controlHost": 9077,
|
||||
"websocketControlHost": null,
|
||||
"parentDataDirectory": temp.mkdirSync(),
|
||||
"socksPort": null,
|
||||
"dnsPort": null,
|
||||
"httpPort": null,
|
||||
"socksHost": null,
|
||||
"dnsHost": null,
|
||||
"httpHost": null,
|
||||
"logLevel": "info",
|
||||
"loadBalanceMethod": "round_robin",
|
||||
"torConfig": {
|
||||
|
|
8
src/default_ports.js
Normal file
8
src/default_ports.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
module.exports = Object.freeze({
|
||||
socks: 9050,
|
||||
http: 9080,
|
||||
dns: 9053,
|
||||
control: 9077,
|
||||
controlWs: 9078,
|
||||
default_host: null
|
||||
});
|
|
@ -6,48 +6,72 @@ const winston = require('winston')
|
|||
const Promise = require('bluebird');
|
||||
|
||||
const { ControlServer } = require('./');
|
||||
const default_ports = require('./default_ports');
|
||||
|
||||
const package_json = JSON.parse(fs.readFileSync(`${__dirname}/../package.json`, 'utf8'));
|
||||
|
||||
function extractHost (host) {
|
||||
if (typeof(host) === 'number')
|
||||
return { hostname: (typeof(default_ports.default_host) === 'string' ? default_ports.default_host : ''), port: host };
|
||||
else if (typeof(host) === 'string' && host.indexOf(':') !== -1)
|
||||
return { hostname: host.split(':').shift(), port: Number(host.split(':').pop()) };
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
function assembleHost(host) {
|
||||
return `${typeof(host.hostname) === 'string' ? host.hostname : '' }:${host.port}`;
|
||||
}
|
||||
|
||||
async function main(nconf, logger) {
|
||||
let instances = nconf.get('instances');
|
||||
let socks_port = nconf.get('socksPort');
|
||||
let dns_port = nconf.get('dnsPort');
|
||||
let http_port = nconf.get('httpPort');
|
||||
let control_port = nconf.get('controlPort');
|
||||
let socks_host = typeof(nconf.get('socksHost')) !== 'boolean' ? extractHost(nconf.get('socksHost')) : nconf.get('socksHost');
|
||||
let dns_host = typeof(nconf.get('dnsHost')) !== 'boolean' ? extractHost(nconf.get('dnsHost')) : nconf.get('dnsHost');
|
||||
let http_host = typeof(nconf.get('httpHost')) !== 'boolean' ? extractHost(nconf.get('httpHost')) : nconf.get('httpHost');
|
||||
let control_host = typeof(nconf.get('controlHost')) !== 'boolean' ? extractHost(nconf.get('controlHost')) : nconf.get('controlHost');
|
||||
let control_host_ws = typeof(nconf.get('websocketControlHost')) !== 'boolean' ? extractHost(nconf.get('websocketControlHost')) : nconf.get('websocketControlHost');
|
||||
|
||||
if (typeof(control_port) === 'boolean') {
|
||||
control_port = 9077;
|
||||
nconf.set('controlPort', 9077);
|
||||
if (typeof(control_host) === 'boolean') {
|
||||
control_host = extractHost(9077);
|
||||
nconf.set('controlHost', assembleHost(control_port));
|
||||
}
|
||||
|
||||
if (typeof(control_host_ws) === 'boolean') {
|
||||
control_host_ws = extractHost(9078);
|
||||
nconf.set('websocketControlPort', assembleHost(control_host_ws));
|
||||
}
|
||||
|
||||
let control = new ControlServer(logger, nconf);
|
||||
|
||||
try {
|
||||
await control.listen(control_port);
|
||||
await control.listenTcp(control_host.port, control_host.hostname);
|
||||
|
||||
if (socks_port) {
|
||||
if (typeof(socks_port) === 'boolean') {
|
||||
socks_port = 9050;
|
||||
nconf.set('socksPort', socks_port);
|
||||
}
|
||||
control.createSOCKSServer(socks_port);
|
||||
if (control_host_ws) {
|
||||
control.listenWs(control_host_ws.port, control_host_ws.hostname);
|
||||
}
|
||||
|
||||
if (http_port) {
|
||||
if (typeof(http_port) === 'boolean') {
|
||||
http_port = 9080;
|
||||
nconf.set('httpPort', http_port);
|
||||
if (socks_host) {
|
||||
if (typeof(socks_host) === 'boolean') {
|
||||
socks_host = extractHost(default_ports.socks);
|
||||
nconf.set('socksHost', assembleHost(socks_host));
|
||||
}
|
||||
control.createHTTPServer(http_port);
|
||||
control.createSOCKSServer(socks_host.port, socks_host.hostname);
|
||||
}
|
||||
|
||||
if (dns_port) {
|
||||
if (typeof(dns_port) === 'boolean') {
|
||||
dns_port = 9053;
|
||||
nconf.set('dnsPort', dns_port);
|
||||
if (http_host) {
|
||||
if (typeof(http_host) === 'boolean') {
|
||||
http_host = extractHost(default_ports.http);
|
||||
nconf.set('httpHost', assembleHost(http_host));
|
||||
}
|
||||
control.createDNSServer(dns_port);
|
||||
control.createHTTPServer(http_host.port, http_host.hostname);
|
||||
}
|
||||
|
||||
if (dns_host) {
|
||||
if (typeof(dns_host) === 'boolean') {
|
||||
dns_host = extractHost(default_ports.dns);
|
||||
nconf.set('dnsPort', assembleHost(dns_host));
|
||||
}
|
||||
control.createDNSServer(dns_host.port, dns_host.hostname);
|
||||
}
|
||||
|
||||
if (instances) {
|
||||
|
@ -56,7 +80,6 @@ async function main(nconf, logger) {
|
|||
|
||||
logger.info('[tor]: tor started');
|
||||
}
|
||||
logger.info(`[control]: control Server listening on ${control_port}`);
|
||||
} catch (error) {
|
||||
logger.error(`[global]: error starting application: ${error.stack}`);
|
||||
process.exit(1);
|
||||
|
@ -102,11 +125,16 @@ let argv_config =
|
|||
demand: false
|
||||
},
|
||||
c: {
|
||||
alias: 'controlPort',
|
||||
describe: 'Port the control server will bind to [default: 9077]',
|
||||
alias: 'controlHost',
|
||||
describe: `Host the control server will bind to, handling TCP connections [default: ${default_ports.default_host}:9077]`,
|
||||
demand: false
|
||||
// ,default: 9077
|
||||
},
|
||||
w: {
|
||||
alias: 'websocketControlHost',
|
||||
describe: 'Host the control server will bind to, handling WebSocket connections. If no hostname is specified will bind to localhost',
|
||||
demand: false
|
||||
},
|
||||
j: {
|
||||
alias: 'instances',
|
||||
describe: 'Number of instances using the default config',
|
||||
|
@ -114,19 +142,19 @@ let argv_config =
|
|||
// ,default: 1
|
||||
},
|
||||
s: {
|
||||
alias: 'socksPort',
|
||||
describe: 'Port the SOCKS5 Proxy server will bind to',
|
||||
alias: 'socksHost',
|
||||
describe: 'Host the SOCKS5 Proxy server will bind to. If no hostname is specified will bind to localhost',
|
||||
demand: false,
|
||||
// ,default: 9050
|
||||
// ,default: default_ports.socks
|
||||
},
|
||||
d: {
|
||||
alias: 'dnsPort',
|
||||
describe: 'Port the DNS Proxy server will bind to',
|
||||
alias: 'dnsHost',
|
||||
describe: 'Host the DNS Proxy server will bind to. If no hostname is specified will bind to localhost',
|
||||
demand: false
|
||||
},
|
||||
h: {
|
||||
alias: 'httpPort',
|
||||
describe: 'Port the HTTP Proxy server will bind to',
|
||||
alias: 'httpHost',
|
||||
describe: 'Host the HTTP Proxy server will bind to. If no hostname is specified will bind to localhost',
|
||||
demand: false
|
||||
},
|
||||
l: {
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
const env_whitelist = [ "CONTROL_PORT",
|
||||
const env_whitelist = [ "CONTROL_HOST",
|
||||
"TOR_PATH",
|
||||
"INSTANCES",
|
||||
"SOCKS_PORT",
|
||||
"DNS_PORT",
|
||||
"HTTP_PORT",
|
||||
"SOCKS_HOST",
|
||||
"DNS_HOST",
|
||||
"HTTP_HOST",
|
||||
"LOG_LEVEL",
|
||||
'PARENT_DATA_DIRECTORIES',
|
||||
'LOAD_BALANCE_METHOD',
|
||||
"controlPort",
|
||||
"WEBSOCKET_CONTROL_PORT",
|
||||
"controlHost",
|
||||
"torPath",
|
||||
"instances",
|
||||
"socksPort",
|
||||
"dnsPort",
|
||||
"httpPort",
|
||||
"socksHost",
|
||||
"dnsHost",
|
||||
"httpHost",
|
||||
"logLevel",
|
||||
'parentDataDirectories',
|
||||
'loadBalanceMethod'
|
||||
'loadBalanceMethod',
|
||||
"websocketControlPort"
|
||||
];
|
||||
|
||||
module.exports = (nconf) => {
|
||||
|
|
Loading…
Reference in a new issue