finished http proxy

This commit is contained in:
Zachary Boyd 2017-12-07 17:21:42 -08:00
parent cecdd2d9fd
commit 4620732805
8 changed files with 186 additions and 6 deletions

View file

@ -26,7 +26,7 @@ ADD tor-sources.list /etc/apt/sources.list.d/tor.list
RUN bash /tmp/nodejs_install RUN bash /tmp/nodejs_install
RUN apt install -y --allow-unauthenticated deb.torproject.org-keyring nodejs tor git tzdata RUN apt install -y nodejs tor git
ADD package.json /app/package.json ADD package.json /app/package.json
@ -34,8 +34,6 @@ RUN npm install
ADD . /app ADD . /app
# Grab the current local timezone from an external api and save it into /etc/timezone, otherwise Tor will complain and won't start
ENTRYPOINT [ "tor-router" ] ENTRYPOINT [ "tor-router" ]
CMD [ "-s", "-d", "-j", "1" ] CMD [ "-s", "-d", "-j", "1" ]

View file

@ -16,7 +16,7 @@ To install globally run: `npm install -g`
Alternatively docker can be used. The build will retrieve the latest version of Tor from the offical Tor Project repository. Alternatively docker can be used. The build will retrieve the latest version of Tor from the offical Tor Project repository.
To build run: `docker build -t znetstar/tor-router .` To build run: `docker build -t znetstar/tor-router .`
To start run: `docker run --rm -it -p 9050:9050 znetstar/tor-router tor-router --help` To start run: `docker run --rm -it -p 9050:9050 znetstar/tor-router`
## Usage ## Usage

View file

@ -1 +0,0 @@
curl -sL http://ip-api.com/json | node -e "process.stdin.resume(); process.stdin.on('data', (data) => { process.stdout.write(JSON.parse(data.toString('utf8')).timezone); process.exit(0); });"

View file

