Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

stunnel

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

stunnel - npm Package Compare versions

Comparing version 0.8.0 to 0.8.1

37

bin/stunnel.js

@@ -0,1 +1,2 @@

#!/usr/bin/env node
(function () {

@@ -7,2 +8,3 @@ 'use strict';

var program = require('commander');
var url = require('url');
var stunnel = require('../wsclient.js');

@@ -37,3 +39,5 @@

};
}).forEach(memo.push);
}).forEach(function (val) {
memo.push(val);
});

@@ -50,14 +54,32 @@ return memo;

})
.option('-k --insecure', 'Allow TLS connections to stunneld without valid certs (H)')
.option('-k --insecure', 'Allow TLS connections to stunneld without valid certs (rejectUnauthorized: false)')
.option('--locals <LINE>', 'comma separated list of <proto>:<//><servername>:<port> to which matching incoming http and https should forward (reverse proxy). Ex: https://john.example.com,tls:*:1337', collectProxies, [ ]) // --reverse-proxies
.option('--stunneld <URL>', '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)')
.option('--secret <STRING>', 'the same secret used by stunneld (used for JWT authentication)')
.option('--token <STRING>', 'a pre-generated token for use with stunneld (instead of generating one with --secret)')
.parse(process.argv)
;
// Assumption: will not get next tcp packet unless previous packet succeeded
var hostname = 'aj.daplie.me'; // 'pokemap.hellabit.com'
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 = {};

@@ -68,4 +90,3 @@ program.locals.forEach(function (proxy) {

});
program.token = program.token || jwt.sign({ name: hostname }, program.secret || 'shhhhh');
program.stunneld = program.stunneld || 'wss://pokemap.hellabit.com:3000';
program.token = program.token || jwt.sign(tokenData, program.secret || 'shhhhh');

@@ -72,0 +93,0 @@ stunnel.connect(program);

{
"name": "stunnel",
"version": "0.8.0",
"version": "0.8.1",
"description": "A pure-JavaScript tunnel client for http and https similar to localtunnel.me, 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.",

@@ -8,2 +8,3 @@ "main": "wsclient.js",

"jstunnel": "bin/stunnel.js",
"stunnel.js": "bin/stunnel.js",
"stunnel-js": "bin/stunnel.js"

@@ -19,2 +20,4 @@ },

