AJ ONeal
6 years ago
commit
5779325061
5 changed files with 247 additions and 0 deletions
@ -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