Break out of localhost. Access your devices from behind firewalls. Securely access your services from anywhere. An easy-to-use secure tunnel for all sorts of wonderful things (kind of like a poor man's VPN).
Go to file
AJ ONeal d4cd0bb5a6 working 2016-10-12 12:59:13 -06:00
bin fixes 2016-10-11 17:43:24 -06:00
snippets moving towards release 2016-09-30 12:33:38 -04:00
.gitignore moving towards release 2016-09-30 12:33:38 -04:00
LICENSE Initial commit 2016-09-21 18:42:26 -06:00
README.md fix streams typo 2016-10-11 15:43:09 -06:00
TODO.md moving towards release 2016-09-30 12:33:38 -04:00
client.js demo works 2016-09-22 16:18:35 -06:00
httpsclient.js move https from ws 2016-10-11 17:29:34 -06:00
package.json update tunnel-packer version 2016-10-06 16:36:51 -06:00
wsclient.js working 2016-10-12 12:59:13 -06:00

README.md

stunnel.js

A client that works in combination with stunneld.js to allow you to serve http and https from any computer, anywhere through a secure tunnel.

  • CLI
  • Library

CLI

Installs as stunnel.js with the alias jstunnel (for those that regularly use stunnel but still like commandline completion).

Install

npm install -g stunnel

Advanced Usage

How to use stunnel.js with your own instance of stunneld.js:

stunnel.js --locals john.example.com --stunneld wss://tunnel.example.com:443 --secret abc123
stunnel.js \
  --locals http:john.example.com:3000,https:john.example.com \
  --stunneld wss://tunnel.example.com:443 \
  --secret abc123
--secret          the same secret used by stunneld (used for authentication)
--locals          comma separated list of <proto>:<servername>:<port> to which
                  incoming http and https should be forwarded
--stunneld        the domain or ip address at which you are running stunneld.js
-k, --insecure    ignore invalid ssl certificates from stunneld

Usage

NOT YET IMPLEMENTED

Daplie's tunneling service is not yet publicly available.

Terms of Service: The Software and Services shall be used for Good, not Evil. Examples of good: education, business, pleasure. Examples of evil: crime, abuse, extortion.

stunnel.js --agree-tos --email john@example.com --locals http:john.example.com:4080,https:john.example.com:8443

Library

Example

var stunnel = require('stunnel');

stunnel.connect({
  stunneld: 'wss://tunnel.example.com'
, token: '...'
, locals: [
    // defaults to sending http to local port 80 and https to local port 443
    { hostname: 'doe.net' }

    // sends both http and https to local port 3000 (httpolyglot)
  , { protocol: 'https', hostname: 'john.doe.net', port: 3000 }

    // send http to local port 4080 and https to local port 8443
  , { protocol: 'https', hostname: 'jane.doe.net', port: 4080 }
  , { protocol: 'https', hostname: 'jane.doe.net', port: 8443 }
  ]

, net: require('net')
, insecure: false
});
  • You can get sneaky with net and provide a createConnection that returns a stream.Duplex.

Token

var tokenData = { domains: [ 'doe.net', 'john.doe.net', 'jane.doe.net' ] }
var secret = 'shhhhh';
var token = jwt.sign(tokenData, secret);

net

Let's say you want to handle http requests in-process or decrypt https before passing it to the local http handler.

You'll need to create a pair of streams to connect between the local handler and the tunnel handler.

You could do a little magic like this:

var Dup = {
  write: function (chunk, encoding, cb) {
    this.__my_socket.write(chunk, encoding);
    cb();
  }
, read: function (size) {
    var x = this.__my_socket.read(size);
    if (x) { this.push(x); }
  }
};

stunnel.connect({
  // ...
, net: {
  createConnection: function (info, cb) {
    // data is the hello packet / first chunk
    // info = { data, servername, port, host, remoteAddress: { family, address, port } }

    var myDuplex = new (require('stream').Duplex)();
    var myDuplex2 = new (require('stream').Duplex)();
    // duplex = { write, push, end, events: [ 'readable', 'data', 'error', 'end' ] };

    myDuplex2.__my_socket = myDuplex;
    myDuplex2._write = Dup.write;
    myDuplex2._read = Dup.read;

    myDuplex.__my_socket = myDuplex2;
    myDuplex._write = Dup.write;
    myDuplex._read = Dup.read;

    myDuplex.remoteFamily = info.remoteFamily;
    myDuplex.remoteAddress = info.remoteAddress;
    myDuplex.remotePort = info.remotePort;

    // socket.local{Family,Address,Port}
    myDuplex.localFamily = 'IPv4';
    myDuplex.localAddress = '127.0.01';
    myDuplex.localPort = info.port;

    httpsServer.emit('connection', myDuplex);

    if (cb) {
      process.nextTick(cb);
    }

    return myDuplex2;
  }
});