v1.0.0: initial release
This commit is contained in:
commit
5779325061
|
@ -0,0 +1,41 @@
|
|||
Copyright 2018 AJ ONeal
|
||||
|
||||
This is open source software; you can redistribute it and/or modify it under the
|
||||
terms of either:
|
||||
|
||||
a) the "MIT License"
|
||||
b) the "Apache-2.0 License"
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
Apache-2.0 License Summary
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,70 @@
|
|||
sclient.js
|
||||
==========
|
||||
|
||||
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.
|
||||
|
||||
Unwrap a TLS connection
|
||||
|
||||
```bash
|
||||
$ sclient whatever.com:443 localhost:3000
|
||||
> [listening] telebit.cloud:443 <= localhost:3000
|
||||
```
|
||||
|
||||
Connect via Telnet
|
||||
|
||||
```bash
|
||||
$ telnet localhost 3000
|
||||
```
|
||||
|
||||
Connect via netcat (nc)
|
||||
|
||||
```bash
|
||||
$ nc telnet localhost 3000
|
||||
```
|
||||
|
||||
Install
|
||||
=======
|
||||
|
||||
### macOS, Linux, Windows
|
||||
|
||||
First download and install the *current* version of [node.js](https://nodejs.org)
|
||||
|
||||
```bash
|
||||
npm install -g sclient
|
||||
```
|
||||
|
||||
```bash
|
||||
npx sclient example.com:443 localhost:3000
|
||||
```
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
```bash
|
||||
sclient <remote> <local> [-k | --insecure]
|
||||
```
|
||||
|
||||
* remote
|
||||
* must have servername (i.e. example.com)
|
||||
* port is optional (default is 443)
|
||||
* local
|
||||
* address is optional (default is localhost)
|
||||
* must have port (i.e. 3000)
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Bridge between `telebit.cloud` and
|
||||
```bash
|
||||
sclient telebit.cloud 3000
|
||||
```
|
||||
|
||||
```bash
|
||||
sclient telebit.cloud:443 localhost:3000
|
||||
```
|
||||
|
||||
```bash
|
||||
sclient badtls.telebit.cloud:443 localhost:3000 -k
|
||||
```
|
|
@ -0,0 +1,57 @@
|
|||
'use strict';
|
||||
|
||||
var pkg = require('../package.json');
|
||||
var remote = (process.argv[2]||'').split(':');
|
||||
var local = (process.argv[3]||'').split(':');
|
||||
var localAddress;
|
||||
var localPort;
|
||||
var rejectUnauthorized;
|
||||
|
||||
function usage() {
|
||||
console.info("");
|
||||
console.info("sclient.js v" + pkg.version);
|
||||
console.info("Usage: sclient <servername:port> <port> [-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);
|
||||
}
|
||||
|
||||
if (!remote[0]) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
if (!remote[1]) {
|
||||
remote[1] = 443;
|
||||
}
|
||||
|
||||
if (!local[0]) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
if (local[0] === String(parseInt(local[0], 10))) {
|
||||
localPort = parseInt(local[0], 10);
|
||||
localAddress = 'localhost';
|
||||
} else {
|
||||
localAddress = local[0];
|
||||
localPort = parseInt(local[1], 10);
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
require('../')(opts);
|
|
@ -0,0 +1,51 @@
|
|||
'use strict';
|
||||
|
||||
var net = require('net');
|
||||
var tls = require('tls');
|
||||
|
||||
function listenForConns(opts) {
|
||||
var server = net.createServer(function (c) {
|
||||
var sclient = tls.connect({
|
||||
servername: opts.remoteAddr, host: opts.remoteAddr, port: opts.remotePort
|
||||
, rejectUnauthorized: opts.rejectUnauthorized
|
||||
}, function () {
|
||||
console.info('[connect] ' + sclient.localAddress.replace('::1', 'localhost') + ":" + sclient.localPort
|
||||
+ " => " + opts.remoteAddr + ":" + opts.remotePort);
|
||||
c.pipe(sclient);
|
||||
sclient.pipe(c);
|
||||
});
|
||||
sclient.on('error', function (err) {
|
||||
console.error('[error] (remote) ' + err.toString());
|
||||
});
|
||||
c.on('error', function (err) {
|
||||
console.error('[error] (local) ' + err.toString());
|
||||
});
|
||||
});
|
||||
server.on('error', function (err) {
|
||||
console.error('[error] ' + err.toString());
|
||||
});
|
||||
server.listen({
|
||||
host: opts.localAddress
|
||||
, port: opts.localPort
|
||||
}, function () {
|
||||
console.info('[listening] ' + opts.remoteAddr + ":" + opts.remotePort
|
||||
+ " <= " + opts.localAddress + ":" + opts.localPort);
|
||||
});
|
||||
}
|
||||
|
||||
function testConn(opts) {
|
||||
// Test connection first
|
||||
var tlsSock = tls.connect({
|
||||
servername: opts.remoteAddr, host: opts.remoteAddr, port: opts.remotePort
|
||||
, rejectUnauthorized: opts.rejectUnauthorized
|
||||
}, function () {
|
||||
tlsSock.end();
|
||||
listenForConns(opts);
|
||||
});
|
||||
tlsSock.on('error', function (err) {
|
||||
console.warn("[warn] '" + opts.remoteAddr + ":" + opts.remotePort + "' may not be accepting connections: ", err.toString(), '\n');
|
||||
listenForConns(opts);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = testConn;
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "sclient",
|
||||
"version": "1.0.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",
|
||||
"bin": {
|
||||
"sclient": "bin/sclient.js"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"lib"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.coolaj86.com/coolaj86/sclient.js.git"
|
||||
},
|
||||
"keywords": [
|
||||
"stunnel",
|
||||
"s_client",
|
||||
"telebit",
|
||||
"openssl"
|
||||
],
|
||||
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
||||
"license": "(MIT OR Apache-2.0)"
|
||||
}
|
Loading…
Reference in New Issue