"keywords": [
"cli",
"client",
"tcp",

@@ -21,0 +24,0 @@ "tls",

# stunnel.js
Works in combination with [stunneld.js](https://github.com/Daplie/node-tunnel-server)
to allow you to serve http and https from provide a secure tunnelA paired client for our node tunnel server
A client that works in combination with [stunneld.js](https://github.com/Daplie/node-tunnel-server)
to allow you to serve http and https from any computer, anywhere through a secure tunnel.

@@ -6,0 +6,0 @@ CLI

@@ -7,2 +7,4 @@ (function () {

var sni = require('sni');
var pack = require('tunnel-packer').pack;
var authenticated = false;

@@ -35,133 +37,124 @@ // TODO move these helpers to tunnel-packer package

function run(copts) {
var services = copts.services; // TODO pair with hostname / sni
var token = copts.token;
var tunnelUrl = copts.stunneld + '/?access_token=' + token;
var wstunneler;
var retry = true;
var localclients = {};
wstunneler = new WebSocket(tunnelUrl, { rejectUnauthorized: false });
function run(copts) {
var services = copts.services; // TODO pair with hostname / sni
var token = copts.token;
var tunnelUrl = copts.stunneld + '/?access_token=' + token;
var wstunneler;
var retry = true;
var localclients = {};
// BaaS / Backendless / noBackend / horizon.io
// user authentication
// a place to store data
// file management
// Synergy Teamwork Paradigm = Jabberwocky
var handlers = {
onmessage: function (opts) {
var cid = addrToId(opts);
var service = opts.service;
var port = services[service];
var servername;
var str;
var m;
function onOpen() {
console.log('[open] tunneler connected');
authenticated = true;
/*
setInterval(function () {
console.log('');
console.log('localclients.length:', Object.keys(localclients).length);
console.log('');
}, 5000);
*/
if (localclients[cid]) {
//console.log("[=>] received data from '" + cid + "' =>", opts.data.byteLength);
localclients[cid].write(opts.data);
return;
}
else if ('http' === service) {
str = opts.data.toString();
m = str.match(/(?:^|[\r\n])Host: ([^\r\n]+)[\r\n]*/im);
servername = (m && m[1].toLowerCase() || '').split(':')[0];
}
else if ('https' === service) {
servername = sni(opts.data);
}
else {
handlers._onLocalError(cid, opts, new Error("unsupported service '" + service + "'"));
return;
}
//wstunneler.send(token);
if (!servername) {
console.info("[error] missing servername for '" + cid + "'", opts.data.byteLength);
//console.warn(opts.data.toString());
wstunneler.send(pack(opts, null, 'error'), { binary: true });
return;
}
// BaaS / Backendless / noBackend / horizon.io
// user authentication
// a place to store data
// file management
// Synergy Teamwork Paradigm = Jabberwocky
var pack = require('tunnel-packer').pack;
var handlers = {
onmessage: function (opts) {
var cid = addrToId(opts);
console.log('[wsclient] onMessage:', cid);
var service = opts.service;
var port = services[service];
var lclient;
var servername;
var str;
var m;
console.info("[connect] new client '" + cid + "' for '" + servername + "' (" + (handlers._numClients() + 1) + " clients)");
function endWithError() {
try {
wstunneler.send(pack(opts, null, 'error'), { binary: true });
} catch(e) {
// ignore
}
}
if (localclients[cid]) {
console.log("[=>] received data from '" + cid + "' =>", opts.data.byteLength);
localclients[cid].write(opts.data);
return;
}
else if ('http' === service) {
str = opts.data.toString();
m = str.match(/(?:^|[\r\n])Host: ([^\r\n]+)[\r\n]*/im);
servername = (m && m[1].toLowerCase() || '').split(':')[0];
}
else if ('https' === service) {
servername = sni(opts.data);
}
else {
endWithError();
return;
}
if (!servername) {
console.warn("|__ERROR__| no servername found for '" + cid + "'", opts.data.byteLength);
//console.warn(opts.data.toString());
wstunneler.send(pack(opts, null, 'error'), { binary: true });
return;
}
console.log("servername: '" + servername + "'");
lclient = localclients[cid] = net.createConnection({ port: port, host: '127.0.0.1' }, function () {
console.log("[=>] first packet from tunneler to '" + cid + "' as '" + opts.service + "'", opts.data.byteLength);
lclient.write(opts.data);
});
lclient.on('data', function (chunk) {
console.log("[<=] local '" + opts.service + "' sent to '" + cid + "' <= ", chunk.byteLength, "bytes");
//console.log(JSON.stringify(chunk.toString()));
wstunneler.send(pack(opts, chunk), { binary: true });
});
lclient.on('error', function (err) {
console.error("[error] local '" + opts.service + "' '" + cid + "'");
console.error(err);
delete localclients[cid];
try {
wstunneler.send(pack(opts, null, 'error'), { binary: true });
} catch(e) {
// ignore
}
});
lclient.on('end', function () {
console.log("[end] local '" + opts.service + "' '" + cid + "'");
delete localclients[cid];
try {
wstunneler.send(pack(opts, null, 'end'), { binary: true });
} catch(e) {
// ignore
}
});
localclients[cid] = net.createConnection({ port: port, host: '127.0.0.1' }, function () {
//console.log("[=>] first packet from tunneler to '" + cid + "' as '" + opts.service + "'", opts.data.byteLength);
localclients[cid].write(opts.data);
});
localclients[cid].on('data', function (chunk) {
//console.log("[<=] local '" + opts.service + "' sent to '" + cid + "' <= ", chunk.byteLength, "bytes");
//console.log(JSON.stringify(chunk.toString()));
wstunneler.send(pack(opts, chunk), { binary: true });
});
localclients[cid].on('error', function (err) {
handlers._onLocalError(cid, opts, err);
});
localclients[cid].on('end', function () {
console.info("[end] closing client '" + cid + "' for '" + servername + "' (" + (handlers._numClients() - 1) + " clients)");
handlers._onLocalClose(cid, opts);
});
}
, onend: function (opts) {
var cid = addrToId(opts);
//console.log("[end] '" + cid + "'");
handlers._onend(cid);
}
, onerror: function (opts) {
var cid = addrToId(opts);
//console.log("[error] '" + cid + "'", opts.code || '', opts.message);
handlers._onend(cid);
}
, _onend: function (cid) {
if (localclients[cid]) {
try {
localclients[cid].end();
} catch(e) {
// ignore
}
, onend: function (opts) {
var cid = addrToId(opts);
console.log("[end] '" + cid + "'");
handlers._onend(cid);
}
, onerror: function (opts) {
var cid = addrToId(opts);
console.log("[error] '" + cid + "'", opts.code || '', opts.message);
handlers._onend(cid);
}
, _onend: function (cid) {
if (localclients[cid]) {
localclients[cid].end();
}
delete localclients[cid];
}
};
var machine = require('tunnel-packer').create(handlers);
wstunneler.on('message', machine.fns.addChunk);
}
delete localclients[cid];
}
, _onLocalClose: function (cid, opts, err) {
try {
wstunneler.send(pack(opts, null, err && 'error' || 'end'), { binary: true });
} catch(e) {
// ignore
}
delete localclients[cid];
}
, _onLocalError: function (cid, opts, err) {
console.info("[error] closing '" + cid + "' because '" + err.message + "' (" + (handlers._numClients() - 1) + " clients)");
handlers._onLocalClose(cid, opts, err);
}
, _numClients: function () {
return Object.keys(localclients).length;
}
};
var wsHandlers = {
onOpen: function () {
console.info("[open] connected to '" + copts.stunneld + "'");
}
wstunneler.on('open', onOpen);
, onClose: function () {
if (!authenticated) {
console.info('[close] failed on first attempt... check authentication.');
}
else if (retry) {
console.info('[retry] disconnected and waiting...');
setTimeout(run, 5000, copts);
}
else {
console.info('[close] closing tunnel to exit...');
}
wstunneler.on('close', function () {
console.log('closing tunnel...');
process.removeListener('exit', onExit);
process.removeListener('SIGINT', onExit);
process.removeListener('exit', wsHandlers.onExit);
process.removeListener('SIGINT', wsHandlers.onExit);
Object.keys(localclients).forEach(function (cid) {

@@ -173,23 +166,17 @@ try {

}
delete localclients[cid];
});
}
if (retry) {
console.log('retry on close');
setTimeout(run, 5000);
}
});
wstunneler.on('error', function (err) {
console.error("[error] will retry on 'close'");
, onError: function (err) {
console.error("[tunnel error] " + err.message);
console.error(err);
});
}
function onExit() {
, onExit: function () {
retry = false;
console.log('on exit...');
try {
wstunneler.close();
} catch(e) {
console.error("[error] wstunneler.close()");
console.error(e);

@@ -199,8 +186,24 @@ // ignore

}
};
var machine = require('tunnel-packer').create(handlers);
process.on('exit', onExit);
process.on('SIGINT', onExit);
}
console.info("[connect] '" + copts.stunneld + "'");
module.exports.connect = run;
wstunneler = new WebSocket(tunnelUrl, { rejectUnauthorized: !copts.insecure });
wstunneler.on('open', wsHandlers.onOpen);
wstunneler.on('message', function (data, flags) {
if (data.error || '{' === data[0]) {
console.log(data);
return;
}
machine.fns.addChunk(data, flags);
});
wstunneler.on('close', wsHandlers.onClose);
wstunneler.on('error', wsHandlers.onError);
process.on('exit', wsHandlers.onExit);
process.on('SIGINT', wsHandlers.onExit);
}
module.exports.connect = run;
}());
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc