Compare commits
	
		
			No commits in common. "master" and "v1.2.2" have entirely different histories.
		
	
	
		
	
		
							
								
								
									
										40
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								README.md
									
									
									
									
									
								
							@ -30,24 +30,6 @@ cURL
 | 
				
			|||||||
$ curl http://localhost:3000 -H 'Host: whatever.com'
 | 
					$ curl http://localhost:3000 -H 'Host: whatever.com'
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Inverse SSH proxy (ssh over https):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
$ sclient ssh user@example.com
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(this is the same as a normal SSH Proxy, just easier to type):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
$ ssh -o ProxyCommand="sclient %h" user@example.com
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Inverse rsync proxy (rsync over https):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
$ sclient rsync user@example.com:path/ path/
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
A poor man's (or Windows user's) makeshift replacement for `openssl s_client`, `stunnel`, or `socat`.
 | 
					A poor man's (or Windows user's) makeshift replacement for `openssl s_client`, `stunnel`, or `socat`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Install
 | 
					Install
 | 
				
			||||||
@ -69,12 +51,12 @@ Usage
 | 
				
			|||||||
=====
 | 
					=====
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
sclient [flags] [ssh|rsync] <remote> [local]
 | 
					sclient [flags] <remote> <local>
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* flags
 | 
					* flags
 | 
				
			||||||
  * `-k, --insecure` ignore invalid TLS (SSL/HTTPS) certificates
 | 
					  * -k, --insecure ignore invalid TLS (SSL/HTTPS) certificates
 | 
				
			||||||
  * `--servername <string>` spoof SNI (to disable use IP as <remote> and do not use this option)
 | 
					  * --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)
 | 
				
			||||||
@ -103,7 +85,7 @@ Ignore a bad TLS/SSL/HTTPS certificate and connect anyway.
 | 
				
			|||||||
sclient -k badtls.telebit.cloud:443 localhost:3000
 | 
					sclient -k badtls.telebit.cloud:443 localhost:3000
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Reading from stdin
 | 
					Reading from stdin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
sclient telebit.cloud:443 -
 | 
					sclient telebit.cloud:443 -
 | 
				
			||||||
@ -113,19 +95,7 @@ sclient telebit.cloud:443 -
 | 
				
			|||||||
sclient telebit.cloud:443 - </path/to/file
 | 
					sclient telebit.cloud:443 - </path/to/file
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### ssh over https
 | 
					Piping
 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
sclient ssh user@telebit.cloud
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### rsync over https
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
sclient rsync -av user@telebit.cloud:my-project/ ~/my-project/
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Piping
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
printf "GET / HTTP/1.1\r\nHost: telebit.cloud\r\n\r\n" | sclient telebit.cloud:443
 | 
					printf "GET / HTTP/1.1\r\nHost: telebit.cloud\r\n\r\n" | sclient telebit.cloud:443
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										272
									
								
								bin/sclient.js
									
									
									
									
									
								
							
							
						
						
									
										272
									
								
								bin/sclient.js
									
									
									
									
									
								
							@ -1,4 +1,3 @@
 | 
				
			|||||||
#!/usr/bin/env node
 | 
					 | 
				
			||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var pkg = require('../package.json');
 | 
					var pkg = require('../package.json');
 | 
				
			||||||
@ -7,6 +6,8 @@ var local;
 | 
				
			|||||||
var isPiped = !process.stdin.isTTY;
 | 
					var isPiped = !process.stdin.isTTY;
 | 
				
			||||||
var localAddress;
 | 
					var localAddress;
 | 
				
			||||||
var localPort;
 | 
					var localPort;
 | 
				
			||||||
 | 
					var rejectUnauthorized;
 | 
				
			||||||
 | 
					var servername;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function usage() {
 | 
					function usage() {
 | 
				
			||||||
  console.info("");
 | 
					  console.info("");
 | 
				
			||||||
@ -18,245 +19,76 @@ function usage() {
 | 
				
			|||||||
  console.info("");
 | 
					  console.info("");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function parseFlags(argv) {
 | 
					function parseFlags() {
 | 
				
			||||||
  var args = argv.slice();
 | 
					  process.argv.some(function (arg, i) {
 | 
				
			||||||
  var flags = {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  args.some(function (arg, i) {
 | 
					 | 
				
			||||||
    if (/^-k|--?insecure$/.test(arg)) {
 | 
					    if (/^-k|--?insecure$/.test(arg)) {
 | 
				
			||||||
      flags.rejectUnauthorized = false;
 | 
					      rejectUnauthorized = false;
 | 
				
			||||||
      args.splice(i, 1);
 | 
					      process.argv.splice(i, 1);
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  args.some(function (arg, i) {
 | 
					  process.argv.some(function (arg, i) {
 | 
				
			||||||
    if (/^--?servername$/.test(arg)) {
 | 
					    if (/^--?servername$/.test(arg)) {
 | 
				
			||||||
      flags.servername = args[i + 1];
 | 
					      servername = process.argv[i + 1];
 | 
				
			||||||
      if (!flags.servername || /^-/.test(flags.servername)) {
 | 
					      if (!servername || /^-/.test(servername)) {
 | 
				
			||||||
        usage();
 | 
					        usage();
 | 
				
			||||||
        process.exit(2);
 | 
					        process.exit(2);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      args.splice(i, 2);
 | 
					      process.argv.splice(i, 2);
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  args.some(function (arg, i) {
 | 
					 | 
				
			||||||
    if (/^--?p(ort)?$/.test(arg)) {
 | 
					 | 
				
			||||||
      flags.port = args[i + 1];
 | 
					 | 
				
			||||||
      if (!flags.port || /^-/.test(flags.port)) {
 | 
					 | 
				
			||||||
        usage();
 | 
					 | 
				
			||||||
        process.exit(201);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      args.splice(i, 2);
 | 
					 | 
				
			||||||
      return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  args.some(function (arg, i) {
 | 
					 | 
				
			||||||
    if (/^--?ssh$/.test(arg)) {
 | 
					 | 
				
			||||||
      flags.wrapSsh = true;
 | 
					 | 
				
			||||||
      args.splice(i, 1);
 | 
					 | 
				
			||||||
      return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  args.some(function (arg, i) {
 | 
					 | 
				
			||||||
    if (/^--?socks5$/.test(arg)) {
 | 
					 | 
				
			||||||
      flags.socks5 = args[i + 1];
 | 
					 | 
				
			||||||
      if (!flags.socks5 || /^-/.test(flags.socks5)) {
 | 
					 | 
				
			||||||
        usage();
 | 
					 | 
				
			||||||
        process.exit(202);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      args.splice(i, 2);
 | 
					 | 
				
			||||||
      return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // This works for most (but not all)
 | 
					 | 
				
			||||||
  // of the ssh and rsync flags - because they mostly don't have arguments
 | 
					 | 
				
			||||||
  args.sort(function (a, b) {
 | 
					 | 
				
			||||||
    if ('-' === a[0]) {
 | 
					 | 
				
			||||||
      if ('-' === b[0]) {
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if ('-' === b[0]) {
 | 
					 | 
				
			||||||
      return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    flags: flags
 | 
					 | 
				
			||||||
  , args: args
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var sclient = require('../');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function testRemote(opts) {
 | 
					 | 
				
			||||||
  var emitter = new (require('events').EventEmitter)();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  sclient._test(opts).then(function () {
 | 
					 | 
				
			||||||
    // connected successfully (and closed)
 | 
					 | 
				
			||||||
    sclient._listen(emitter, opts);
 | 
					 | 
				
			||||||
  }).catch(function (err) {
 | 
					 | 
				
			||||||
    // did not connect succesfully
 | 
					 | 
				
			||||||
    sclient._listen(emitter, opts);
 | 
					 | 
				
			||||||
    console.warn("[warn] '" + opts.remoteAddr + ":" + opts.remotePort
 | 
					 | 
				
			||||||
      + "' may not be accepting connections: ", err.toString(), '\n');
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  emitter.once('listening', function (opts) {
 | 
					 | 
				
			||||||
    console.info('[listening] ' + opts.remoteAddr + ":" + opts.remotePort
 | 
					 | 
				
			||||||
      + " <= " + opts.localAddress + ":" + opts.localPort);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (opts.command) {
 | 
					 | 
				
			||||||
      var args = [
 | 
					 | 
				
			||||||
        opts.remoteUser + 'localhost'
 | 
					 | 
				
			||||||
      , '-p', opts.localPort
 | 
					 | 
				
			||||||
      // we're _inverse_ proxying ssh, so we must alias the serveranem and ignore the IP
 | 
					 | 
				
			||||||
      , '-o', 'HostKeyAlias=' + opts.remoteAddr
 | 
					 | 
				
			||||||
      , '-o', 'CheckHostIP=no'
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
      var spawn = require('child_process').spawn;
 | 
					 | 
				
			||||||
      if ('rsync' === opts.command) {
 | 
					 | 
				
			||||||
        var remote = args.shift() + ':' + opts.remotePath;
 | 
					 | 
				
			||||||
        args = [ remote, '-e', 'ssh ' + args.join(' ') ];
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (opts.socks5) {
 | 
					 | 
				
			||||||
        args.push('-D');
 | 
					 | 
				
			||||||
        args.push('localhost:' + opts.socks5);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      args = args.concat(opts.args);
 | 
					 | 
				
			||||||
      var child = spawn(opts.command, args, { stdio: 'inherit' });
 | 
					 | 
				
			||||||
      child.on('exit', function () {
 | 
					 | 
				
			||||||
        console.info('closing...');
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      child.on('close', function () {
 | 
					 | 
				
			||||||
        opts.server.close();
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  emitter.on('connect', function (sock) {
 | 
					 | 
				
			||||||
    console.info('[connect] ' + sock.localAddress.replace('::1', 'localhost') + ":" + sock.localPort
 | 
					 | 
				
			||||||
      + " => " + opts.remoteAddr + ":" + opts.remotePort);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  emitter.on('remote-error', function (err) {
 | 
					 | 
				
			||||||
    console.error('[error] (remote) ' + err.toString());
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  emitter.on('local-error', function (err) {
 | 
					 | 
				
			||||||
    console.error('[error] (local) ' + err.toString());
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function main() {
 | 
					parseFlags();
 | 
				
			||||||
  var cmd = parseFlags(process.argv);
 | 
					 | 
				
			||||||
  var binParam;
 | 
					 | 
				
			||||||
  var remoteUser;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Re-arrange argument order for ssh
 | 
					remote = (process.argv[2]||'').split(':');
 | 
				
			||||||
  if (cmd.flags.wrapSsh) {
 | 
					local = (process.argv[3]||'').split(':');
 | 
				
			||||||
    cmd.args.splice(3, 0, 'ssh');
 | 
					 | 
				
			||||||
  } else if (-1 !== [ 'ssh', 'rsync', 'vpn' ].indexOf((cmd.args[2]||'').split(':')[0])) {
 | 
					 | 
				
			||||||
    cmd.flags.wrapSsh = true;
 | 
					 | 
				
			||||||
    binParam = cmd.args.splice(2, 1);
 | 
					 | 
				
			||||||
    cmd.args.splice(3, 0, binParam[0]);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  remoteUser = (cmd.args[2]||'').split('@');
 | 
					// arg 0 is node
 | 
				
			||||||
  if (remoteUser[1]) {
 | 
					// arg 1 is sclient
 | 
				
			||||||
    // has 'user@' in front
 | 
					// arg 2 is remote
 | 
				
			||||||
    remote = (remoteUser[1]||'').split(':');
 | 
					// arg 3 is local
 | 
				
			||||||
    remoteUser = remoteUser[0] + '@';
 | 
					if (4 !== process.argv.length) {
 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    // no 'user@' in front
 | 
					 | 
				
			||||||
    remote = (remoteUser[0]||'').split(':');
 | 
					 | 
				
			||||||
    remoteUser = '';
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  local = (cmd.args[3]||'').split(':');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (-1 !== [ 'ssh', 'rsync', 'vpn' ].indexOf(local[0])) {
 | 
					 | 
				
			||||||
    cmd.flags.wrapSsh = true;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (cmd.flags.wrapSsh) {
 | 
					 | 
				
			||||||
    process.argv = cmd.args;
 | 
					 | 
				
			||||||
  } else if (4 !== cmd.args.length) {
 | 
					 | 
				
			||||||
    // arg 0 is node
 | 
					 | 
				
			||||||
    // arg 1 is sclient
 | 
					 | 
				
			||||||
    // arg 2 is remote
 | 
					 | 
				
			||||||
    // arg 3 is local (or ssh or rsync)
 | 
					 | 
				
			||||||
  if (isPiped) {
 | 
					  if (isPiped) {
 | 
				
			||||||
    local = ['|'];
 | 
					    local = ['|'];
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    usage();
 | 
					    usage();
 | 
				
			||||||
    process.exit(1);
 | 
					    process.exit(1);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Check for the first argument (what to connect to)
 | 
					 | 
				
			||||||
  if (!remote[0]) {
 | 
					 | 
				
			||||||
    usage();
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!local[0]) {
 | 
					 | 
				
			||||||
    usage();
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // check if it looks like a port number
 | 
					 | 
				
			||||||
  if (local[0] === String(parseInt(local[0], 10))) {
 | 
					 | 
				
			||||||
    localPort = parseInt(local[0], 10);
 | 
					 | 
				
			||||||
    localAddress = 'localhost';
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    localAddress = local[0]; // potentially '-' or '|' or '$'
 | 
					 | 
				
			||||||
    localPort = parseInt(local[1], 10);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var opts = {
 | 
					 | 
				
			||||||
    remoteUser: remoteUser
 | 
					 | 
				
			||||||
  , remoteAddr: remote[0]
 | 
					 | 
				
			||||||
  , remotePort: remote[1] || 443
 | 
					 | 
				
			||||||
  , localAddress: localAddress
 | 
					 | 
				
			||||||
  , localPort: localPort
 | 
					 | 
				
			||||||
  , rejectUnauthorized: cmd.flags.rejectUnauthorized
 | 
					 | 
				
			||||||
  , servername: cmd.flags.servername
 | 
					 | 
				
			||||||
  , stdin: null
 | 
					 | 
				
			||||||
  , stdout: null
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if ('-' === localAddress || '|' === localAddress) {
 | 
					 | 
				
			||||||
    opts.stdin = process.stdin;
 | 
					 | 
				
			||||||
    opts.stdout = process.stdout;
 | 
					 | 
				
			||||||
    // no need for port
 | 
					 | 
				
			||||||
  } else if (-1 !== [ 'ssh', 'rsync', 'vpn' ].indexOf(localAddress)) {
 | 
					 | 
				
			||||||
    cmd.flags.wrapSsh = true;
 | 
					 | 
				
			||||||
    opts.localAddress = 'localhost';
 | 
					 | 
				
			||||||
    opts.localPort = local[1] || 0; // choose at random
 | 
					 | 
				
			||||||
    opts.command = localAddress;
 | 
					 | 
				
			||||||
    opts.args = cmd.args.slice(4); // node, sclient, ssh, addr
 | 
					 | 
				
			||||||
    opts.socks5 = cmd.flags.socks5;
 | 
					 | 
				
			||||||
    if ('rsync' === opts.command) {
 | 
					 | 
				
			||||||
      opts.remotePath = opts.remotePort;
 | 
					 | 
				
			||||||
      opts.remotePort = 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if ('vpn' === opts.command) {
 | 
					 | 
				
			||||||
      opts.command = 'ssh';
 | 
					 | 
				
			||||||
      if (!opts.socks5) {
 | 
					 | 
				
			||||||
        usage();
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!opts.remotePort) {
 | 
					 | 
				
			||||||
      opts.remotePort = cmd.flags.port || 443;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  } else if (!localPort) {
 | 
					 | 
				
			||||||
    usage();
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  testRemote(opts);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
main();
 | 
					// Check for the first argument (what to connect to)
 | 
				
			||||||
 | 
					if (!remote[0]) {
 | 
				
			||||||
 | 
					  usage();
 | 
				
			||||||
 | 
					  return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!local[0]) {
 | 
				
			||||||
 | 
					  usage();
 | 
				
			||||||
 | 
					  return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					if (local[0] === String(parseInt(local[0], 10))) {
 | 
				
			||||||
 | 
					  localPort = parseInt(local[0], 10);
 | 
				
			||||||
 | 
					  localAddress = 'localhost';
 | 
				
			||||||
 | 
					} else {
 | 
				
			||||||
 | 
					  localAddress = local[0]; // potentially '-' or '|'
 | 
				
			||||||
 | 
					  localPort = parseInt(local[1], 10);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if ('-' === localAddress || '|' === localAddress) {
 | 
				
			||||||
 | 
					  // no need for port
 | 
				
			||||||
 | 
					} else if (!localPort) {
 | 
				
			||||||
 | 
					  usage();
 | 
				
			||||||
 | 
					  return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var opts = {
 | 
				
			||||||
 | 
					  remoteAddr: remote[0]
 | 
				
			||||||
 | 
					, remotePort: remote[1] || 443
 | 
				
			||||||
 | 
					, localAddress: localAddress
 | 
				
			||||||
 | 
					, localPort: localPort
 | 
				
			||||||
 | 
					, rejectUnauthorized: rejectUnauthorized
 | 
				
			||||||
 | 
					, servername: servername
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					require('../')(opts);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										37
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								index.js
									
									
									
									
									
								
							@ -1,35 +1,34 @@
 | 
				
			|||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var PromiseA = global.Promise;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var net = require('net');
 | 
					var net = require('net');
 | 
				
			||||||
var tls = require('tls');
 | 
					var tls = require('tls');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function listenForConns(emitter, opts) {
 | 
					function listenForConns(opts) {
 | 
				
			||||||
  function pipeConn(c, out) {
 | 
					  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
 | 
				
			||||||
    }, function () {
 | 
					    }, function () {
 | 
				
			||||||
      emitter.emit('connect', sclient);
 | 
					      console.info('[connect] ' + sclient.localAddress.replace('::1', 'localhost') + ":" + sclient.localPort
 | 
				
			||||||
 | 
					        + " => " + opts.remoteAddr + ":" + opts.remotePort);
 | 
				
			||||||
      c.pipe(sclient);
 | 
					      c.pipe(sclient);
 | 
				
			||||||
      sclient.pipe(out || c);
 | 
					      sclient.pipe(out || c);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    sclient.on('error', function (err) {
 | 
					    sclient.on('error', function (err) {
 | 
				
			||||||
      emitter.emit('remote-error', err);
 | 
					      console.error('[error] (remote) ' + err.toString());
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    c.on('error', function (err) {
 | 
					    c.on('error', function (err) {
 | 
				
			||||||
      emitter.emit('local-error', err);
 | 
					      console.error('[error] (local) ' + err.toString());
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    if (out) {
 | 
					    if (out) {
 | 
				
			||||||
      out.on('error', function (err) {
 | 
					      out.on('error', function (err) {
 | 
				
			||||||
        emitter.emit('local-error', err);
 | 
					        console.error('[error] (local) ' + err.toString());
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if ('-' === opts.localAddress || '|' === opts.localAddress) {
 | 
					  if ('-' === opts.localAddress || '|' === opts.localAddress) {
 | 
				
			||||||
    pipeConn(opts.stdin, opts.stdout);
 | 
					    pipeConn(process.stdin, process.stdout);
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -41,14 +40,12 @@ function listenForConns(emitter, opts) {
 | 
				
			|||||||
    host: opts.localAddress
 | 
					    host: opts.localAddress
 | 
				
			||||||
  , port: opts.localPort
 | 
					  , port: opts.localPort
 | 
				
			||||||
  }, function () {
 | 
					  }, function () {
 | 
				
			||||||
    opts.localPort = this.address().port;
 | 
					    console.info('[listening] ' + opts.remoteAddr + ":" + opts.remotePort
 | 
				
			||||||
    opts.server = this;
 | 
					      + " <= " + opts.localAddress + ":" + opts.localPort);
 | 
				
			||||||
    emitter.emit('listening', opts);
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function testConn(opts) {
 | 
					function testConn(opts) {
 | 
				
			||||||
  return new PromiseA(function (resolve, reject) {
 | 
					 | 
				
			||||||
  // Test connection first
 | 
					  // Test connection first
 | 
				
			||||||
  var tlsOpts = {
 | 
					  var tlsOpts = {
 | 
				
			||||||
    host: opts.remoteAddr, port: opts.remotePort
 | 
					    host: opts.remoteAddr, port: opts.remotePort
 | 
				
			||||||
@ -56,23 +53,15 @@ function testConn(opts) {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
  if (opts.servername) {
 | 
					  if (opts.servername) {
 | 
				
			||||||
    tlsOpts.servername = opts.servername;
 | 
					    tlsOpts.servername = opts.servername;
 | 
				
			||||||
    } else if (/^[\w\.\-]+\.[a-z]{2,}$/i.test(opts.remoteAddr)) {
 | 
					 | 
				
			||||||
      tlsOpts.servername = opts.remoteAddr.toLowerCase();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (opts.alpn) {
 | 
					 | 
				
			||||||
      tlsOpts.ALPNProtocols = [ 'http', 'h2' ];
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  var tlsSock = tls.connect(tlsOpts, function () {
 | 
					  var tlsSock = tls.connect(tlsOpts, function () {
 | 
				
			||||||
    tlsSock.end();
 | 
					    tlsSock.end();
 | 
				
			||||||
      resolve();
 | 
					    listenForConns(opts);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  tlsSock.on('error', function (err) {
 | 
					  tlsSock.on('error', function (err) {
 | 
				
			||||||
      reject(err);
 | 
					    console.warn("[warn] '" + opts.remoteAddr + ":" + opts.remotePort + "' may not be accepting connections: ", err.toString(), '\n');
 | 
				
			||||||
    });
 | 
					    listenForConns(opts);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// no public exports yet
 | 
					module.exports = testConn;
 | 
				
			||||||
// the API is for the commandline only
 | 
					 | 
				
			||||||
module.exports._test = testConn;
 | 
					 | 
				
			||||||
module.exports._listen = listenForConns;
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "sclient",
 | 
					  "name": "sclient",
 | 
				
			||||||
  "version": "1.4.3",
 | 
					  "version": "1.2.2",
 | 
				
			||||||
  "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://telebit.cloud/sclient/",
 | 
					  "homepage": "https://telebit.cloud/sclient/",
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user