From 2825afbb13d97ca82deee626d336374fd2aa217a Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Fri, 30 Sep 2016 18:03:41 -0400 Subject: [PATCH] fs cleanup --- .gitignore | 2 + bin/stunneld.js | 91 +++++++++++++++++++++++++++++++ package.json | 35 ++++++++++-- mux-tcp.js => snippets/mux-tcp.js | 0 serve.js => snippets/serve.js | 0 snippets/serve80.js | 59 ++++++++++++++++++++ snippets/tcp-spy.js | 33 +++++++++++ snippets/tls-spy.js | 47 ++++++++++++++++ snippets/wss.js | 36 ++++++++++++ mux-ws.js => wstunneld.js | 0 10 files changed, 298 insertions(+), 5 deletions(-) create mode 100755 bin/stunneld.js rename mux-tcp.js => snippets/mux-tcp.js (100%) rename serve.js => snippets/serve.js (100%) create mode 100644 snippets/serve80.js create mode 100644 snippets/tcp-spy.js create mode 100644 snippets/tls-spy.js create mode 100644 snippets/wss.js rename mux-ws.js => wstunneld.js (100%) diff --git a/.gitignore b/.gitignore index 5148e52..7184f26 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +node_modules.* + # Logs logs *.log diff --git a/bin/stunneld.js b/bin/stunneld.js new file mode 100755 index 0000000..feb2479 --- /dev/null +++ b/bin/stunneld.js @@ -0,0 +1,91 @@ +#!/usr/bin/env node +(function () { +'use strict'; + +var pkg = require('../package.json'); + +var program = require('commander'); +var url = require('url'); +var stunneld = require('../wstunneld.js'); + +function collectProxies(val, memo) { + var vals = val.split(/,/g); + vals.map(function (location) { + // http:john.example.com:3000 + // http://john.example.com:3000 + var parts = location.split(':'); + parts[0] = parts[0].toLowerCase(); + parts[1] = parts[1].toLowerCase().replace(/(\/\/)?/, '') || '*'; + parts[2] = parseInt(parts[2], 10) || 0; + if (!parts[2]) { + // TODO grab OS list of standard ports? + if ('http' === parts[0]) { + parts[2] = 80; + } + else if ('https' === parts[0]) { + parts[2] = 443; + } + else { + throw new Error("port must be specified - ex: tls:*:1337"); + } + } + + return { + protocol: parts[0] + , hostname: parts[1] + , port: parts[2] + }; + }).forEach(function (val) { + memo.push(val); + }); + + return memo; +} + +program + .version(pkg.version) + //.command('jsurl ') + .arguments('') + .action(function (url) { + program.url = url; + }) + .option('-k --insecure', 'Allow TLS connections to stunneld without valid certs (rejectUnauthorized: false)') + .option('--locals ', 'comma separated list of :: to which matching incoming http and https should forward (reverse proxy). Ex: https://john.example.com,tls:*:1337', collectProxies, [ ]) // --reverse-proxies + .option('--stunneld ', 'the domain (or ip address) at which you are running stunneld.js (the proxy)') // --proxy + .option('--secret ', 'the same secret used by stunneld (used for JWT authentication)') + .option('--token ', 'a pre-generated token for use with stunneld (instead of generating one with --secret)') + .parse(process.argv) + ; + +program.stunneld = program.stunneld || 'wss://pokemap.hellabit.com:3000'; + +var jwt = require('jsonwebtoken'); +var domainsMap = {}; +var tokenData = { + name: null +, domains: null +}; +var location = url.parse(program.stunneld); + +if (!location.protocol || /\./.test(location.protocol)) { + program.stunneld = 'wss://' + program.stunneld; + location = url.parse(program.stunneld); +} +program.stunneld = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : ''); + +program.locals.forEach(function (proxy) { + domainsMap[proxy.hostname] = true; +}); +tokenData.domains = Object.keys(domainsMap); +tokenData.name = tokenData.domains[0]; + +program.services = {}; +program.locals.forEach(function (proxy) { + //program.services = { 'ssh': 22, 'http': 80, 'https': 443 }; + program.services[proxy.protocol] = proxy.port; +}); +program.token = program.token || jwt.sign(tokenData, program.secret || 'shhhhh'); + +stunnel.connect(program); + +}()); diff --git a/package.json b/package.json index 55ceb2a..b72f586 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,13 @@ { - "name": "tunnel-server", - "version": "1.0.0", - "description": "A naive tcp tunnel server", - "main": "serve.js", + "name": "stunneld", + "version": "0.8.0", + "description": "A pure-JavaScript tunnel daemon for http and https similar to a localtunnel.me server, but uses TLS (SSL) with ServerName Indication (SNI) over https to work even in harsh network conditions such as in student dorms and behind HOAs, corporate firewalls, public libraries, airports, airplanes, etc. Can also tunnel tls and plain tcp.", + "main": "wstunneld.js", + "bin": { + "jstunneld": "bin/stunneld.js", + "stunneld.js": "bin/stunneld.js", + "stunneld-js": "bin/stunneld.js" + }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, @@ -11,8 +16,28 @@ "url": "git+https://github.com/Daplie/node-tunnel-server.git" }, "keywords": [ + "server", + "daemon", "tcp", - "tunnel" + "tls", + "http", + "https", + "sni", + "servername", + "indication", + "stunnel", + "secure", + "securetunnel", + "secure-tunnel", + "tunnel", + "localtunnel", + "localtunnel.me", + "proxy", + "reverse", + "reverse-proxy", + "reverseproxy", + "vpn", + "sni" ], "author": "AJ ONeal (https://coolaj86.com/)", "license": "(MIT OR Apache-2.0)", diff --git a/mux-tcp.js b/snippets/mux-tcp.js similarity index 100% rename from mux-tcp.js rename to snippets/mux-tcp.js diff --git a/serve.js b/snippets/serve.js similarity index 100% rename from serve.js rename to snippets/serve.js diff --git a/snippets/serve80.js b/snippets/serve80.js new file mode 100644 index 0000000..b9f2680 --- /dev/null +++ b/snippets/serve80.js @@ -0,0 +1,59 @@ +'use strict'; + +var net = require('net'); +var tls = require('tls'); +var http = require('http'); +var https = require('https'); +var sni = require('sni'); + +var http80 = http.createServer(function (req, res) { + res.end('Happy Day!'); +}); + +var tcp80 = net.createServer(function (client) { + http80.emit('connection', client); +}); + +tcp80.listen(80, function () { + console.log('listening on 80'); +}); + +var tlsOpts = require('localhost.daplie.com-certificates').merge({}); +var https443 = https.createServer(tlsOpts, function (req, res) { + res.end('Happy Encrypted Day!'); +}); + +var tls443 = tls.createServer(tlsOpts, function (socket) { + socket.on('data', function (chunk) { + console.log('chunk', chunk.toString()); + }); +}); + +var tcp443 = net.createServer(function (client) { + //tls443.emit('connection', client); // no go + //return; + + client.once('data', function (chunk) { + var servername = sni(chunk); + + console.log('servername:', servername); + + //client.push(chunk); + + https443.emit('connection', client); + //tls443.emit('connection', client); // no go + //client.pause(); + process.nextTick(function () { + //client.emit('data', chunk); + client.push(chunk); + client.emit('readable', chunk); + //client.resume(); + }); + + //client.resume(); + }); +}); + +tcp443.listen(443, function () { + console.log('listening on 443'); +}); diff --git a/snippets/tcp-spy.js b/snippets/tcp-spy.js new file mode 100644 index 0000000..7dedabe --- /dev/null +++ b/snippets/tcp-spy.js @@ -0,0 +1,33 @@ +'use strict'; + +var net = require('net'); +var http = require('http'); + +var http80 = http.createServer(function (req, res) { + res.end('Hello, World!'); +}); + +var tcp80 = net.createServer(function (socket) { + + socket.once('data', function (chunk) { + + if (/http\/1/i.test(chunk.toString())) { + console.log("looks like http, continue"); + http80.emit('connection', socket); + } else { + console.log("looks like tcp, die"); + socket.end(); + } + + socket.pause(); + process.nextTick(function () { + socket.emit('data', chunk); + socket.resume(); + }); + }); + +}); + +tcp80.listen(80, function () { + console.log('listening on 80'); +}); diff --git a/snippets/tls-spy.js b/snippets/tls-spy.js new file mode 100644 index 0000000..4670a97 --- /dev/null +++ b/snippets/tls-spy.js @@ -0,0 +1,47 @@ +'use strict'; + +var net = require('net'); +var tls = require('tls'); +var http = require('http'); +var sni = require('sni'); +var https = require('https'); +var tlsOpts = require('localhost.daplie.com-certificates').merge({}); + +var http80 = http.createServer(function (req, res) { + res.end('Hello, World!'); +}); + +var https443 = https.createServer(tlsOpts, function (req, res) { + res.end('Hello, Encrypted World!'); +}); + +var tcp3000 = net.createServer(function (socket) { + + socket.once('data', function (chunk) { + + if (/http\/1/i.test(chunk.toString())) { + console.log("looks like http, continue"); + http80.emit('connection', socket); + } else { + console.log("doesn't look like http, try tls"); + https443.emit('connection', socket); + var tlsSocket = new tls.TLSSocket(socket, { secureContext: tls.createSecureContext(tlsOpts) }); + tlsSocket.on('data', function (chunk) { + console.log('chunk', chunk); + }); + socket.emit('connect'); + //http80.emit('connection', socket); + } + + socket.pause(); + process.nextTick(function () { + socket.emit('data', chunk); + socket.resume(); + }); + }); + +}); + +tcp3000.listen(3000, function () { + console.log('listening on 3000'); +}); diff --git a/snippets/wss.js b/snippets/wss.js new file mode 100644 index 0000000..77bd025 --- /dev/null +++ b/snippets/wss.js @@ -0,0 +1,36 @@ +(function () { +'use strict'; + +function app(req, res) { + console.log('hello'); + res.send({ msg: "hello" }); +} + +var tlsOpts = require('localhost.daplie.com-certificates').merge({}); +var url = require('url'); +var WebSocketServer = require('ws').Server; +var server = require('https').createServer(tlsOpts, app); +var wss = new WebSocketServer({ server: server }); +//var express = require('express'); +//var app = express(); +var port = 3000; + +wss.on('connection', function connection(ws) { + console.log('connection'); + var location = url.parse(ws.upgradeReq.url, true); + + console.log('location.query.access_token'); + console.log(location.query.access_token); + // you might use location.query.access_token to authenticate or share sessions + // or ws.upgradeReq.headers.cookie (see http://stackoverflow.com/a/16395220/151312) + + ws.on('message', function incoming(message) { + console.log('received: %s', message); + }); + + //ws.send('something'); +}); + +server.listen(port, function () { console.log('Listening on ' + server.address().port); }); + +}()); diff --git a/mux-ws.js b/wstunneld.js similarity index 100% rename from mux-ws.js rename to wstunneld.js