206 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| var net = require('net');
 | |
| var sni = require('sni');
 | |
| var jwt = require('jsonwebtoken');
 | |
| var packer = require('tunnel-packer');
 | |
| 
 | |
| var Transform = require('stream').Transform;
 | |
| var util = require('util');
 | |
| 
 | |
| function MyTransform(options) {
 | |
|   if (!(this instanceof MyTransform)) {
 | |
|     return new MyTransform(options);
 | |
|   }
 | |
|   this.__my_addr = options.address;
 | |
|   Transform.call(this, options);
 | |
| }
 | |
| util.inherits(MyTransform, Transform);
 | |
| function transform(me, data, encoding, callback) {
 | |
|   var address = me.__my_addr;
 | |
| 
 | |
|   me.push(packer.pack(address, data));
 | |
|   callback();
 | |
| }
 | |
| MyTransform.prototype._transform = function (data, encoding, callback) {
 | |
|   return transform(this, data, encoding, callback);
 | |
| };
 | |
| 
 | |
| function socketToAddr(socket) {
 | |
|   return { family: socket.remoteFamily, address: socket.remoteAddress, port: socket.remotePort };
 | |
| }
 | |
| 
 | |
| function addrToId(address) {
 | |
|   return address.family + ',' + address.address + ',' + address.port;
 | |
| }
 | |
| 
 | |
| function socketToId(socket) {
 | |
|   return addrToId(socketToAddr(socket));
 | |
| }
 | |
| 
 | |
| //require('cluster-store').create().then(function (/*store*/) {
 | |
|   // initialization is now complete
 | |
|   //store.set('foo', 'bar');
 | |
| 
 | |
|   var remotes = {};
 | |
| 
 | |
|   setInterval(function () {
 | |
|     Object.keys(remotes).forEach(function (id) {
 | |
|       var remote = remotes[id];
 | |
| 
 | |
|       console.log('Remote ', id, 'has', Object.keys(remote.clients).length, 'clients', remote.socket.bytesRead, remote.socket.bytesWritten);
 | |
|       /*
 | |
|       forEach(function (cid) {
 | |
|         var client = remote.clients[cid];
 | |
|       });
 | |
|       */
 | |
|     });
 | |
|   }, 5000);
 | |
| 
 | |
