diff --git a/CHANGELOG.md b/CHANGELOG.md index f020e4c..8818484 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [3.4.3] - 2018-08-10 + +### Added +- Adds a changelog +- Adds `queryInstanceByName` and `queryInstanceAt` RPC methods to retrieve individual instances + ## [3.4.2] - 2018-08-09 ### Added @@ -30,7 +36,7 @@ ## [3.3.0] - 2018-05-10 ### Added -- Adds documentation on all RPC Methods available +- Adds documentation on all available RPC Methods - Allows different load-balance methods to be defined, and changed at runtime and via RPC - Each instance can have started with a specific configuration (torrc) by setting the `Config` property in the definition diff --git a/README.md b/README.md index a8eecc0..c2a06a0 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ Tor Router also includes a DNS proxy server and a HTTP proxy as well, which like the SOCKS proxy will distribute traffic across multiple instances of Tor in round-robin fashion. The HTTP proxy server can be used to access Tor via an HTTP Proxy. +A list of changes can be [found here](https://github.com/znetstar/tor-router/blob/master/CHANGELOG.md) + ## Building and Running The only installation requirement is node.js. Tor is bundled with the application. To use an external Tor executable use the `--torPath` command line switch or set the `TOR_PATH` environment variable. @@ -37,6 +39,10 @@ The following command line switches and their environment variable equivalents a For example: `tor-router -j 3 -s 9050` would start the proxy with 3 tor instances and listen for SOCKS connections on 9050. +## Testing + +Tests are written in mocha and can be found under `test/test.js` and can be run with `npm test` + ## Configuration Using the `--config` or `-f` command line switch you can set the path to a JSON file which can be used to load configuration on startup @@ -147,8 +153,4 @@ let rpcRequest = { "id": 1 }; client.write(JSON.stringify(rpcRequest)); -``` - -## Test - -Tests are written in mocha, just run `npm test` \ No newline at end of file +``` \ No newline at end of file diff --git a/docs/rpc-methods.md b/docs/rpc-methods.md index 910dce9..cd5eb54 100644 --- a/docs/rpc-methods.md +++ b/docs/rpc-methods.md @@ -1,14 +1,22 @@ -## RPC Functions +# RPC Functions The following functions are available via the RPC -# queryInstances() +## queryInstances() Returns an array containing information on the instances currently running under the router. -# createInstances(Array or Integrer) +## queryInstanceByName(String) -If passed an integrer, creates thats many Tor instances. An array can also be passed describing the names, weights and configurations of prospective instances. : +Returns information on an instance identified by name + +## queryInstanceAt(Integer) + +Returns information on an instance identified by index + +## createInstances(Array or Integer) + +If passed an Integer, creates thats many Tor instances. An array can also be passed describing the names, weights and configurations of prospective instances. : ``` var rpcRequest = { @@ -30,63 +38,63 @@ var rpcRequest = { Will wait until the Tor Instance has fully connected to the network before returning -# addInstances(Array) +## addInstances(Array) Serves the same purpose as "createInstances" but only takes an Array -# removeInstances(Integrer) +## removeInstances(Integer) Removes a number of instances -# removeInstanceAt(Integrer) +## removeInstanceAt(Integer) Remove a specific instance from the pool by its index -# removeInstanceByName(String) +## removeInstanceByName(String) Remove a specific instance from the pool by its name -# newIdentites() +## newIdentites() Get new identites for all instances -# newIdentityAt(Integrer) +## newIdentityAt(Integer) Get a new identity for a specific instance by its index -# newIdentityByName(String) +## newIdentityByName(String) Get a new identity for a specific instance by its name -# nextInstance() +## nextInstance() Cycle to the next instance using the load balancing method -# closeInstances() +## closeInstances() Shutdown all Tor instances -# setTorConfig(Object) +## setTorConfig(Object) Applies the configuration to all active instances -# getDefaultTorConfig() +## getDefaultTorConfig() Retrieve the default Tor Config for all future instances -# setDefaultTorConfig(Object) +## setDefaultTorConfig(Object) Set the default Tor Config for all future instances -# getLoadBalanceMethod() +## getLoadBalanceMethod() Get the current load balance method -# setLoadBalanceMethod(String) +## setLoadBalanceMethod(String) Set the current load balance method -# getInstanceConfigAt(Integrer: index, String: keyword) +## getInstanceConfigAt(Integer: index, String: keyword) Retrieves the current value of an option set in the configuration by the index of the instance using the control protocol. @@ -103,28 +111,28 @@ var rpcRequest = { }; ``` -# getInstanceConfigByName(String: name, String: keyword) +## getInstanceConfigByName(String: name, String: keyword) Works the same way as `getInstanceConfigAt` except takes an instance name instead of an index -# setInstanceConfigAt(Integrer: index, String: keyword, String: value) +## setInstanceConfigAt(Integer: index, String: keyword, String: value) Sets the value in the configuration of an instance using the control protocol. Changes will be applied immediately. -# setInstanceConfigByName(Integrer: index, String: keyword, String: value) +## setInstanceConfigByName(Integer: index, String: keyword, String: value) Works the same way as `setInstanceConfigAt` except takes an instance name instead of an index -# signalAllInstances(String) +## signalAllInstances(String) Sends a signal using the control protocol to all instances A list of all signals can be [found here](https://gitweb.torproject.org/torspec.git/tree/control-spec.txt) -# signalInstanceAt(Integrer: index, String: signal) +## signalInstanceAt(Integer: index, String: signal) Sends a signal using the control protocol to an instance identified by its index -# signalInstanceByName(String: name, String: signal) +## signalInstanceByName(String: name, String: signal) Sends a signal using the control protocol to an instance identified by its name \ No newline at end of file diff --git a/package.json b/package.json index 0c13bf1..4c24193 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tor-router", - "version": "3.4.2", + "version": "3.4.3", "main": "src/index.js", "repository": "git@github.com:znetstar/tor-router.git", "author": "Zachary Boyd ", diff --git a/src/ControlServer.js b/src/ControlServer.js index 63d6b49..1815579 100644 --- a/src/ControlServer.js +++ b/src/ControlServer.js @@ -17,14 +17,44 @@ class ControlServer { server.expose('createDNSServer', this.createDNSServer.bind(this)); server.expose('createHTTPServer', this.createHTTPServer.bind(this)); - // queryInstanceAt, queryInstanceByName + const instance_info = (i) => { + return { name: i.instance_name, dns_port: i.dns_port, socks_port: i.socks_port, process_id: i.process.pid, config: i.definition.Config, weight: i.definition.weight }; + }; server.expose('queryInstances', (function () { return new Promise((resolve, reject) => { if (!this.torPool) return reject({ message: 'No pool created' }); - resolve(this.torPool.instances.map((i) => ( { name: i.instance_name, dns_port: i.dns_port, socks_port: i.socks_port, process_id: i.process.pid, config: i.definition.Config, weight: i.definition.weight } )) ); + resolve(this.torPool.instances.map(instance_info) ); + }); + }).bind(this)); + + server.expose('queryInstanceByName', (function (instance_name) { + return new Promise((resolve, reject) => { + if (!this.torPool) + return reject({ message: 'No pool created' }); + + let i = this.torPool.instance_by_name(instance_name); + + if (!i) + return reject({ message: `Instance "${instance_name}"" does not exist` }); + + resolve(instance_info(i)); + }); + }).bind(this)); + + server.expose('queryInstanceAt', (function (index) { + return new Promise((resolve, reject) => { + if (!this.torPool) + return reject({ message: 'No pool created' }); + + let i = this.torPool.instance_at(index); + + if (!i) + return reject({ message: `Instance at "${i}"" does not exist` }); + + resolve(instance_info(this.torPool.instance_at(index))); }); }).bind(this)); diff --git a/test/test.js b/test/test.js index db6bf64..684359f 100644 --- a/test/test.js +++ b/test/test.js @@ -23,7 +23,7 @@ var logger = winston.createLogger({ }); const WAIT_FOR_CREATE = 120000; -const PAGE_LOAD_TIME = 30000; +const PAGE_LOAD_TIME = 60000; describe('TorProcess', function () { var tor = new (TorRouter.TorProcess)(nconf.get('torPath'), { DataDirectory: nconf.get('parentDataDirectory'), ProtocolWarnings: 0 }, null, logger); @@ -281,20 +281,6 @@ describe('TorPool', function () { }); - describe('#new_ips(index)', function () { - this.timeout(5000); - it('should signal to retrieve a new identity to all instances', function (done) { - torPool.new_ips(done); - }); - }); - - describe('#new_ip_at(instance_name)', function () { - this.timeout(5000); - it('should signal to retrieve a new identity identified by index', function (done) { - torPool.new_ip_at(0, done); - }); - }); - describe('#set_config_all(keyword, value)', function () { it('should set configuration on all active instances', function (done) { this.timeout(5000); @@ -457,7 +443,7 @@ describe('HTTPServer', function () { req.on('response', function (res) { done(); - }) + }); }); }); @@ -476,7 +462,7 @@ describe('HTTPServer', function () { req.on('response', function (res) { done(); - }) + }); }); }); @@ -652,6 +638,34 @@ describe('ControlServer - RPC', function () { }); }); + describe('#queryInstanceByName(instance_name)', function () { + this.timeout(3000); + it('should return a single instance', function (done) { + rpcClient.invoke('queryInstanceByName', ['instance-1'], function (error, raw) { + if (error) + return done(error); + + var instance = JSON.parse(raw).result; + + done(null, (typeof(instance.name) !== undefined) && (instance.name !== null)); + }); + }); + }); + + describe('#queryInstanceAt(index)', function () { + this.timeout(3000); + it('should return a single instance', function (done) { + rpcClient.invoke('queryInstanceAt', [0], function (error, raw) { + if (error) + return done(error); + + var instance = JSON.parse(raw).result; + + done(null, (typeof(instance.name) !== undefined) && (instance.name !== null)); + }); + }); + }); + describe('#newIdentites()', function () { this.timeout(3000); it('should request new identities for all instances', function (done) {