v1.2.0: bring up to par with sclient.go; add --servername, allow pipes, use - for stdin
This commit is contained in:
parent
f14708495a
commit
1287ccc1ce
33
README.md
33
README.md
|
@ -51,9 +51,12 @@ Usage
|
||||||
=====
|
=====
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sclient <remote> <local> [-k | --insecure]
|
sclient [flags] <remote> <local>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* flags
|
||||||
|
* -k, --insecure ignore invalid TLS (SSL/HTTPS) certificates
|
||||||
|
* --servername <string> spoof SNI (to disable use IP as <remote> and do not use this option)
|
||||||
* remote
|
* remote
|
||||||
* must have servername (i.e. example.com)
|
* must have servername (i.e. example.com)
|
||||||
* port is optional (default is 443)
|
* 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.
|
Ignore a bad TLS/SSL/HTTPS certificate and connect anyway.
|
||||||
|
|
||||||
```bash
|
```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 - </path/to/file
|
||||||
|
```
|
||||||
|
|
||||||
|
Piping
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "GET / HTTP/1.1\r\nHost: telebit.cloud\r\n\r\n" | sclient telebit.cloud:443
|
||||||
|
```
|
||||||
|
|
||||||
|
Testing for security vulnerabilities on the remote:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sclient --servername "Robert'); DROP TABLE Students;" -k example.com localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sclient --servername "../../../.hidden/private.txt" -k example.com localhost:3000
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,30 +1,68 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var pkg = require('../package.json');
|
var pkg = require('../package.json');
|
||||||
var remote = (process.argv[2]||'').split(':');
|
var remote;
|
||||||
var local = (process.argv[3]||'').split(':');
|
var local;
|
||||||
|
var isPiped = !process.stdin.isTTY;
|
||||||
var localAddress;
|
var localAddress;
|
||||||
var localPort;
|
var localPort;
|
||||||
var rejectUnauthorized;
|
var rejectUnauthorized;
|
||||||
|
var servername;
|
||||||
|
|
||||||
function usage() {
|
function usage() {
|
||||||
console.info("");
|
console.info("");
|
||||||
console.info("sclient.js v" + pkg.version);
|
console.info("sclient.js v" + pkg.version);
|
||||||
console.info("Usage: sclient <servername:port> <port> [-k | --insecure]");
|
console.info("Usage: sclient [--servername <string>] [-k | --insecure] <servername:port> <port>");
|
||||||
console.info(" ex: sclient whatever.com 3000");
|
console.info(" ex: sclient whatever.com 3000");
|
||||||
console.info(" (whatever.com:443 localhost:3000)");
|
console.info(" (whatever.com:443 localhost:3000)");
|
||||||
console.info(" ex: sclient whatever.com:4080 0.0.0.0:3000");
|
console.info(" ex: sclient whatever.com:4080 0.0.0.0:3000");
|
||||||
console.info("");
|
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]) {
|
if (!remote[0]) {
|
||||||
usage();
|
usage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!remote[1]) {
|
|
||||||
remote[1] = 443;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!local[0]) {
|
if (!local[0]) {
|
||||||
usage();
|
usage();
|
||||||
|
@ -34,24 +72,23 @@ if (local[0] === String(parseInt(local[0], 10))) {
|
||||||
localPort = parseInt(local[0], 10);
|
localPort = parseInt(local[0], 10);
|
||||||
localAddress = 'localhost';
|
localAddress = 'localhost';
|
||||||
} else {
|
} else {
|
||||||
localAddress = local[0];
|
localAddress = local[0]; // potentially '-' or '|'
|
||||||
localPort = parseInt(local[1], 10);
|
localPort = parseInt(local[1], 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!localPort) {
|
if ('-' === localAddress || '|' === localAddress) {
|
||||||
|
// no need for port
|
||||||
|
} else if (!localPort) {
|
||||||
usage();
|
usage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/^-k|--insecure$/.test(process.argv[4])) {
|
|
||||||
rejectUnauthorized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var opts = {
|
var opts = {
|
||||||
remoteAddr: remote[0]
|
remoteAddr: remote[0]
|
||||||
, remotePort: remote[1]
|
, remotePort: remote[1]
|
||||||
, localAddress: localAddress
|
, localAddress: localAddress
|
||||||
, localPort: localPort
|
, localPort: localPort
|
||||||
, rejectUnauthorized: rejectUnauthorized
|
, rejectUnauthorized: rejectUnauthorized
|
||||||
|
, servername: servername
|
||||||
};
|
};
|
||||||
require('../')(opts);
|
require('../')(opts);
|
||||||
|
|
26
index.js
26
index.js
|
@ -4,7 +4,7 @@ var net = require('net');
|
||||||
var tls = require('tls');
|
var tls = require('tls');
|
||||||
|
|
||||||
function listenForConns(opts) {
|
function listenForConns(opts) {
|
||||||
var server = net.createServer(function (c) {
|
function pipeConn(c, out) {
|
||||||
var sclient = tls.connect({
|
var sclient = tls.connect({
|
||||||
servername: opts.remoteAddr, host: opts.remoteAddr, port: opts.remotePort
|
servername: opts.remoteAddr, host: opts.remoteAddr, port: opts.remotePort
|
||||||
, rejectUnauthorized: opts.rejectUnauthorized
|
, rejectUnauthorized: opts.rejectUnauthorized
|
||||||
|
@ -12,7 +12,7 @@ function listenForConns(opts) {
|
||||||
console.info('[connect] ' + sclient.localAddress.replace('::1', 'localhost') + ":" + sclient.localPort
|
console.info('[connect] ' + sclient.localAddress.replace('::1', 'localhost') + ":" + sclient.localPort
|
||||||
+ " => " + opts.remoteAddr + ":" + opts.remotePort);
|
+ " => " + opts.remoteAddr + ":" + opts.remotePort);
|
||||||
c.pipe(sclient);
|
c.pipe(sclient);
|
||||||
sclient.pipe(c);
|
sclient.pipe(out || c);
|
||||||
});
|
});
|
||||||
sclient.on('error', function (err) {
|
sclient.on('error', function (err) {
|
||||||
console.error('[error] (remote) ' + err.toString());
|
console.error('[error] (remote) ' + err.toString());
|
||||||
|
@ -20,7 +20,19 @@ function listenForConns(opts) {
|
||||||
c.on('error', function (err) {
|
c.on('error', function (err) {
|
||||||
console.error('[error] (local) ' + err.toString());
|
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) {
|
server.on('error', function (err) {
|
||||||
console.error('[error] ' + err.toString());
|
console.error('[error] ' + err.toString());
|
||||||
});
|
});
|
||||||
|
@ -35,10 +47,14 @@ function listenForConns(opts) {
|
||||||
|
|
||||||
function testConn(opts) {
|
function testConn(opts) {
|
||||||
// Test connection first
|
// Test connection first
|
||||||
var tlsSock = tls.connect({
|
var tlsOpts = {
|
||||||
servername: opts.remoteAddr, host: opts.remoteAddr, port: opts.remotePort
|
host: opts.remoteAddr, port: opts.remotePort
|
||||||
, rejectUnauthorized: opts.rejectUnauthorized
|
, rejectUnauthorized: opts.rejectUnauthorized
|
||||||
}, function () {
|
};
|
||||||
|
if (opts.servername) {
|
||||||
|
tlsOpts.servername = opts.servername;
|
||||||
|
}
|
||||||
|
var tlsSock = tls.connect(tlsOpts, function () {
|
||||||
tlsSock.end();
|
tlsSock.end();
|
||||||
listenForConns(opts);
|
listenForConns(opts);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "sclient",
|
"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.",
|
"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",
|
"main": "index.js",
|
||||||
"homepage": "https://git.coolaj86.com/coolaj86/sclient.js",
|
"homepage": "https://git.coolaj86.com/coolaj86/sclient.js",
|
||||||
|
|
Loading…
Reference in New Issue