Can now connect directly to an instance via http
This commit is contained in:
parent
4553bcc82b
commit
ece4d4ea02
|
@ -17,7 +17,6 @@
|
|||
"devDependencies": {
|
||||
"chai": "^4.1.2",
|
||||
"mocha": "^5.2.0",
|
||||
"proxy-agent": "^3.0.1",
|
||||
"request": "^2.79.0",
|
||||
"request-promise": "^4.2.2"
|
||||
},
|
||||
|
@ -37,6 +36,7 @@
|
|||
"socksv5": "git+https://github.com/znetstar/socksv5.git#431e541390314adbbe765650d8d810ec1df38d8a",
|
||||
"temp": "^0.8.3",
|
||||
"winston": "^3.0.0-rc5",
|
||||
"yargs": "^11.0.0"
|
||||
"yargs": "^11.0.0",
|
||||
"proxy-agent": "^3.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,14 +144,14 @@ class ControlServer {
|
|||
}
|
||||
|
||||
async createSOCKSServer(port, hostname) {
|
||||
this.socksServer = new SOCKSServer(this.torPool, this.logger);
|
||||
this.socksServer = new SOCKSServer(this.torPool, this.logger, (this.nconf.get('proxyByName') ? { deny_unidentified_users: this.nconf.get('denyUnidentifedUsers') } : ""));
|
||||
await this.socksServer.listen(port || default_ports.socks, hostname);
|
||||
this.logger.info(`[socks]: listening on socks5://${hostname}:${port}`);
|
||||
this.socksServer;
|
||||
}
|
||||
|
||||
async createHTTPServer(port, hostname) {
|
||||
this.httpServer = new HTTPServer(this.torPool, this.logger);
|
||||
this.httpServer = new HTTPServer(this.torPool, this.logger, (this.nconf.get('proxyByName') ? { deny_unidentified_users: this.nconf.get('denyUnidentifedUsers') } : ""));
|
||||
await this.httpServer.listen(port || default_ports.http, hostname);
|
||||
this.logger.info(`[http]: listening on http://${hostname}:${port}`);
|
||||
this.httpServer;
|
||||
|
|
|
@ -4,7 +4,7 @@ const { Server } = http;
|
|||
|
||||
const Promise = require('bluebird');
|
||||
const socks = require('socksv5');
|
||||
const SocksProxyAgent = require('socks-proxy-agent');
|
||||
const ProxyAgent = require('proxy-agent');
|
||||
|
||||
const TOR_ROUTER_PROXY_AGENT = 'tor-router';
|
||||
|
||||
|
@ -21,8 +21,57 @@ class HTTPServer extends Server {
|
|||
});
|
||||
}
|
||||
|
||||
constructor(tor_pool, logger) {
|
||||
authenticate_user_http(req, res) {
|
||||
return this.authenticate_user(req, () => {
|
||||
res.writeHead(407, { 'Proxy-Authenticate': `Basic realm="Name of instance to route to"` });
|
||||
res.end();
|
||||
return false;
|
||||
})
|
||||
}
|
||||
|
||||
authenticate_user_connect(req, socket) {
|
||||
return this.authenticate_user(req, () => {
|
||||
socket.end();
|
||||
return false;
|
||||
})
|
||||
}
|
||||
|
||||
authenticate_user(req, deny) {
|
||||
if (!this.proxy_by_name)
|
||||
return true;
|
||||
|
||||
let deny_un = this.proxy_by_name.deny_unidentified_users;
|
||||
|
||||
let header = req.headers['authorization'] || req.headers['proxy-authorization'];
|
||||
if (!header && deny_un) return deny();
|
||||
else if (!header) return true;
|
||||
|
||||
let token = header.split(/\s+/).pop();
|
||||
if (!token && deny_un) return deny();
|
||||
else if (!token) return true;
|
||||
|
||||
let buf = new Buffer.from(token, 'base64').toString();
|
||||
let username = buf.split(/:/).shift();
|
||||
if ( !username && deny_un ) return deny();
|
||||
else if (!username) return true;
|
||||
|
||||
this.logger.verbose(`[http]: connected attempted to instance "${username}"`);
|
||||
|
||||
let instance = this.tor_pool.instance_by_name(username);
|
||||
|
||||
if (!instance) return deny();
|
||||
req.instance = instance;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constructor(tor_pool, logger, proxy_by_name) {
|
||||
let handle_http_connections = (req, res) => {
|
||||
if (!this.authenticate_user_http(req, res))
|
||||
return;
|
||||
|
||||
let { instance } = req;
|
||||
|
||||
let url = URL.parse(req.url);
|
||||
url.port = url.port || 80;
|
||||
|
||||
|
@ -52,7 +101,7 @@ class HTTPServer extends Server {
|
|||
port: url.port,
|
||||
path: url.path,
|
||||
headers: req.headers,
|
||||
agent: new SocksProxyAgent(`socks://127.0.0.1:${socks_port}`)
|
||||
agent: new ProxyAgent(`socks://127.0.0.1:${socks_port}`)
|
||||
}, (proxy_res) => {
|
||||
proxy_res.on('data', (chunk) => {
|
||||
res.write(chunk);
|
||||
|
@ -84,7 +133,16 @@ class HTTPServer extends Server {
|
|||
|
||||
};
|
||||
|
||||
if (tor_pool.instances.length) {
|
||||
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(tor_pool.next());
|
||||
} else {
|
||||
this.logger.debug(`[http-proxy]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online`);
|
||||
|
@ -93,6 +151,11 @@ class HTTPServer extends Server {
|
|||
};
|
||||
|
||||
let handle_connect_connections = (req, inbound_socket, head) => {
|
||||
if (!this.authenticate_user_connect(req, inbound_socket))
|
||||
return;
|
||||
|
||||
let { instance } = req;
|
||||
|
||||
let hostname = req.url.split(':').shift();
|
||||
let port = Number(req.url.split(':').pop());
|
||||
|
||||
|
@ -135,11 +198,21 @@ class HTTPServer extends Server {
|
|||
inbound_socket.pipe(outbound_socket);
|
||||
});
|
||||
};
|
||||
if (tor_pool.instances.length) {
|
||||
connect(tor_pool.next());
|
||||
|
||||
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(`[http-connect]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online`);
|
||||
tor_pool.once('instance_created', connect);
|
||||
this.tor_pool.once('instance_created', connect);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -148,6 +221,7 @@ class HTTPServer extends Server {
|
|||
|
||||
this.logger = logger || require('./winston-silent-logger');
|
||||
this.tor_pool = tor_pool;
|
||||
this.proxy_by_name = proxy_by_name;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -15,10 +15,35 @@ class SOCKSServer extends Server{
|
|||
});
|
||||
}
|
||||
|
||||
authenticate_user(username, password, callback) {
|
||||
let deny_un = this.proxy_by_name.deny_unidentifed_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);
|
||||
|
||||
this.logger.verbose(`[socks]: connected attempted to instance "${username}"`);
|
||||
|
||||
let instance = this.tor_pool.instance_by_name(username);
|
||||
|
||||
// If a username is specified but no instances match that username deny
|
||||
if (!instance)
|
||||
return callback(false);
|
||||
|
||||
// Otherwise allow
|
||||
callback(true, instance);
|
||||
}
|
||||
|
||||
constructor(tor_pool, logger, proxy_by_name) {
|
||||
let handleConnection = (info, accept, deny) => {
|
||||
let inbound_socket = accept(true);
|
||||
var outbound_socket;
|
||||
let instance;
|
||||
|
||||
if (inbound_socket.user)
|
||||
instance = inbound_socket.user;
|
||||
|
||||
let outbound_socket;
|
||||
let buffer = [];
|
||||
|
||||
let onInboundData = (data) => buffer.push(data)
|
||||
|
@ -70,27 +95,37 @@ class SOCKSServer extends Server{
|
|||
}
|
||||
});
|
||||
};
|
||||
if (tor_pool.instances.length) {
|
||||
connect(tor_pool.next());
|
||||
|
||||
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`);
|
||||
tor_pool.once('instance_created', connect);
|
||||
this.tor_pool.once('instance_created', connect);
|
||||
}
|
||||
};
|
||||
|
||||
super(handleConnection);
|
||||
|
||||
this.logger = logger || require('./winston-silent-logger');;
|
||||
this.logger = logger || require('./winston-silent-logger');
|
||||
this.tor_pool = tor_pool;
|
||||
this.proxy_by_name = proxy_by_name;
|
||||
|
||||
let auth = socks.auth.None();
|
||||
|
||||
if (!proxy_by_name) {
|
||||
this.logger.debug(`[socks]: connecting to a specific instance by name has ben turned off`);
|
||||
let auth = socks.auth.None();
|
||||
} else {
|
||||
this.logger.debug(`[socks]: connecting to a specific instance by name has ben turned on`);
|
||||
let auth = socks.auth.UserPassword(
|
||||
(username, password, cb) => {
|
||||
|
||||
}
|
||||
);
|
||||
auth = socks.auth.UserPassword(this.authenticate_user);
|
||||
}
|
||||
|
||||
this.useAuth(auth);
|
||||
|
|
|
@ -124,11 +124,11 @@ class TorPool extends EventEmitter {
|
|||
}
|
||||
|
||||
instance_by_name(name) {
|
||||
return this.instances.filter((i) => i.definition.Name === name)[0];
|
||||
return this._instances.filter((i) => i.definition.Name === name)[0];
|
||||
}
|
||||
|
||||
instance_at(index) {
|
||||
return this.instances[index];
|
||||
return this._instances[index];
|
||||
}
|
||||
|
||||
async remove(instances) {
|
||||
|
|
|
@ -64,6 +64,8 @@ class TorProcess extends EventEmitter {
|
|||
return this._controller || null;
|
||||
}
|
||||
|
||||
get ready() { return this._ready; }
|
||||
|
||||
/* Passthrough to granax */
|
||||
|
||||
async new_identity() {
|
||||
|
@ -133,7 +135,7 @@ class TorProcess extends EventEmitter {
|
|||
});
|
||||
|
||||
this.once('ready', () => {
|
||||
this.ready = true;
|
||||
this._ready = true;
|
||||
this.logger.info(`[tor-${this.instance_name}]: tor is ready`);
|
||||
});
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ module.exports = {
|
|||
"socksHost": null,
|
||||
"dnsHost": null,
|
||||
"httpHost": null,
|
||||
"proxyByName": true,
|
||||
"denyUnidentifedUsers": false,
|
||||
"logLevel": "info",
|
||||
"loadBalanceMethod": "round_robin",
|
||||
"torConfig": {
|
||||
|
|
|
@ -177,6 +177,11 @@ let argv_config =
|
|||
alias: "torPath",
|
||||
describe: "Provide the path for the Tor executable that will be used",
|
||||
demand: false
|
||||
},
|
||||
n: {
|
||||
alias: 'proxyByName',
|
||||
describe: 'Allow connecting to a specific instance identified by the username field when connecting to a proxy',
|
||||
demand: false
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ const env_whitelist = [ "CONTROL_HOST",
|
|||
'PARENT_DATA_DIRECTORIES',
|
||||
'LOAD_BALANCE_METHOD',
|
||||
"WEBSOCKET_CONTROL_PORT",
|
||||
"PROXY_BY_NAME",
|
||||
"DENY_UNIDENTIFIED_USERS",
|
||||
"controlHost",
|
||||
"torPath",
|
||||
"instances",
|
||||
|
@ -17,7 +19,9 @@ const env_whitelist = [ "CONTROL_HOST",
|
|||
"logLevel",
|
||||
'parentDataDirectories',
|
||||
'loadBalanceMethod',
|
||||
"websocketControlPort"
|
||||
"websocketControlPort",
|
||||
"proxyByName",
|
||||
"denyUnidentifedUsers"
|
||||
];
|
||||
|
||||
module.exports = (nconf) => {
|
||||
|
|
Loading…
Reference in a new issue