changed method for mapping services to local ports

This commit is contained in:
tigerbot 2017-04-03 15:11:59 -06:00
parent a9326c3eb0
commit ae15111b0f
2 changed files with 63 additions and 69 deletions

View File

@ -13,7 +13,6 @@ function collectDomains(val, memo) {
function parseProxy(location) { function parseProxy(location) {
// john.example.com // john.example.com
// https:3443
// http:john.example.com:3000 // http:john.example.com:3000
// http://john.example.com:3000 // http://john.example.com:3000
var parts = location.split(':'); var parts = location.split(':');
@ -144,19 +143,11 @@ function connectTunnel() {
} }
}; };
program.locals.forEach(function (proxy) { Object.keys(program.services).forEach(function (protocol) {
var port = proxy.port; var subServices = program.services[protocol];
if (!proxy.port) { Object.keys(subServices).forEach(function (hostname) {
if ('http' === proxy.protocol) { console.info('[local proxy]', protocol + '://' + hostname + ' => ' + subServices[hostname]);
port = hasHttp; });
}
else if ('https' === proxy.protocol) {
port = hasHttps;
}
}
if (proxy.protocol) {
console.info('[local proxy]', proxy.protocol + '://' + proxy.hostname + ' => ' + port);
}
}); });
console.info(''); console.info('');
@ -179,22 +170,22 @@ function rawTunnel() {
return; return;
} }
if (!program.token) {
var jwt = require('jsonwebtoken'); var jwt = require('jsonwebtoken');
var tokenData = { var tokenData = {
domains: null domains: Object.keys(domainsMap).filter(Boolean)
}; };
var location = url.parse(program.stunneld);
program.token = jwt.sign(tokenData, program.secret);
}
var location = url.parse(program.stunneld);
if (!location.protocol || /\./.test(location.protocol)) { if (!location.protocol || /\./.test(location.protocol)) {
program.stunneld = 'wss://' + program.stunneld; program.stunneld = 'wss://' + program.stunneld;
location = url.parse(program.stunneld); location = url.parse(program.stunneld);
} }
program.stunneld = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : ''); program.stunneld = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '');
tokenData.domains = Object.keys(domainsMap).filter(Boolean);
program.token = program.token || jwt.sign(tokenData, program.secret);
connectTunnel(); connectTunnel();
} }
@ -234,45 +225,50 @@ function daplieTunnel() {
} }
var domainsMap = {}; var domainsMap = {};
var hasHttp; var services = {};
var hasHttps;
program.locals = program.locals || []; program.locals = (program.locals || []).concat(program.domains || []);
program.locals = program.locals.concat(program.domains || []);
program.locals.forEach(function (proxy) {
if ('*' === proxy.hostname) {
if ('http' === proxy.protocol) {
hasHttp = proxy.port;
}
else if ('https' === proxy.protocol) {
hasHttps = proxy.port;
}
}
});
if (!hasHttp) {
program.locals.push({
protocol: 'http'
, hostname: '*'
, port: 8443
});
hasHttp = 8443;
}
if (!hasHttps) {
program.locals.push({
protocol: 'https'
, hostname: '*'
, port: 8443
});
hasHttps = 8443;
}
program.locals.forEach(function (proxy) { program.locals.forEach(function (proxy) {
// Create a map from which we can derive a list of all domains we want forwarded to us.
if (proxy.hostname && proxy.hostname !== '*') {
domainsMap[proxy.hostname] = true; domainsMap[proxy.hostname] = true;
});
if (domainsMap.hasOwnProperty('*')) {
delete domainsMap['*'];
//domainsMap['*'] = false;
} }
// Create a map of which port different protocols should be forwarded to, allowing for specific
// domains to go to different ports if need be (though that only works for HTTP and HTTPS).
if (proxy.protocol && proxy.port) {
services[proxy.protocol] = services[proxy.protocol] || {};
if (/http/.test(proxy.protocol) && proxy.hostname && proxy.hostname !== '*') {
services[proxy.protocol][proxy.hostname] = proxy.port;
}
else {
if (services[proxy.protocol]['*'] && services[proxy.protocol]['*'] !== proxy.port) {
console.error('cannot forward generic', proxy.protocol, 'traffic to multiple ports');
process.exit(1);
}
else {
services[proxy.protocol]['*'] = proxy.port;
}
}
}
});
if (Object.keys(domainsMap).length === 0) {
console.error('no domains specified');
process.exit(1);
return;
}
// Make sure we have generic ports for HTTP and HTTPS
services.https = services.https || {};
services.https['*'] = services.https['*'] || 8443;
services.http = services.http || {};
services.http['*'] = services.http['*'] || services.https['*'];
program.services = services;
if (!(program.secret || program.token) && !program.stunneld) { if (!(program.secret || program.token) && !program.stunneld) {
daplieTunnel(); daplieTunnel();
} }

