From 1287ccc1ce5fecbe3991da323b8af170af40737a Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 3 Sep 2018 15:29:19 -0600 Subject: [PATCH] v1.2.0: bring up to par with sclient.go; add --servername, allow pipes, use - for stdin --- README.md | 33 ++++++++++++++++++++++++-- bin/sclient.js | 63 +++++++++++++++++++++++++++++++++++++++----------- index.js | 28 +++++++++++++++++----- package.json | 2 +- 4 files changed, 104 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 3b3cc9f..532a1ee 100644 --- a/README.md +++ b/README.md @@ -51,9 +51,12 @@ Usage ===== ```bash -sclient [-k | --insecure] +sclient [flags] ``` +* flags + * -k, --insecure ignore invalid TLS (SSL/HTTPS) certificates + * --servername spoof SNI (to disable use IP as <remote> and do not use this option) * remote * must have servername (i.e. example.com) * port is optional (default is 443) @@ -79,5 +82,31 @@ sclient telebit.cloud:443 localhost:3000 Ignore a bad TLS/SSL/HTTPS certificate and connect anyway. ```bash -sclient badtls.telebit.cloud:443 localhost:3000 -k +sclient -k badtls.telebit.cloud:443 localhost:3000 +``` + +Reading from stdin + +```bash +sclient telebit.cloud:443 - +``` + +```bash +sclient telebit.cloud:443 - [-k | --insecure]"); + console.info("Usage: sclient [--servername ] [-k | --insecure] "); console.info(" ex: sclient whatever.com 3000"); console.info(" (whatever.com:443 localhost:3000)"); console.info(" ex: sclient whatever.com:4080 0.0.0.0:3000"); console.info(""); - process.exit(0); } +function parseFlags() { + process.argv.some(function (arg, i) { + if (/^-k|--?insecure$/.test(arg)) { + rejectUnauthorized = false; + process.argv.splice(i, 1); + return true; + } + }); + process.argv.some(function (arg, i) { + if (/^--?servername$/.test(arg)) { + servername = process.argv[i + 1]; + if (!servername || /^-/.test(servername)) { + usage(); + process.exit(2); + } + process.argv.splice(i, 2); + return true; + } + }); +} + +parseFlags(); + +remote = (process.argv[2]||'').split(':'); +local = (process.argv[3]||'').split(':'); + +// arg 0 is node +// arg 1 is sclient +// arg 2 is remote +// arg 3 is local +if (4 !== process.argv.length) { + if (isPiped) { + local = ['|']; + } else { + usage(); + process.exit(1); + } +} + +// Check for the first argument (what to connect to) if (!remote[0]) { usage(); return; } -if (!remote[1]) { - remote[1] = 443; -} if (!local[0]) { usage(); @@ -34,24 +72,23 @@ if (local[0] === String(parseInt(local[0], 10))) { localPort = parseInt(local[0], 10); localAddress = 'localhost'; } else { - localAddress = local[0]; + localAddress = local[0]; // potentially '-' or '|' localPort = parseInt(local[1], 10); } -if (!localPort) { +if ('-' === localAddress || '|' === localAddress) { + // no need for port +} else if (!localPort) { usage(); return; } -if (/^-k|--insecure$/.test(process.argv[4])) { - rejectUnauthorized = false; -} - var opts = { remoteAddr: remote[0] , remotePort: remote[1] , localAddress: localAddress , localPort: localPort , rejectUnauthorized: rejectUnauthorized +, servername: servername }; require('../')(opts); diff --git a/index.js b/index.js index 7a815a5..10d8252 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,7 @@ var net = require('net'); var tls = require('tls'); function listenForConns(opts) { - var server = net.createServer(function (c) { + function pipeConn(c, out) { var sclient = tls.connect({ servername: opts.remoteAddr, host: opts.remoteAddr, port: opts.remotePort , rejectUnauthorized: opts.rejectUnauthorized @@ -12,7 +12,7 @@ function listenForConns(opts) { console.info('[connect] ' + sclient.localAddress.replace('::1', 'localhost') + ":" + sclient.localPort + " => " + opts.remoteAddr + ":" + opts.remotePort); c.pipe(sclient); - sclient.pipe(c); + sclient.pipe(out || c); }); sclient.on('error', function (err) { console.error('[error] (remote) ' + err.toString()); @@ -20,7 +20,19 @@ function listenForConns(opts) { c.on('error', function (err) { console.error('[error] (local) ' + err.toString()); }); - }); + if (out) { + out.on('error', function (err) { + console.error('[error] (local) ' + err.toString()); + }); + } + } + + if ('-' === opts.localAddress || '|' === opts.localAddress) { + pipeConn(process.stdin, process.stdout); + return; + } + + var server = net.createServer(pipeConn); server.on('error', function (err) { console.error('[error] ' + err.toString()); }); @@ -35,10 +47,14 @@ function listenForConns(opts) { function testConn(opts) { // Test connection first - var tlsSock = tls.connect({ - servername: opts.remoteAddr, host: opts.remoteAddr, port: opts.remotePort + var tlsOpts = { + host: opts.remoteAddr, port: opts.remotePort , rejectUnauthorized: opts.rejectUnauthorized - }, function () { + }; + if (opts.servername) { + tlsOpts.servername = opts.servername; + } + var tlsSock = tls.connect(tlsOpts, function () { tlsSock.end(); listenForConns(opts); }); diff --git a/package.json b/package.json index 0e1cdbd..52ce9a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sclient", - "version": "1.0.4", + "version": "1.2.0", "description": "Secure Client for exposing TLS (aka SSL) secured services as plain-text connections locally. Also ideal for multiplexing a single port with multiple protocols using SNI.", "main": "index.js", "homepage": "https://git.coolaj86.com/coolaj86/sclient.js",