getting closer...
This commit is contained in:
parent
9d6384addc
commit
d4c52787b9
241
bin/telebit.js
241
bin/telebit.js
|
@ -6,6 +6,7 @@ var pkg = require('../package.json');
|
||||||
|
|
||||||
var url = require('url');
|
var url = require('url');
|
||||||
var remote = require('../remote.js');
|
var remote = require('../remote.js');
|
||||||
|
var state = {};
|
||||||
|
|
||||||
var argv = process.argv.slice(2);
|
var argv = process.argv.slice(2);
|
||||||
//var Greenlock = require('greenlock');
|
//var Greenlock = require('greenlock');
|
||||||
|
@ -18,6 +19,8 @@ if (-1 === confIndex) {
|
||||||
confpath = argv[confIndex + 1];
|
confpath = argv[confIndex + 1];
|
||||||
|
|
||||||
function help() {
|
function help() {
|
||||||
|
console.info('');
|
||||||
|
console.info('Telebit Remote v' + pkg.version);
|
||||||
console.info('');
|
console.info('');
|
||||||
console.info('Usage:');
|
console.info('Usage:');
|
||||||
console.info('');
|
console.info('');
|
||||||
|
@ -42,6 +45,141 @@ if (!confpath || /^--/.test(confpath)) {
|
||||||
help();
|
help();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
require('fs').readFile(confpath, 'utf8', function (err, text) {
|
||||||
|
var config;
|
||||||
|
|
||||||
|
var recase = require('recase').create({});
|
||||||
|
var camelCopy = recase.camelCopy.bind(recase);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
console.error("\nCouldn't load config:\n\n\t" + err.message + "\n");
|
||||||
|
process.exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
config = JSON.parse(text);
|
||||||
|
} catch(e1) {
|
||||||
|
try {
|
||||||
|
config = require('js-yaml').safeLoad(text);
|
||||||
|
} catch(e2) {
|
||||||
|
console.error(e1.message);
|
||||||
|
console.error(e2.message);
|
||||||
|
process.exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.config = camelCopy(config);
|
||||||
|
rawTunnel();
|
||||||
|
});
|
||||||
|
|
||||||
|
function connectTunnel() {
|
||||||
|
var services = { https: {}, http: {}, tcp: {} };
|
||||||
|
state.net = {
|
||||||
|
createConnection: function (info, cb) {
|
||||||
|
// data is the hello packet / first chunk
|
||||||
|
// info = { data, servername, port, host, remoteFamily, remoteAddress, remotePort }
|
||||||
|
var net = require('net');
|
||||||
|
// socket = { write, push, end, events: [ 'readable', 'data', 'error', 'end' ] };
|
||||||
|
var socket = net.createConnection({ port: info.port, host: info.host }, cb);
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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
|
||||||
|
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('');
|
||||||
|
|
||||||
|
var tun = remote.connect({
|
||||||
|
relay: state.config.relay
|
||||||
|
, locals: state.config.servernames
|
||||||
|
, services: state.services
|
||||||
|
, net: state.net
|
||||||
|
, insecure: state.config.relay_ignore_invalid_certificates
|
||||||
|
, token: state.config.token
|
||||||
|
});
|
||||||
|
|
||||||
|
function sigHandler() {
|
||||||
|
console.log('SIGINT');
|
||||||
|
|
||||||
|
// We want to handle cleanup properly unless something is broken in our cleanup process
|
||||||
|
// that prevents us from exitting, in which case we want the user to be able to send
|
||||||
|
// the signal again and exit the way it normally would.
|
||||||
|
process.removeListener('SIGINT', sigHandler);
|
||||||
|
tun.end();
|
||||||
|
}
|
||||||
|
process.on('SIGINT', sigHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rawTunnel() {
|
||||||
|
if (!state.config.relay) {
|
||||||
|
throw new Error("config is missing 'relay'");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(state.config.secret || state.config.token)) {
|
||||||
|
console.error("You must use --secret or --token with --relay");
|
||||||
|
process.exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var location = url.parse(state.config.relay);
|
||||||
|
if (!location.protocol || /\./.test(location.protocol)) {
|
||||||
|
state.config.relay = 'wss://' + state.config.relay;
|
||||||
|
location = url.parse(state.config.relay);
|
||||||
|
}
|
||||||
|
var aud = location.hostname + (location.port ? ':' + location.port : '');
|
||||||
|
state.config.relay = location.protocol + '//' + aud;
|
||||||
|
|
||||||
|
if (!state.config.token) {
|
||||||
|
var jwt = require('jsonwebtoken');
|
||||||
|
var tokenData = {
|
||||||
|
domains: state.config.servernames
|
||||||
|
, aud: aud
|
||||||
|
, iss: Math.round(Date.now() / 1000)
|
||||||
|
};
|
||||||
|
|
||||||
|
state.token = jwt.sign(tokenData, state.config.secret);
|
||||||
|
}
|
||||||
|
state.token = state.token || state.config.token;
|
||||||
|
|
||||||
|
connectTunnel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
var domainsMap = {};
|
var domainsMap = {};
|
||||||
var services = {};
|
var services = {};
|
||||||
|
|
||||||
|
@ -148,77 +286,6 @@ function collectProxies(val, memo) {
|
||||||
return memo;
|
return memo;
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectTunnel() {
|
|
||||||
var state = {};
|
|
||||||
var services = { https: {}, http: {}, tcp: {} };
|
|
||||||
state.net = {
|
|
||||||
createConnection: function (info, cb) {
|
|
||||||
// data is the hello packet / first chunk
|
|
||||||
// info = { data, servername, port, host, remoteFamily, remoteAddress, remotePort }
|
|
||||||
var net = require('net');
|
|
||||||
// socket = { write, push, end, events: [ 'readable', 'data', 'error', 'end' ] };
|
|
||||||
var socket = net.createConnection({ port: info.port, host: info.host }, cb);
|
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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
|
|
||||||
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;
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.keys(program.services).forEach(function (protocol) {
|
|
||||||
var subServices = program.services[protocol];
|
|
||||||
Object.keys(subServices).forEach(function (hostname) {
|
|
||||||
console.info('[local proxy]', protocol + '://' + hostname + ' => ' + subServices[hostname]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
console.info('');
|
|
||||||
|
|
||||||
var tun = remote.connect({
|
|
||||||
relay: state.config.relay
|
|
||||||
, locals: state.config.servernames
|
|
||||||
, services: state.services
|
|
||||||
, net: state.net
|
|
||||||
, insecure: state.config.relay_ignore_invalid_certificates
|
|
||||||
, token: state.config.token
|
|
||||||
});
|
|
||||||
|
|
||||||
function sigHandler() {
|
|
||||||
console.log('SIGINT');
|
|
||||||
|
|
||||||
// We want to handle cleanup properly unless something is broken in our cleanup process
|
|
||||||
// that prevents us from exitting, in which case we want the user to be able to send
|
|
||||||
// the signal again and exit the way it normally would.
|
|
||||||
process.removeListener('SIGINT', sigHandler);
|
|
||||||
tun.end();
|
|
||||||
}
|
|
||||||
process.on('SIGINT', sigHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
var program = require('commander');
|
var program = require('commander');
|
||||||
program
|
program
|
||||||
.version(pkg.version)
|
.version(pkg.version)
|
||||||
|
@ -240,35 +307,6 @@ program
|
||||||
.parse(process.argv)
|
.parse(process.argv)
|
||||||
;
|
;
|
||||||
|
|
||||||
function rawTunnel() {
|
|
||||||
program.relay = program.relay || 'wss://telebit.cloud';
|
|
||||||
|
|
||||||
if (!(program.secret || program.token)) {
|
|
||||||
console.error("You must use --secret or --token with --relay");
|
|
||||||
process.exit(1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var location = url.parse(program.relay);
|
|
||||||
if (!location.protocol || /\./.test(location.protocol)) {
|
|
||||||
program.relay = 'wss://' + program.relay;
|
|
||||||
location = url.parse(program.relay);
|
|
||||||
}
|
|
||||||
var aud = location.hostname + (location.port ? ':' + location.port : '');
|
|
||||||
program.relay = location.protocol + '//' + aud;
|
|
||||||
|
|
||||||
if (!program.token) {
|
|
||||||
var jwt = require('jsonwebtoken');
|
|
||||||
var tokenData = {
|
|
||||||
domains: Object.keys(domainsMap).filter(Boolean)
|
|
||||||
, aud: aud
|
|
||||||
};
|
|
||||||
|
|
||||||
program.token = jwt.sign(tokenData, program.secret);
|
|
||||||
}
|
|
||||||
|
|
||||||
connectTunnel();
|
|
||||||
}
|
|
||||||
|
|
||||||
program.locals = (program.locals || []).concat(program.domains || []);
|
program.locals = (program.locals || []).concat(program.domains || []);
|
||||||
program.locals.forEach(function (proxy) {
|
program.locals.forEach(function (proxy) {
|
||||||
|
@ -311,7 +349,6 @@ services.http = services.http || {};
|
||||||
services.http['*'] = services.http['*'] || services.https['*'];
|
services.http['*'] = services.http['*'] || services.https['*'];
|
||||||
|
|
||||||
program.services = services;
|
program.services = services;
|
||||||
|
*/
|
||||||
rawTunnel();
|
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -49,7 +49,9 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bluebird": "^3.5.1",
|
"bluebird": "^3.5.1",
|
||||||
"commander": "^2.9.0",
|
"commander": "^2.9.0",
|
||||||
|
"js-yaml": "^3.11.0",
|
||||||
"jsonwebtoken": "^7.1.9",
|
"jsonwebtoken": "^7.1.9",
|
||||||
|
"recase": "^1.0.4",
|
||||||
"sni": "^1.0.0",
|
"sni": "^1.0.0",
|
||||||
"tunnel-packer": "^1.2.0",
|
"tunnel-packer": "^1.2.0",
|
||||||
"ws": "^2.2.3"
|
"ws": "^2.2.3"
|
||||||
|
|
Loading…
Reference in New Issue