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 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
@ -34,8 +34,6 @@ RUN npm install
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" ]
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.
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

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('-s, --socksPort [9050]', 'SOCKS 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)
.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 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 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;
if (log_level === 'null')
@ -44,6 +46,10 @@ if (socks_port) {
let socks = control.createSOCKSServer(socks_port);
}
if (http_port) {
let http = control.createHTTPServer(http_port);
}
if (dns_port) {
let dns = control.createDNSServer(dns_port);
}

View file

@ -1,6 +1,6 @@
{
"name": "tor-router",
"version": "3.0.7",
"version": "3.1.0",
"main": "src/index.js",
"repository": "git@github.com:znetstar/tor-router.git",
"author": "Zachary Boyd <zachary@zacharyboyd.nyc>",
@ -27,6 +27,7 @@
"lodash": "^4.17.4",
"native-dns": "git+https://github.com/znetstar/node-dns.git",
"socket.io": "^1.7.3",
"socks-proxy-agent": "^3.0.1",
"socksv5": "git+https://github.com/lee-elenbaas/socksv5.git",
"temp": "^0.8.3",
"winston": "^2.3.1"

View file

@ -2,6 +2,7 @@ const HTTPServer = require('http').Server;
const TorPool = require('./TorPool');
const SOCKSServer = require('./SOCKSServer');
const DNSServer = require('./DNSServer');
const HTTPProxyServer = require('./HTTPServer');
class ControlServer {
constructor(logger) {
@ -21,6 +22,7 @@ class ControlServer {
socket.on('createTorPool', this.createTorPool.bind(this));
socket.on('createSOCKSServer', this.createSOCKSServer.bind(this));
socket.on('createDNSServer', this.createDNSServer.bind(this));
socket.on('createHTTPServer', this.createHTTPServer.bind(this));
socket.on('queryInstances', (callback) => {
if (!this.torPool)
return callback({ message: 'No pool created' });
@ -51,6 +53,13 @@ class ControlServer {
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) {
this.dnsServer = new DNSServer(this.torPool, this.logger);
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'),
DNSServer: require('./DNSServer'),
SOCKSServer: require('./SOCKSServer'),
HTTPServer: require('./HTTPServer'),
ControlServer: require('./ControlServer')
};