View File

@ -7,13 +7,6 @@ var Packer = require('tunnel-packer');
var authenticated = false; var authenticated = false;
function run(copts) { function run(copts) {
// TODO pair with hostname / sni
copts.services = {};
copts.locals.forEach(function (proxy) {
//program.services = { 'ssh': 22, 'http': 80, 'https': 443 };
copts.services[proxy.protocol] = proxy.port;
});
var tunnelUrl = copts.stunneld.replace(/\/$/, '') + '/?access_token=' + copts.token; var tunnelUrl = copts.stunneld.replace(/\/$/, '') + '/?access_token=' + copts.token;
var wstunneler; var wstunneler;
var localclients = {}; var localclients = {};
@ -26,9 +19,10 @@ function run(copts) {
onmessage: function (opts) { onmessage: function (opts) {
var net = copts.net || require('net'); var net = copts.net || require('net');
var cid = Packer.addrToId(opts); var cid = Packer.addrToId(opts);
var service = opts.service; var service = opts.service.toLowerCase();
var port = copts.services[service]; var portList = copts.services[service];
var servername; var servername;
var port;
var str; var str;
var m; var m;
@ -39,7 +33,12 @@ function run(copts) {
localclients[cid].write(opts.data); localclients[cid].write(opts.data);
return; return;
} }
else if ('http' === service) { if (!portList) {
handlers._onLocalError(cid, opts, new Error("unsupported service '" + service + "'"));
return;
}
if ('http' === service) {
str = opts.data.toString(); str = opts.data.toString();
m = str.match(/(?:^|[\r\n])Host: ([^\r\n]+)[\r\n]*/im); m = str.match(/(?:^|[\r\n])Host: ([^\r\n]+)[\r\n]*/im);
servername = (m && m[1].toLowerCase() || '').split(':')[0]; servername = (m && m[1].toLowerCase() || '').split(':')[0];
@ -48,20 +47,19 @@ function run(copts) {
servername = sni(opts.data); servername = sni(opts.data);
} }
else { else {
handlers._onLocalError(cid, opts, new Error("unsupported service '" + service + "'")); servername = '*';
return;
} }
if (!servername) { if (!servername) {
console.info("[error] missing servername for '" + cid + "'", opts.data.byteLength);
//console.warn(opts.data.toString()); //console.warn(opts.data.toString());
wstunneler.send(Packer.pack(opts, null, 'error'), { binary: true }); handlers._onLocalError(cid, opts, new Error("missing servername for '" + cid + "' " + opts.data.byteLength));
return; return;
} }
port = portList[servername] || portList['*'];
console.info("[connect] new client '" + cid + "' for '" + servername + "' (" + (handlers._numClients() + 1) + " clients)"); console.info("[connect] new client '" + cid + "' for '" + servername + "' (" + (handlers._numClients() + 1) + " clients)");
console.log('port', port, opts.port, service, copts.services); console.log('port', port, opts.port, service, portList);
localclients[cid] = net.createConnection({ localclients[cid] = net.createConnection({
port: port port: port
, host: '127.0.0.1' , host: '127.0.0.1'