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 remote = require('../remote.js');
 | 
			
		||||
var state = {};
 | 
			
		||||
 | 
			
		||||
var argv = process.argv.slice(2);
 | 
			
		||||
//var Greenlock = require('greenlock');
 | 
			
		||||
@ -18,6 +19,8 @@ if (-1 === confIndex) {
 | 
			
		||||
confpath = argv[confIndex + 1];
 | 
			
		||||
 | 
			
		||||
function help() {
 | 
			
		||||
  console.info('');
 | 
			
		||||
  console.info('Telebit Remote v' + pkg.version);
 | 
			
		||||
  console.info('');
 | 
			
		||||
  console.info('Usage:');
 | 
			
		||||
  console.info('');
 | 
			
		||||
@ -42,6 +45,141 @@ if (!confpath || /^--/.test(confpath)) {
 | 
			
		||||
  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 services = {};
 | 
			
		||||
 | 
			
		||||
@ -148,77 +286,6 @@ function collectProxies(val, 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');
 | 
			
		||||
program
 | 
			
		||||
  .version(pkg.version)
 | 
			
		||||
@ -240,35 +307,6 @@ program
 | 
			
		||||
  .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.forEach(function (proxy) {
 | 
			
		||||
@ -311,7 +349,6 @@ services.http = services.http || {};
 | 
			
		||||
services.http['*'] = services.http['*'] || services.https['*'];
 | 
			
		||||
 | 
			
		||||
program.services = services;
 | 
			
		||||
 | 
			
		||||
rawTunnel();
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
}());
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,9 @@
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "bluebird": "^3.5.1",
 | 
			
		||||
    "commander": "^2.9.0",
 | 
			
		||||
    "js-yaml": "^3.11.0",
 | 
			
		||||
    "jsonwebtoken": "^7.1.9",
 | 
			
		||||
    "recase": "^1.0.4",
 | 
			
		||||
    "sni": "^1.0.0",
 | 
			
		||||
    "tunnel-packer": "^1.2.0",
 | 
			
		||||
    "ws": "^2.2.3"
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user