|   var server443 = net.createServer(function (browser) {
 | |
|     browser.once('data', function (hello) {
 | |
|       //require('fs').writeFileSync('/tmp/sni.hello.bin', hello);
 | |
|       var servername = sni(hello);
 | |
|       var remote = remotes[servername];
 | |
|       if (!remote) {
 | |
|         console.log("no remote for '" + servername + "'");
 | |
|         browser.end();
 | |
|         return;
 | |
|       }
 | |
|       var address = socketToAddr(browser);
 | |
|       var id = addrToId(address);
 | |
|       var wrapForRemote = new MyTransform({ id: id, remoteId: remote.id, address: address, servername: servername });
 | |
| 
 | |
|       //socket.unshift(hello);
 | |
| 
 | |
|       //remote.socket/*.pipe(transform)*/.pipe(socket, { end: false });
 | |
|       var bstream = browser.pipe(wrapForRemote);
 | |
|       /*
 | |
|       function write() {
 | |
|         console.log("client '" + address.address + "' writing to '" + servername + "'");
 | |
|         var bytes = browser.read();
 | |
|         if (bytes) {
 | |
|           console.log("wrote ", bytes.byteLength);
 | |
|           remote.socket.write(bytes, write);
 | |
|         }
 | |
|         else {
 | |
|           console.log("nothing to write right now");
 | |
|         }
 | |
|       }
 | |
|       bstream.on('readable', write);
 | |
|       */
 | |
|       bstream.on('data', function (chunk) {
 | |
|         console.log("client '" + address.address + "' writing to '" + servername + "'", chunk.byteLength);
 | |
|         remote.socket.write(chunk);
 | |
|       });
 | |
| 
 | |
|       var data = packer.pack(address, hello);
 | |
|       console.log("client '" + address.address + "' greeting '" + servername + "'", hello.byteLength, data.byteLength);
 | |
|       remote.socket.write(data);
 | |
| 
 | |
|       remote.clients[id] = browser;
 | |
|       bstream.on('error', function () {
 | |
|         console.error("browser has erred");
 | |
|         //wrapForRemote.write('|_ERROR_|');
 | |
|         delete remote.clients[id];
 | |
|       });
 | |
|       bstream.on('end', function () {
 | |
|         console.log("browser has closed the socket");
 | |
|         //wrapForRemote.write('|_END_|');
 | |
|         delete remote.clients[id];
 | |
|       });
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   server443.listen(443, function () {
 | |
|     console.log('listening on 443');
 | |
|   });
 | |
| 
 | |
|   var server5443 = net.createServer(function (rserver) {
 | |
|     rserver.once('data', function (hello) {
 | |
|       var token;
 | |
|       try {
 | |
|         token = jwt.decode(hello.toString('utf8'));
 | |
|         console.log(token);
 | |
|       } catch(e) {
 | |
|         rserver.end();
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       if (!token.name) {
 | |
|         console.log("no 'name' in token");
 | |
|         rserver.end();
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       var remote = {
 | |
|         socket: rserver
 | |
|       , id: socketToId(rserver)
 | |
|       , clients: {}
 | |
|       };
 | |
|       var unpacker = packer.create({ onMessage: function (opts) {
 | |
|         // opts.data
 | |
|         var id = addrToId(opts);
 | |
| 
 | |
|         console.log("remote '" + remote.id + "' has data for '" + id + "'", opts.data.byteLength);
 | |
| 
 | |
|         if (!remote.clients[id]) {
 | |
|           console.log('no client for', id, opts.data.toString('utf8').substr(0, 100));
 | |
|           //remote.socket.write(packer.pack(opts, Buffer.from('|__END__|')));
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|         remote.clients[id].write(opts.data);
 | |
|       } });
 | |
| 
 | |
|       console.log('new remote:', token.name);
 | |
|       /*
 | |
|       var data = packer.pack({ family: 'IPv4', address: '254.254.254.1', port: 443 }, Buffer.from(remote.id));
 | |
| 
 | |
|       rserver.write(data, function () {
 | |
|         remotes[token.name] = remote;
 | |
|       });
 | |
|       */
 | |
| 
 | |
|       remotes[token.name] = remote;
 | |
|       rserver.on('data', function (chunk) {
 | |
|         unpacker.fns.addChunk(chunk);
 | |
|       });
 | |
| 
 | |
|       function closeEm() {
 | |
|         console.log("closing connection to '" + token.name + "'");
 | |
|         delete remotes[token.name];
 | |
| 
 | |
|         Object.keys(remote.clients).forEach(function (cid) {
 | |
|           remote.clients[cid].end();
 | |
|           delete remote.clients[cid];
 | |
|         });
 | |
| 
 | |
|         //remote = null;
 | |
|         //rserver = null;
 | |
|         //unpacker = null;
 | |
|       }
 | |
| 
 | |
|       rserver.on('end', closeEm);
 | |
|       rserver.on('error', closeEm);
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   server5443.listen(5443, function () {
 | |
|     console.log('listening on 5443');
 | |
|   });
 | |
| 
 | |
| 
 | |
|   var http80 = require('http').createServer();
 | |
|   http80.on('request', function (req, res) {
 | |
|     res.end('Happy Day!');
 | |
|   });
 | |
| 
 | |
|   var server80 = net.createServer(function (client) {
 | |
|     http80.emit('connection', client);
 | |
|   });
 | |
|   server80.listen(80, function () {
 | |
|     console.log('listening on 80');
 | |
|   });
 | |
| //});
 |