@ -16,6 +16,7 @@ program
.option('-j, --instances <1>', 'Number of tor instances', Number) .option('-j, --instances <1>', 'Number of tor instances', Number)
.option('-s, --socksPort [9050]', 'SOCKS Server port', Number) .option('-s, --socksPort [9050]', 'SOCKS Server port', Number)
.option('-d, --dnsPort [9053]', 'DNS Server port', Number) .option('-d, --dnsPort [9053]', 'DNS Server port', Number)
.option('-h, --httpPort [9080]', 'HTTP Server port', Number)
.option('-l, --logLevel [info]', 'Log level (defaults to "info") set to "null" to disable logging', Number) .option('-l, --logLevel [info]', 'Log level (defaults to "info") set to "null" to disable logging', Number)
.parse(process.argv); .parse(process.argv);
@ -29,6 +30,7 @@ let instances = program.instances || Number(process.env.INSTANCES);
let log_level = program.logLevel || process.env.LOG_LEVEL; let log_level = program.logLevel || process.env.LOG_LEVEL;
let socks_port = (program.socksPort === true ? 9050 : program.socksPort) || Number(process.env.SOCKS_PORT); let socks_port = (program.socksPort === true ? 9050 : program.socksPort) || Number(process.env.SOCKS_PORT);
let dns_port = (program.dnsPort === true ? 9053 : program.dnsPort) || Number(process.env.DNS_PORT); let dns_port = (program.dnsPort === true ? 9053 : program.dnsPort) || Number(process.env.DNS_PORT);
let http_port = (program.httpPort === true ? 9080 : program.httpPort) || Number(process.env.HTTP_PORT);
let control_port = (program.controlPort === true ? 9077 : program.controlPort) || Number(process.env.CONTROL_PORT) || 9077; let control_port = (program.controlPort === true ? 9077 : program.controlPort) || Number(process.env.CONTROL_PORT) || 9077;
if (log_level === 'null') if (log_level === 'null')
@ -44,6 +46,10 @@ if (socks_port) {
let socks = control.createSOCKSServer(socks_port); let socks = control.createSOCKSServer(socks_port);
} }
if (http_port) {
let http = control.createHTTPServer(http_port);
}
if (dns_port) { if (dns_port) {
let dns = control.createDNSServer(dns_port); let dns = control.createDNSServer(dns_port);
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "tor-router", "name": "tor-router",
"version": "3.0.7", "version": "3.1.0",
"main": "src/index.js", "main": "src/index.js",
"repository": "git@github.com:znetstar/tor-router.git", "repository": "git@github.com:znetstar/tor-router.git",
"author": "Zachary Boyd <zachary@zacharyboyd.nyc>", "author": "Zachary Boyd <zachary@zacharyboyd.nyc>",
@ -27,6 +27,7 @@
"lodash": "^4.17.4", "lodash": "^4.17.4",
"native-dns": "git+https://github.com/znetstar/node-dns.git", "native-dns": "git+https://github.com/znetstar/node-dns.git",
"socket.io": "^1.7.3", "socket.io": "^1.7.3",
"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",
"winston": "^2.3.1" "winston": "^2.3.1"

View file

@ -2,6 +2,7 @@ const HTTPServer = require('http').Server;
const TorPool = require('./TorPool'); const TorPool = require('./TorPool');
const SOCKSServer = require('./SOCKSServer'); const SOCKSServer = require('./SOCKSServer');
const DNSServer = require('./DNSServer'); const DNSServer = require('./DNSServer');
const HTTPProxyServer = require('./HTTPServer');
class ControlServer { class ControlServer {
constructor(logger) { constructor(logger) {
@ -21,6 +22,7 @@ class ControlServer {
socket.on('createTorPool', this.createTorPool.bind(this)); socket.on('createTorPool', this.createTorPool.bind(this));
socket.on('createSOCKSServer', this.createSOCKSServer.bind(this)); socket.on('createSOCKSServer', this.createSOCKSServer.bind(this));
socket.on('createDNSServer', this.createDNSServer.bind(this)); socket.on('createDNSServer', this.createDNSServer.bind(this));
socket.on('createHTTPServer', this.createHTTPServer.bind(this));
socket.on('queryInstances', (callback) => { socket.on('queryInstances', (callback) => {
if (!this.torPool) if (!this.torPool)
return callback({ message: 'No pool created' }); return callback({ message: 'No pool created' });
@ -51,6 +53,13 @@ class ControlServer {
return this.socksServer; return this.socksServer;
} }
createHTTPServer(port) {
this.httpServer = new HTTPProxyServer(this.torPool, this.logger);
this.httpServer.listen(port || 9080);
this.logger && this.logger.info(`[http]: Listening on ${port}`);
return this.httpServer;
}
createDNSServer(port) { createDNSServer(port) {
this.dnsServer = new DNSServer(this.torPool, this.logger); this.dnsServer = new DNSServer(this.torPool, this.logger);
this.dnsServer.serve(port || 9053); this.dnsServer.serve(port || 9053);

166
src/HTTPServer.js Normal file
View file

@ -0,0 +1,166 @@
const http = require('http');
const Server = http.Server;
const domain = require('domain');
const socks = require('socksv5');
const URL = require('url');
const SocksProxyAgent = require('socks-proxy-agent');
class HTTPServer extends Server {
constructor(tor_pool, logger) {
let handle_http_connections = (req, res) => {
let d = domain.create();
d.add(req);
d.add(res);
let url = URL.parse(req.url);
url.port = url.port || 80;
var buffer = [];
function onIncomingData(chunk) {
buffer.push(chunk);
}
function preConnectClosed() {
req.finished = true;
}
req.on('data', onIncomingData);
req.on('end', preConnectClosed);
let connect = (tor_instance) => {
let socks_port = tor_instance.socks_port;
logger && logger.info(`[http]: ${req.connection.remoteAddress}:${req.connection.remotePort} → 127.0.0.1:${socks_port}${url.hostname}:${url.port}`);
d.run(() => {
let proxy_req = http.request({
method: req.method,
hostname: url.hostname,
port: url.port,
path: url.path,
headers: req.headers,
agent: new SocksProxyAgent(`socks://127.0.0.1:${socks_port}`)
}, (proxy_res) => {
d.add(proxy_res);
proxy_res.on('data', (chunk) => {
res.write(chunk);
});
proxy_res.on('end', () => {
res.end();
});
res.writeHead(proxy_res.statusCode, proxy_res.headers);
});
req.removeListener('data', onIncomingData);
req.on('data', (chunk) => {
proxy_req.write(chunk);
})
req.on('end', () => {
proxy_req.end();
})
while (buffer.length) {
proxy_req.write(buffer.shift());
}
if (req.finished)
proxy_req.end();
d.add(proxy_req);
});
};
if (tor_pool.instances.length) {
connect(tor_pool.next());
} else {
logger.debug(`[http]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online`);
tor_pool.once('instance_created', connect);
}
};
let handle_tcp_connections = (req, inbound_socket, head) => {
let d = domain.create();
d.add(socket);
let url = URL.parse(req.url);
let hostname = url.host.split(':').shift();
let port = url.host.split(':').pop();
let connect = (tor_instance) => {
let socks_port = tor_instance.socks_port;
logger && logger.info(`[http]: ${req.connection.remoteAddress}:${req.connection.remotePort} → 127.0.0.1:${socks_port}${hostname}:${port}`)
d.on('error', onClose);
d.add(inbound_socket);
var buffer = [];
let onInboundData = function (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(`[http]: an error occured: ${error.message}`)
d.exit();
};
d.run(() => {
socks.connect({
host: hostname,
port: port,
proxyHost: '127.0.0.1',
proxyPort: socks_port,
localDNS: false,
auths: [ socks.auth.None() ]
}, ($outbound_socket) => {
outbound_socket = $outbound_socket;
d.add(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 (tor_pool.instances.length) {
connect(tor_pool.next());
} else {
logger.debug(`[http]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online`);
tor_pool.once('instance_created', connect);
}
};
super(handle_http_connections);
this.on('connect', handle_tcp_connections);
this.logger = logger;
this.tor_pool = tor_pool;
}
};
module.exports = HTTPServer;

View file

@ -3,5 +3,6 @@ module.exports = {
TorPool: require('./TorPool'), TorPool: require('./TorPool'),
DNSServer: require('./DNSServer'), DNSServer: require('./DNSServer'),
SOCKSServer: require('./SOCKSServer'), SOCKSServer: require('./SOCKSServer'),
HTTPServer: require('./HTTPServer'),
ControlServer: require('./ControlServer') ControlServer: require('./ControlServer')
}; };