prepare to handle tunnel
This commit is contained in:
		
							parent
							
								
									350d87c38d
								
							
						
					
					
						commit
						0fdd2773b5
					
				@ -184,7 +184,7 @@ module.exports = function (deps, conf, overrideHttp) {
 | 
			
		||||
                , stunneld: result.tunnelUrl
 | 
			
		||||
                  // we'll provide faux networking and pipe as we please
 | 
			
		||||
                , services: { https: { '*': 443 }, http: { '*': 80 }, smtp: { '*': 25}, smtps: { '*': 587 /*also 465/starttls*/ } /*, ssh: { '*': 22 }*/ }
 | 
			
		||||
                , net: conf.net
 | 
			
		||||
                , net: deps.tunnel.net || deps.net
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                if (tun) {
 | 
			
		||||
 | 
			
		||||
@ -81,6 +81,7 @@ module.exports.create = function (deps, config) {
 | 
			
		||||
        firstChunk = firstChunk.toString('utf8');
 | 
			
		||||
        // JSON.stringify("Host: example.com\r\nNext: Header".replace(/(Host: [^\r\n]*)/i, "$1" + "\r\n" + "X: XYZ"))
 | 
			
		||||
        firstChunk = firstChunk.replace(/(Host: [^\r\n]*)/i, "$1" + "\r\n" + newHeads.join("\r\n"));
 | 
			
		||||
 | 
			
		||||
        process.nextTick(function () {
 | 
			
		||||
          conn.unshift(Buffer.from(firstChunk, 'utf8'));
 | 
			
		||||
        });
 | 
			
		||||
@ -104,6 +105,7 @@ module.exports.create = function (deps, config) {
 | 
			
		||||
        }
 | 
			
		||||
        opts.hostname = hostname;
 | 
			
		||||
        conn.__opts = opts;
 | 
			
		||||
 | 
			
		||||
        modules.http.emit('connection', conn);
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
@ -123,6 +125,15 @@ module.exports.create = function (deps, config) {
 | 
			
		||||
  , _create: function (address, port/*, nextServer*/) {
 | 
			
		||||
      // port provides hinting for https, smtps, etc
 | 
			
		||||
      return function (socket, firstChunk, opts) {
 | 
			
		||||
        if (opts.hyperPeek) {
 | 
			
		||||
          // See "PEEK COMMENT" for more info
 | 
			
		||||
          // This was peeked at properly, so we don't have to re-wrap it
 | 
			
		||||
          // in order to get the connection to not hang.
 | 
			
		||||
          // The real first 'data' and 'readable' events will occur as they should
 | 
			
		||||
          program.tlsTunnelServer.emit('connection', socket);
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var servername = opts.servername;
 | 
			
		||||
        var packerStream = require('tunnel-packer').Stream;
 | 
			
		||||
        var myDuplex = packerStream.create(socket);
 | 
			
		||||
@ -176,26 +187,49 @@ module.exports.create = function (deps, config) {
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  // opts = { servername, encrypted, remoteAddress, remotePort }
 | 
			
		||||
  function handler(conn, opts) {
 | 
			
		||||
  // opts = { servername, encrypted, peek, data, remoteAddress, remotePort }
 | 
			
		||||
  function peek(conn, firstChunk, opts) {
 | 
			
		||||
    // TODO port/service-based routing can do here
 | 
			
		||||
 | 
			
		||||
    // TLS
 | 
			
		||||
    if (22 === firstChunk[0]) {
 | 
			
		||||
      console.log('tryTls');
 | 
			
		||||
      opts.servername = (parseSni(firstChunk)||'').toLowerCase() || 'localhost.invalid';
 | 
			
		||||
      tlsRouter.get(opts.localAddress || conn.localAddress, conn.localPort)(conn, firstChunk, opts);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    console.log('tryTcp');
 | 
			
		||||
 | 
			
		||||
    if (opts.hyperPeek) {
 | 
			
		||||
      // even though we've already peeked, this logic is just as well to let be
 | 
			
		||||
      // since it works properly either way, unlike the tls socket
 | 
			
		||||
      conn.once('data', function (chunk) {
 | 
			
		||||
        tcpRouter.get(opts.localAddress || conn.localAddress, conn.localPort)(conn, chunk, opts);
 | 
			
		||||
      });
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tcpRouter.get(opts.localAddress || conn.localAddress, conn.localPort)(conn, firstChunk, opts);
 | 
			
		||||
  }
 | 
			
		||||
  function netHandler(conn, opts) {
 | 
			
		||||
    opts = opts || {};
 | 
			
		||||
    console.log('[handler]', conn.localAddres, conn.localPort, opts.encrypted);
 | 
			
		||||
    console.log('[netHandler]', conn.localAddres, conn.localPort, opts.encrypted);
 | 
			
		||||
 | 
			
		||||
    conn.once('data', function (firstChunk) {
 | 
			
		||||
      var servername;
 | 
			
		||||
    // XXX PEEK COMMENT XXX
 | 
			
		||||
    // TODO we can have our cake and eat it too
 | 
			
		||||
    // we can skip the need to wrap the TLS connection twice
 | 
			
		||||
    // because we've already peeked at the data,
 | 
			
		||||
    // but this needs to be handled better before we enable that
 | 
			
		||||
    // (because it creates new edge cases)
 | 
			
		||||
    if (opts.hyperPeek) {
 | 
			
		||||
      console.log('hyperpeek');
 | 
			
		||||
      peek(conn, opts.firstChunk, opts);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      // TODO port-based routing can do here
 | 
			
		||||
 | 
			
		||||
      // TLS
 | 
			
		||||
      if (22 === firstChunk[0]) {
 | 
			
		||||
        servername = (parseSni(firstChunk)||'').toLowerCase() || 'localhost.invalid';
 | 
			
		||||
        console.log('tryTls');
 | 
			
		||||
        tlsRouter.get(conn.localAddress, conn.localPort)(conn, firstChunk, opts);
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        console.log('tryTcp');
 | 
			
		||||
        tcpRouter.get(conn.localAddress, conn.localPort)(conn, firstChunk, opts);
 | 
			
		||||
      }
 | 
			
		||||
    conn.once('data', function (chunk) {
 | 
			
		||||
      peek(conn, chunk, opts);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -238,7 +272,7 @@ module.exports.create = function (deps, config) {
 | 
			
		||||
    // TODO ask http module about the default path (/srv/www/:hostname)
 | 
			
		||||
    // (if it exists, we can allow and add to config)
 | 
			
		||||
    if (!modules.http) {
 | 
			
		||||
      modules.http = require('./modules/http.js').create(config);
 | 
			
		||||
      modules.http = require('./modules/http.js').create(deps, config);
 | 
			
		||||
    }
 | 
			
		||||
    modules.http.checkServername(opts.domain).then(function (stuff) {
 | 
			
		||||
      if (!stuff.domains) {
 | 
			
		||||
@ -284,6 +318,41 @@ module.exports.create = function (deps, config) {
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  deps.tunnel = deps.tunnel || {};
 | 
			
		||||
  deps.tunnel.net = {
 | 
			
		||||
    createConnection: function (opts, cb) {
 | 
			
		||||
      var Duplex = require('stream').Duplex;
 | 
			
		||||
      var myDuplex = new Duplex();
 | 
			
		||||
      var wrapOpts = {};
 | 
			
		||||
 | 
			
		||||
      // this has the normal net/tcp stuff plus our custom stuff
 | 
			
		||||
      // opts = { address, port,
 | 
			
		||||
      //          hostname, servername, encrypted, data, localAddress, localPort, remoteAddress, remotePort, remoteFamily }
 | 
			
		||||
      Object.keys(opts).forEach(function (key) {
 | 
			
		||||
        wrapOpts[key] = opts[key];
 | 
			
		||||
        myDuplex[key] = opts[key];
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      // A few more extra specialty options
 | 
			
		||||
      wrapOpts.firstChunk = opts.data;
 | 
			
		||||
      wrapOpts.hyperPeek = !!opts.data;
 | 
			
		||||
      wrapOpts.localAddress = wrapOpts.localAddress || '127.0.0.2'; // TODO use the tunnel's external address
 | 
			
		||||
      wrapOpts.localPort = wrapOpts.localPort || 'tunnel-0';
 | 
			
		||||
 | 
			
		||||
      netHandler(myDuplex, wrapOpts);
 | 
			
		||||
 | 
			
		||||
      process.nextTick(function () {
 | 
			
		||||
        //opts.data = wrapOpts.data;
 | 
			
		||||
 | 
			
		||||
        // this cb will cause the stream to emit its (actually) first data event
 | 
			
		||||
        // (even though it already gave a peek into that first data chunk)
 | 
			
		||||
        cb();
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return myDuplex;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  Object.keys(program.tlsOptions).forEach(function (key) {
 | 
			
		||||
    tunnelAdminTlsOpts[key] = program.tlsOptions[key];
 | 
			
		||||
  });
 | 
			
		||||
@ -322,7 +391,7 @@ module.exports.create = function (deps, config) {
 | 
			
		||||
    //});
 | 
			
		||||
    //(program.httpTunnelServer || program.httpServer).emit('connection', tlsSocket);
 | 
			
		||||
    //tcpRouter.get(conn.localAddress, conn.localPort)(conn, firstChunk, { encrypted: false });
 | 
			
		||||
    handler(tlsSocket, {
 | 
			
		||||
    netHandler(tlsSocket, {
 | 
			
		||||
      servername: tlsSocket.servername
 | 
			
		||||
    , encrypted: true
 | 
			
		||||
      // remoteAddress... ugh... https://github.com/nodejs/node/issues/8854
 | 
			
		||||
@ -332,6 +401,6 @@ module.exports.create = function (deps, config) {
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  PromiseA.all(config.tcp.ports.map(function (port) {
 | 
			
		||||
    return listeners.tcp.add(port, handler);
 | 
			
		||||
    return listeners.tcp.add(port, netHandler);
 | 
			
		||||
  }));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user