working cleanup
This commit is contained in:
parent
e848e1466b
commit
acaf22c200
|
@ -3,6 +3,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var pkg = require('../package.json');
|
var pkg = require('../package.json');
|
||||||
|
console.log(pkg.name, pkg.version);
|
||||||
|
|
||||||
var url = require('url');
|
var url = require('url');
|
||||||
var remote = require('../remote.js');
|
var remote = require('../remote.js');
|
||||||
|
@ -37,7 +38,12 @@ function help() {
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 === confIndex || -1 !== argv.indexOf('-h') || -1 !== argv.indexOf('--help')) {
|
if (-1 === confIndex) {
|
||||||
|
confpath = require('path').join(require('os').homedir(), '.config/telebit/telebit.yml');
|
||||||
|
console.info('Using default --config "' + confpath + '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 !== argv.indexOf('-h') || -1 !== argv.indexOf('--help')) {
|
||||||
help();
|
help();
|
||||||
}
|
}
|
||||||
if (!confpath || /^--/.test(confpath)) {
|
if (!confpath || /^--/.test(confpath)) {
|
||||||
|
@ -74,7 +80,6 @@ require('fs').readFile(confpath, 'utf8', function (err, text) {
|
||||||
});
|
});
|
||||||
|
|
||||||
function connectTunnel() {
|
function connectTunnel() {
|
||||||
var services = { https: {}, http: {}, tcp: {} };
|
|
||||||
state.net = {
|
state.net = {
|
||||||
createConnection: function (info, cb) {
|
createConnection: function (info, cb) {
|
||||||
// data is the hello packet / first chunk
|
// data is the hello packet / first chunk
|
||||||
|
@ -86,66 +91,17 @@ function connectTunnel() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Note: the remote needs to know:
|
|
||||||
// what servernames to forward
|
|
||||||
// what ports to forward
|
|
||||||
// what udp ports to forward
|
|
||||||
// redirect http to https automatically
|
|
||||||
// redirect www to nowww automatically
|
|
||||||
if (state.config.http) {
|
|
||||||
Object.keys(state.config.http).forEach(function (hostname) {
|
|
||||||
if ('*' === hostname) {
|
|
||||||
state.config.servernames.forEach(function (servername) {
|
|
||||||
services.https[servername] = state.config.http[hostname];
|
|
||||||
services.http[servername] = 'redirect-https';
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
services.https[hostname] = state.config.http[hostname];
|
|
||||||
services.http[hostname] = 'redirect-https';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
Object.keys(state.config.localPorts).forEach(function (port) {
|
|
||||||
var proto = state.config.localPorts[port];
|
|
||||||
if (!proto) { return; }
|
|
||||||
if ('http' === proto) {
|
|
||||||
state.config.servernames.forEach(function (servername) {
|
|
||||||
services.http[servername] = port;
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ('https' === proto) {
|
|
||||||
state.config.servernames.forEach(function (servername) {
|
|
||||||
services.https[servername] = port;
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (true === proto) { proto = 'tcp'; }
|
|
||||||
if ('tcp' !== proto) { throw new Error("unsupported protocol '" + proto + "'"); }
|
|
||||||
//services[proxy.protocol]['*'] = proxy.port;
|
|
||||||
//services[proxy.protocol][proxy.hostname] = proxy.port;
|
|
||||||
services[proto]['*'] = port;
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
state.services = services;
|
|
||||||
|
|
||||||
Object.keys(services).forEach(function (protocol) {
|
|
||||||
var subServices = state.services[protocol];
|
|
||||||
Object.keys(subServices).forEach(function (hostname) {
|
|
||||||
console.info('[local proxy]', protocol + '://' + hostname + ' => ' + subServices[hostname]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
console.info('');
|
|
||||||
|
|
||||||
state.greenlock = state.config.greenlock || {};
|
state.greenlock = state.config.greenlock || {};
|
||||||
|
if (!state.config.sortingHat) {
|
||||||
|
state.config.sortingHat = './lib/sorting-hat.js';
|
||||||
|
}
|
||||||
|
state.config.sortingHat = require('path').resolve(__dirname, '..', state.config.sortingHat);
|
||||||
|
|
||||||
// TODO Check undefined vs false for greenlock config
|
// TODO Check undefined vs false for greenlock config
|
||||||
var tun = remote.connect({
|
var tun = remote.connect({
|
||||||
relay: state.config.relay
|
relay: state.config.relay
|
||||||
, config: state.config
|
, config: state.config
|
||||||
, sortingHat: state.config.sortingHat || './lib/sorting-hat.js'
|
, sortingHat: state.config.sortingHat
|
||||||
, locals: state.config.servernames
|
|
||||||
, services: state.services
|
|
||||||
, net: state.net
|
, net: state.net
|
||||||
, insecure: state.config.relay_ignore_invalid_certificates
|
, insecure: state.config.relay_ignore_invalid_certificates
|
||||||
, token: state.token
|
, token: state.token
|
||||||
|
@ -157,6 +113,7 @@ function connectTunnel() {
|
||||||
, configDir: state.greenlock.configDir || '~/acme/etc/'
|
, configDir: state.greenlock.configDir || '~/acme/etc/'
|
||||||
// TODO, store: require(state.greenlock.store.name || 'le-store-certbot').create(state.greenlock.store.options || {})
|
// TODO, store: require(state.greenlock.store.name || 'le-store-certbot').create(state.greenlock.store.options || {})
|
||||||
, approveDomains: function (opts, certs, cb) {
|
, approveDomains: function (opts, certs, cb) {
|
||||||
|
console.log("trying approve domains");
|
||||||
// Certs being renewed are listed in certs.altnames
|
// Certs being renewed are listed in certs.altnames
|
||||||
if (certs) {
|
if (certs) {
|
||||||
opts.domains = certs.altnames;
|
opts.domains = certs.altnames;
|
||||||
|
@ -164,16 +121,22 @@ function connectTunnel() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 !== state.config.servernames.indexOf(opts.domains[0])) {
|
// by virtue of the fact that it's being tunneled through a
|
||||||
|
// trusted source that is already checking, we're good
|
||||||
|
//if (-1 !== state.config.servernames.indexOf(opts.domains[0])) {
|
||||||
opts.email = state.greenlock.email || state.config.email;
|
opts.email = state.greenlock.email || state.config.email;
|
||||||
opts.agreeTos = state.greenlock.agree || state.agreeTos;
|
opts.agreeTos = state.greenlock.agree || state.agreeTos;
|
||||||
cb(null, { options: opts, certs: certs });
|
cb(null, { options: opts, certs: certs });
|
||||||
return;
|
return;
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
//cb(new Error("servername not found in allowed list"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
require(state.config.sortingHat).print(state.config);
|
||||||
|
|
||||||
function sigHandler() {
|
function sigHandler() {
|
||||||
console.log('SIGINT');
|
console.log('SIGINT');
|
||||||
|
|
||||||
|
@ -208,7 +171,7 @@ function rawTunnel() {
|
||||||
if (!state.config.token) {
|
if (!state.config.token) {
|
||||||
var jwt = require('jsonwebtoken');
|
var jwt = require('jsonwebtoken');
|
||||||
var tokenData = {
|
var tokenData = {
|
||||||
domains: state.config.servernames
|
domains: Object.keys(state.config.servernames).filter(function (name) { return /\./.test(name); })
|
||||||
, aud: aud
|
, aud: aud
|
||||||
, iss: Math.round(Date.now() / 1000)
|
, iss: Math.round(Date.now() / 1000)
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,185 @@
|
||||||
|
module.exports.print = function (config) {
|
||||||
|
var services = { https: {}, http: {}, tcp: {} };
|
||||||
|
// Note: the remote needs to know:
|
||||||
|
// what servernames to forward
|
||||||
|
// what ports to forward
|
||||||
|
// what udp ports to forward
|
||||||
|
// redirect http to https automatically
|
||||||
|
// redirect www to nowww automatically
|
||||||
|
if (config.http) {
|
||||||
|
Object.keys(config.http).forEach(function (hostname) {
|
||||||
|
if ('*' === hostname) {
|
||||||
|
config.servernames.forEach(function (servername) {
|
||||||
|
services.https[servername] = config.http[hostname];
|
||||||
|
services.http[servername] = 'redirect-https';
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
services.https[hostname] = config.http[hostname];
|
||||||
|
services.http[hostname] = 'redirect-https';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Object.keys(config.localPorts).forEach(function (port) {
|
||||||
|
var proto = config.localPorts[port];
|
||||||
|
if (!proto) { return; }
|
||||||
|
if ('http' === proto) {
|
||||||
|
config.servernames.forEach(function (servername) {
|
||||||
|
services.http[servername] = port;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ('https' === proto) {
|
||||||
|
config.servernames.forEach(function (servername) {
|
||||||
|
services.https[servername] = port;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (true === proto) { proto = 'tcp'; }
|
||||||
|
if ('tcp' !== proto) { throw new Error("unsupported protocol '" + proto + "'"); }
|
||||||
|
//services[proxy.protocol]['*'] = proxy.port;
|
||||||
|
//services[proxy.protocol][proxy.hostname] = proxy.port;
|
||||||
|
services[proto]['*'] = port;
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
Object.keys(services).forEach(function (protocol) {
|
||||||
|
var subServices = services[protocol];
|
||||||
|
Object.keys(subServices).forEach(function (hostname) {
|
||||||
|
console.info('[local proxy]', protocol + '://' + hostname + ' => ' + subServices[hostname]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
console.info('');
|
||||||
|
};
|
||||||
|
|
||||||
module.exports.assign = function (state, tun, cb) {
|
module.exports.assign = function (state, tun, cb) {
|
||||||
var net = state.net || require('net');
|
var net = state.net || require('net');
|
||||||
var service = tun.service.toLowerCase();
|
|
||||||
var portList = state.services[service];
|
|
||||||
var port;
|
|
||||||
|
|
||||||
if (!tun.name && !tun.serviceport) {
|
if (!tun.name && !tun.serviceport) {
|
||||||
console.log('tun:\n',tun);
|
console.log('tun:\n',tun);
|
||||||
//console.warn(tun.data.toString());
|
//console.warn(tun.data.toString());
|
||||||
cb(new Error("missing routing information for ':tun_id'"));
|
cb(new Error("No routing information for ':tun_id'. Missing both 'name' and 'serviceport'."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!state.config.servernames) {
|
||||||
|
state.config.servernames = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
var handlers = {};
|
||||||
|
handlers.http = function (socket) {
|
||||||
|
if (!state.greenlock) {
|
||||||
|
state.greenlock = require('greenlock').create(state.greenlockConfig);
|
||||||
|
}
|
||||||
|
if (!state.httpRedirectServer) {
|
||||||
|
state.redirectHttps = require('redirect-https')();
|
||||||
|
state.httpRedirectServer = require('http').createServer(state.greenlock.middleware(state.redirectHttps));
|
||||||
|
}
|
||||||
|
state.httpRedirectServer.emit('connection', socket);
|
||||||
|
};
|
||||||
|
handlers.https = function (tlsSocket) {
|
||||||
|
if (!state.defaultHttpServer) {
|
||||||
|
state.defaultHttpServer = require('http').createServer(function (req, res) {
|
||||||
|
console.log('[hit http/s server]');
|
||||||
|
res.end('Hello, Encrypted Tunnel World!');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
state.defaultHttpServer.emit('connection', tlsSocket);
|
||||||
|
};
|
||||||
|
|
||||||
|
if ('http' === tun.service || 'https' === tun.service) {
|
||||||
|
if (!tun.name) {
|
||||||
|
cb(new Error("No routing information for ':tun_id'. Service '" + tun.service + "' is missing 'name'."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirectHttp(cb) {
|
||||||
|
var socketPair = require('socket-pair');
|
||||||
|
conn = socketPair.create(function (err, other) {
|
||||||
|
if (err) { cb(err); return; }
|
||||||
|
handlers.http(other);
|
||||||
|
cb(null, conn);
|
||||||
|
});
|
||||||
|
//if (tun.data) { conn.write(tun.data); }
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
var handled;
|
||||||
|
|
||||||
|
if ('http' === tun.service) {
|
||||||
|
// TODO match *.example.com
|
||||||
|
handled = Object.keys(state.config.servernames).some(function (sn) {
|
||||||
|
if (sn !== tun.name) { return; }
|
||||||
|
|
||||||
|
console.log('Found config match for PLAIN', tun.name);
|
||||||
|
if (!state.config.servernames[sn]) { return; }
|
||||||
|
|
||||||
|
if (false === state.config.servernames[sn].terminate) {
|
||||||
|
cb(new Error("insecure http not supported yet"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Redirecting HTPTP for', tun.name);
|
||||||
|
redirectHttp(cb);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if (!handled) {
|
||||||
|
redirectHttp(cb);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function terminateTls(cb) {
|
||||||
|
var socketPair = require('socket-pair');
|
||||||
|
conn = socketPair.create(function (err, other) {
|
||||||
|
if (err) { cb(err); return; }
|
||||||
|
|
||||||
|
if (!state.greenlock) {
|
||||||
|
state.greenlock = require('greenlock').create(state.greenlockConfig);
|
||||||
|
}
|
||||||
|
if (!state.terminatorServer) {
|
||||||
|
state.terminatorServer = require('tls').createServer(state.greenlock.tlsOptions, function (tlsSocket) {
|
||||||
|
console.log('[hit tls server]');
|
||||||
|
if (err) { cb(err); return; }
|
||||||
|
handlers.https(tlsSocket);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[emitting tls connection]');
|
||||||
|
state.terminatorServer.emit('connection', other);
|
||||||
|
cb(null, conn);
|
||||||
|
});
|
||||||
|
//if (tun.data) { conn.write(tun.data); }
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('https' === tun.service) {
|
||||||
|
// TODO match *.example.com
|
||||||
|
handled = Object.keys(state.config.servernames).some(function (sn) {
|
||||||
|
if (sn !== tun.name) { return; }
|
||||||
|
|
||||||
|
console.log('Found config match for TLS', tun.name);
|
||||||
|
if (!state.config.servernames[sn]) { return; }
|
||||||
|
|
||||||
|
if (false === state.config.servernames[sn].terminate) {
|
||||||
|
cb(new Error("insecure http not supported yet"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Terminating TLS for', tun.name);
|
||||||
|
terminateTls(cb);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if (!handled) {
|
||||||
|
terminateTls(cb);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
var portList = state.services[service];
|
||||||
|
var port;
|
||||||
port = portList[tun.name];
|
port = portList[tun.name];
|
||||||
if (!port) {
|
if (!port) {
|
||||||
// Check for any wildcard domains, sorted longest to shortest so the one with the
|
// Check for any wildcard domains, sorted longest to shortest so the one with the
|
||||||
|
@ -48,7 +217,7 @@ module.exports.assign = function (state, tun, cb) {
|
||||||
function handleNow(socket) {
|
function handleNow(socket) {
|
||||||
var httpServer;
|
var httpServer;
|
||||||
var tlsServer;
|
var tlsServer;
|
||||||
if ('https' === service) {
|
if ('https' === tun.service) {
|
||||||
if (!state.greenlock) {
|
if (!state.greenlock) {
|
||||||
state.greenlock = require('greenlock').create(state.greenlockConfig);
|
state.greenlock = require('greenlock').create(state.greenlockConfig);
|
||||||
}
|
}
|
||||||
|
@ -77,9 +246,7 @@ module.exports.assign = function (state, tun, cb) {
|
||||||
conn = socketPair.create(function (err, other) {
|
conn = socketPair.create(function (err, other) {
|
||||||
if (err) { console.error('[Error] ' + err.message); }
|
if (err) { console.error('[Error] ' + err.message); }
|
||||||
handleNow(other);
|
handleNow(other);
|
||||||
if (createOpts.data) {
|
//if (createOpts.data) { conn.write(createOpts.data); }
|
||||||
conn.write(createOpts.data);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
/*
|
/*
|
||||||
var streamPair = require('stream-pair');
|
var streamPair = require('stream-pair');
|
||||||
|
@ -96,9 +263,7 @@ module.exports.assign = function (state, tun, cb) {
|
||||||
// this will happen before 'data' or 'readable' is triggered
|
// this will happen before 'data' or 'readable' is triggered
|
||||||
// We use the data from the createOpts object so that the createConnection function has
|
// We use the data from the createOpts object so that the createConnection function has
|
||||||
// the oppurtunity of removing/changing it if it wants/needs to handle it differently.
|
// the oppurtunity of removing/changing it if it wants/needs to handle it differently.
|
||||||
if (createOpts.data) {
|
//if (createOpts.data) { conn.write(createOpts.data); }
|
||||||
conn.write(createOpts.data);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
cb(null, conn);
|
cb(null, conn);
|
||||||
|
|
|
@ -52,11 +52,11 @@
|
||||||
"greenlock": "^2.2.19",
|
"greenlock": "^2.2.19",
|
||||||
"js-yaml": "^3.11.0",
|
"js-yaml": "^3.11.0",
|
||||||
"jsonwebtoken": "^7.1.9",
|
"jsonwebtoken": "^7.1.9",
|
||||||
|
"proxy-packer": "^1.4.3",
|
||||||
"recase": "^1.0.4",
|
"recase": "^1.0.4",
|
||||||
"redirect-https": "^1.1.5",
|
"redirect-https": "^1.1.5",
|
||||||
"sni": "^1.0.0",
|
"sni": "^1.0.0",
|
||||||
"socket-pair": "^1.0.3",
|
"socket-pair": "^1.0.3",
|
||||||
"proxy-packer": "^1.4.3",
|
|
||||||
"ws": "^2.2.3"
|
"ws": "^2.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue