2018-09-19 15:22:17 +00:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< title > SOCKSServer.js - Documentation< / title >
< script src = "scripts/prettify/prettify.js" > < / script >
< script src = "scripts/prettify/lang-css.js" > < / script >
<!-- [if lt IE 9]>
< script src = "//html5shiv.googlecode.com/svn/trunk/html5.js" > < / script >
<![endif]-->
< link type = "text/css" rel = "stylesheet" href = "styles/prettify.css" >
< link type = "text/css" rel = "stylesheet" href = "styles/jsdoc.css" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< / head >
< body >
< input type = "checkbox" id = "nav-trigger" class = "nav-trigger" / >
< label for = "nav-trigger" class = "navicon-button x" >
< div class = "navicon" > < / div >
< / label >
< label for = "nav-trigger" class = "overlay" > < / label >
< nav >
< h2 > < a href = "index.html" > Home< / a > < / h2 > < h3 > Classes< / h3 > < ul > < li > < a href = "ControlServer.html" > ControlServer< / a > < ul class = 'methods' > < li data-type = 'method' > < a href = "ControlServer.html#.instance_info" > instance_info< / a > < / li > < li data-type = 'method' > < a href = "ControlServer.html#close" > close< / a > < / li > < li data-type = 'method' > < a href = "ControlServer.html#createDNSServer" > createDNSServer< / a > < / li > < li data-type = 'method' > < a href = "ControlServer.html#createHTTPServer" > createHTTPServer< / a > < / li > < li data-type = 'method' > < a href = "ControlServer.html#createSOCKSServer" > createSOCKSServer< / a > < / li > < li data-type = 'method' > < a href = "ControlServer.html#createTorPool" > createTorPool< / a > < / li > < li data-type = 'method' > < a href = "ControlServer.html#listen" > listen< / a > < / li > < li data-type = 'method' > < a href = "ControlServer.html#listenTcp" > listenTcp< / a > < / li > < li data-type = 'method' > < a href = "ControlServer.html#listenWs" > listenWs< / a > < / li > < / ul > < / li > < li > < a href = "DNSServer.html" > DNSServer< / a > < ul class = 'methods' > < li data-type = 'method' > < a href = "DNSServer.html#listen" > listen< / a > < / li > < / ul > < / li > < li > < a href = "HTTPServer.html" > HTTPServer< / a > < ul class = 'methods' > < li data-type = 'method' > < a href = "HTTPServer.html#listen" > listen< / a > < / li > < / ul > < / li > < li > < a href = "SOCKSServer.html" > SOCKSServer< / a > < ul class = 'methods' > < li data-type = 'method' > < a href = "SOCKSServer.html#listen" > listen< / a > < / li > < / ul > < / li > < li > < a href = "TorPool.html" > TorPool< / a > < ul class = 'methods' > < li data-type = 'method' > < a href = "TorPool.html#add" > add< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#add_instance_to_group" > add_instance_to_group< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#add_instance_to_group_at" > add_instance_to_group_at< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#add_instance_to_group_by_name" > add_instance_to_group_by_name< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#create" > create< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#create_instance" > create_instance< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#exit" > exit< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#get_config_at" > get_config_at< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#get_config_by_name" > get_config_by_name< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#instance_at" > instance_at< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#instance_by_name" > instance_by_name< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#instances_by_group" > instances_by_group< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#new_identites" > new_identites< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#new_identites_by_group" > new_identites_by_group< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#new_identity_at" > new_identity_at< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#new_identity_by_name" > new_identity_by_name< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#next" > next< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#next_by_group" > next_by_group< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#remove" > remove< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#remove_at" > remove_at< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#remove_by_name" > remove_by_name< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#remove_instance_from_group" > remove_instance_from_group< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#remove_instance_from_group_at" > remove_instance_from_group_at< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#remove_instance_from_group_by_name" > remove_instance_from_group_by_name< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#set_config_all" > set_config_all< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#set_config_at" > set_config_at< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#set_config_by_group" > set_config_by_group< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#set_config_by_name" > set_config_by_name< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#signal_all" > signal_all< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#signal_at" > signal_at< / a > < / li > < li data-type = 'method' > < a href = "TorPool.html#signal_by_group" > signal_by_group< / a > < /li
< / nav >
< div id = "main" >
< h1 class = "page-title" > SOCKSServer.js< / h1 >
< section >
< article >
< pre class = "prettyprint source linenums" > < code > const socks = require('socksv5');
const Promise = require('bluebird');
const { Server } = socks;
/**
* Configuration for the "proxy by name" feature (connecting to specific instances or groups of instances using the username field when connecting).
* @typedef ProxyByNameConfig
*
* @property {boolean} [deny_unidentified_users=false] - Deny unauthenticated (e.g. no username - socks://my-server:9050) users access to the proxy server.
* @property {string} mode - Either "group" for routing to a group of instances or "individual" for routing to individual instances.
*/
/**
* Details on the source of a connection the proxy server.
* @typedef InstanceConnectionSource
* @property {string} hostname - Hostname where the connection was made from.
* @property {number} port - Port where the connection was made from.
* @property {boolean} by_name - Indicates whether the connection was made using a username (made to a specific instance or group of instances).
* @property {string} proto - The protocol of the connection "socks", "http", "http-connect" or "dns"
*/
/**
* A SOCKS5 proxy server that will route requests to instances in the TorPool provided.
* @extends Server
*/
class SOCKSServer extends Server{
/**
* Callback for `authenticate_user`.
* @callback SOCKSServer~authenticate_user_callback
* @param {boolean} allow - Indicates if the connection should be allowed.
* @param {boolean} user - Indicates if the connection should have a session (authentication was successful).
*/
/**
* Binds the server to a port and IP Address.
*
* @async
* @param {number} port - The port to bind to.
* @param {string} [host="::"] - Address to bind to. Will default to :: or 0.0.0.0 if not specified.
* @returns {Promise}
*
*/
async listen() {
return await new Promise((resolve, reject) => {
let args = Array.from(arguments);
let inner_func = super.listen;
args.push(() => {
let args = Array.from(arguments);
resolve.apply(args);
});
inner_func.apply(this, args);
});
}
/**
* Retrieves an instance from the pool or an instance from a group by the name provided.
* @param {string} username - Name of the group or instance to route to.
* @returns {TorProcess}
* @throws If {@link SOCKSServer#proxy_by_name} is set to an invalid value.
* @throws If the name of the instance or group provided is invalid.
* @private
*/
get_instance_pbn(username) {
if (this.proxy_by_name.mode === 'individual')
return this.tor_pool.instance_by_name(username);
else if (this.proxy_by_name.mode === 'group') {
return this.tor_pool.next_by_group(username);
} else
throw Error(`Unknown "proxy_by_name" mode ${this.proxy_by_name.mode}`);
}
/**
* Checks the username provided against all groups (for "group" mode) or all instances (for "individual" mode).
* @param {string} username
* @param {string} password
* @param {SOCKSServer~authenticate_user_callback} callback - Callback for `authenticate_user`.
* @throws If {@link SOCKSServer#proxy_by_name} is invalid.
* @private
*/
authenticate_user(username, password, callback) {
let deny_un = this.proxy_by_name.deny_unidentified_users;
// No username and deny unindentifed then deny
if (!username & & deny_un) callback(false);
// Otherwise if there is no username allow
else if (!username) callback(true);
if (this.proxy_by_name.mode === 'individual'){
if (!this.tor_pool.instance_names.includes(username)) return callback(false);
}
else if (this.proxy_by_name.mode === 'group') {
if (!this.tor_pool.group_names.has(username)) return callback(false);
}
else
throw Error(`Unknown "proxy_by_name" mode "${this.proxy_by_name.mode}"`);
// Otherwise allow
callback(true, true);
}
/**
* Creates an instance of `SOCKSServer`.
* @param {TorPool} tor_pool - The pool of instances that will be used for requests
* @param {Logger} [logger] - Winston logger that will be used for logging. If not specified will disable logging.
* @param {ProxyByNameConfig} [proxy_by_name] - Enable routing to specific instances or groups of instances using the username field (socks://instance-1:@my-server:9050) when connecting.
*/
constructor(tor_pool, logger, proxy_by_name) {
/**
* Handles SOCKS5 inbound connections.
*
* @function handle_connections
* @param {object} info - Information about the inbound connection.
* @param {Function} accept - Callback that allows the connection.
* @param {Function} deny - Callback that denies the connection.
* @private
*/
const handle_connections = (info, accept, deny) => {
let inbound_socket = accept(true);
let instance;
if (inbound_socket.user)
instance = this.get_instance_pbn(inbound_socket.user);
let outbound_socket;
let buffer = [];
let onInboundData = (data) => buffer.push(data)
let onClose = (error) => {
inbound_socket & & inbound_socket.end();
outbound_socket & & outbound_socket.end();
inbound_socket = outbound_socket = buffer = void(0);
if (error)
this.logger.error(`[socks]: an error occured: ${error.message}`)
};
if (!inbound_socket) return;
inbound_socket.on('close', onClose);
inbound_socket.on('data', onInboundData);
inbound_socket.on('error', onClose);
let connect = (tor_instance) => {
let source = { hostname: info.srcAddr, port: info.srcPort, proto: 'socks', by_name: Boolean(instance) };
let socks_port = tor_instance.socks_port;
socks.connect({
host: info.dstAddr,
port: info.dstPort,
proxyHost: '127.0.0.1',
proxyPort: socks_port,
localDNS: false,
auths: [ socks.auth.None() ]
}, ($outbound_socket) => {
/**
* Fires when the proxy has made a connection through an instance.
*
* @event SOCKSServer#instance-connection
* @param {TorProcess} instance - Instance that has been connected to.
* @param {InstanceConnectionSource} source - Details on the source of the connection.
*/
this.emit('instance_connection', tor_instance, source);
this.logger.verbose(`[socks]: ${source.hostname}:${source.port} → 127.0.0.1:${socks_port}${tor_instance.definition.Name ? ' ('+tor_instance.definition.Name+')' : '' } → ${info.dstAddr}:${info.dstPort}`)
outbound_socket = $outbound_socket;
outbound_socket & & outbound_socket.on('close', onClose);
inbound_socket & & inbound_socket.removeListener('data', onInboundData);
inbound_socket & & inbound_socket.on('data', (data) => {
outbound_socket & & outbound_socket.write(data);
});
outbound_socket & & outbound_socket.on('data', (data) => {
inbound_socket & & inbound_socket.write(data);
});
outbound_socket & & outbound_socket.on('error', onClose);
while (buffer & & buffer.length & & outbound_socket) {
outbound_socket.write(buffer.shift());
}
});
};
if (instance) {
if (instance.ready) {
connect(instance);
}
else {
this.logger.debug(`[socks]: a connection has been attempted to "${instance.instance_name}", but it is not live... waiting for the instance to come online`);
instance.once('ready', (() => connect(instance)));
}
}
else if (this.tor_pool.instances.length) {
connect(this.tor_pool.next());
} else {
this.logger.debug(`[socks]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online`);
this.tor_pool.once('instance_created', connect);
}
}
super(handle_connections);
let auth = socks.auth.None();
if (proxy_by_name) {
auth = socks.auth.UserPassword(this.authenticate_user.bind(this));
}
this.useAuth(auth);
/**
* Winston logger to use.
*
* @type {Logger}
* @public
*/
this.logger = logger || require('./winston_silent_logger');
/**
* Pool of instances use to service requests.
*
* @type {TorPool}
* @public
*/
this.tor_pool = tor_pool;
/**
* Configuration for the "proxy by name" feature.
*
* @type {ProxyByNameConfig}
* @public
*/
this.proxy_by_name = proxy_by_name;
this.logger.debug(`[socks]: connecting to a specific instance by name has ben turned ${proxy_by_name ? 'on' : 'off'}`);
}
};
/**
* Module that contains the {@link SOCKSServer} class.
* @module tor-router/SOCKSServer
* @see SOCKSServer
*/
module.exports = SOCKSServer;< / code > < / pre >
< / article >
< / section >
< / div >
< br class = "clear" >
< footer >
2018-09-25 16:53:29 +00:00
Documentation generated by < a href = "https://github.com/jsdoc3/jsdoc" > JSDoc 3.5.5< / a > on Tue Sep 25 2018 12:53:23 GMT-0400 (Eastern Daylight Time) using the < a href = "https://github.com/clenemt/docdash" > docdash< / a > theme.
2018-09-19 15:22:17 +00:00
< / footer >
< script > prettyPrint ( ) ; < / script >
< script src = "scripts/linenumber.js" > < / script >
< / body >
< / html >