Adding native autossh, auto ports, localhosts.

This commit is contained in:
Valentin Boettcher 2018-04-03 18:49:54 +02:00
parent 6b680621a2
commit 8606e1a0b1
4 changed files with 112 additions and 101 deletions

View file

@ -1,27 +1 @@
/home/hiro/Documents/Projects/autossh/src/index.js
28:2 warning Expected indentation of 6 space characters but found 0 indent
32:12 warning This function has too many statements (14). Maximum allowed is 12 max-statements
68:12 warning Closing curly brace appears on the same line as the subsequent block brace-style
142:12 warning Closing curly brace appears on the same line as the subsequent block brace-style
274:5 warning Expected indentation of 2 space characters but found 4 indent
275:2 warning Expected indentation of 6 space characters but found 0 indent
276:2 warning Expected indentation of 6 space characters but found 0 indent
276:23 warning Multiple spaces found before '&&' no-multi-spaces
277:7 warning Expected indentation of 2 space characters but found 6 indent
279:5 warning Expected indentation of 6 space characters but found 4 indent
282:7 warning Expected indentation of 8 space characters but found 6 indent
286:7 warning Expected indentation of 8 space characters but found 6 indent
292:7 warning Expected indentation of 8 space characters but found 6 indent
299:11 warning Closing curly brace appears on the same line as the subsequent block brace-style
302:2 error Mixed spaces and tabs no-mixed-spaces-and-tabs
302:4 warning Expected indentation of 8 space characters but found 0 indent
302:4 warning Unnecessary { after 'if' condition curly
303:15 warning Expected indentation of 2 space characters but found 14 indent
304:2 error Mixed spaces and tabs no-mixed-spaces-and-tabs
305:5 warning Expected indentation of 6 space characters but found 4 indent
307:5 warning Expected indentation of 6 space characters but found 4 indent
309:3 warning Expected indentation of 4 space characters but found 2 indent
✖ 22 problems (2 errors, 20 warnings)


View file

@ -33,6 +33,16 @@ ssh -NL 64444:localhost:5432 -o "ExitOnForwardFailure yes" -o ServerAliveInterva
<br />
#### Using Autossh
There is a very stable tool which is quite good at monitoring ssh
connections. Setting the `useAutossh` option to `true` will tell
`node-autossh` to use `autossh` instead of `ssh`. No further
modifications of the settings are necessary as `autossh` is just a
wrapper around `ssh` and will work with the same options.
Using the native `autossh` is recommended and will result in greater
stability.
#### Event Listeners
Autossh inherits from node.js's EventEmitter, and implements three events: `error`, `timeout`, `connect`
@ -54,11 +64,13 @@ The `connect` event will fire only once when the initial ssh connection is made.
- `kill` - a method to kill autossh
- `pid` - the autossh process id
- `host`
- `localHost` - The host, to which the tunnel applies.
- `localHost` - the host, to which the tunnel applies
- `username`
- `remotePort`
- `localPort`
- `execString` - the autossh command string
- `useAutossh` - use autossh (see https://linux.die.net/man/1/autossh)
- `executable` - the ssh connabd to use (it is passed to `/usr/bin/env`, **Higly Optional!**)
- `extraOpts` - an Array of extra options
**Example 1**

View file

@ -14,6 +14,8 @@ var _portfinder2 = _interopRequireDefault(_portfinder);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
@ -26,7 +28,7 @@ var AutoSSH = function (_EventEmitter) {
_inherits(AutoSSH, _EventEmitter);
/*
*/
*/
function AutoSSH() {
var conf = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
@ -74,10 +76,14 @@ var AutoSSH = function (_EventEmitter) {
this.sshPort = conf.sshPort || 22;
this.privateKey = conf.privateKey || null;
this.useAutossh = conf.useAutossh || false;
this.executable = (this.useAutossh ? 'autossh' : 'ssh') || '';
this.extraOpts = conf.extraOpts || [];
}
/*
*/
*/
}, {
key: 'connect',
@ -107,7 +113,7 @@ var AutoSSH = function (_EventEmitter) {
}
/*
*/
*/
}, {
key: 'getConnectionInfo',
@ -124,7 +130,7 @@ var AutoSSH = function (_EventEmitter) {
username: this.username || null,
remotePort: parseInt(this.remotePort),
localPort: parseInt(this.localPort),
execString: this.execString || null
execArgs: this.execArgs || null
};
if (this.currentProcess) infoObj.pid = this.currentProcess.pid;
@ -135,7 +141,7 @@ var AutoSSH = function (_EventEmitter) {
}
/* fired when connection established
*/
*/
}, {
key: 'emitConnect',
@ -144,7 +150,7 @@ var AutoSSH = function (_EventEmitter) {
}
/* fired when timeout error occurs
*/
*/
}, {
key: 'emitTimeout',
@ -160,12 +166,12 @@ var AutoSSH = function (_EventEmitter) {
username: this.username,
remotePort: this.remotePort,
localPort: this.localPort,
execString: this.execString
execArgs: this.execArgs
});
}
/* starts polling the port to see if connection established
*/
*/
}, {
key: 'pollConnection',
@ -190,7 +196,7 @@ var AutoSSH = function (_EventEmitter) {
}
/* checks if connection is established at port
*/
*/
}, {
key: 'isConnectionEstablished',
@ -214,7 +220,7 @@ var AutoSSH = function (_EventEmitter) {
}
/* parses the conf for errors
*/
*/
}, {
key: 'getConfErrors',
@ -243,7 +249,7 @@ var AutoSSH = function (_EventEmitter) {
}
/*
*/
*/
}, {
key: 'generateRandomPort',
@ -254,29 +260,36 @@ var AutoSSH = function (_EventEmitter) {
}
/*
*/
*/
}, {
key: 'generateDefaultOptions',
value: function generateDefaultOptions() {
var exitOnFailure = '-o ExitOnForwardFailure=yes';
var strictHostCheck = '-o StrictHostKeyChecking=no';
return exitOnFailure + ' ' + strictHostCheck;
return [exitOnFailure, strictHostCheck];
}
/*
*/
*/
}, {
key: 'generateServerAliveOptions',
value: function generateServerAliveOptions() {
var serverAliveInterval = '-o ServerAliveInterval=' + this.serverAliveInterval;
var serverAliveCountMax = '-o ServerAliveCountMax=' + this.serverAliveCountMax;
return serverAliveInterval + ' ' + serverAliveCountMax;
return [serverAliveInterval, serverAliveCountMax];
}
}, {
key: 'stripEmpty',
value: function stripEmpty(arr) {
return arr.filter(function (elem) {
return Boolean(elem);
});
}
/*
*/
*/
}, {
key: 'generateExecOptions',
@ -286,16 +299,17 @@ var AutoSSH = function (_EventEmitter) {
var privateKey = this.privateKey ? '-i ' + this.privateKey : '';
var sshPort = this.sshPort === 22 ? '' : '-p ' + this.sshPort;
var gatewayPorts = this.localHost === 'localhost' ? '' : '-o GatewayPorts=yes';
return defaultOpts + ' ' + serverAliveOpts + ' ' + gatewayPorts + ' ' + privateKey + ' ' + sshPort;
var extraOpts = this.extraOpts;
var autosshFlags = this.useAutossh ? ['-M 0'] : [];
return [].concat(autosshFlags, _toConsumableArray(defaultOpts), _toConsumableArray(serverAliveOpts), [gatewayPorts, privateKey, sshPort], _toConsumableArray(extraOpts));
}
/*
*/
*/
}, {
key: 'generateExecString',
value: function generateExecString() {
key: 'generateExecArgs',
value: function generateExecArgs() {
var startPort = this.reverse ? this.remotePort : this.localPort;
var endPort = this.reverse ? this.localPort : this.remotePort;
var bindAddress = startPort + ':' + this.localHost + ':' + endPort;
@ -303,23 +317,22 @@ var AutoSSH = function (_EventEmitter) {
var userAtHost = this.username + '@' + this.host;
var method = this.reverse ? 'R' : 'L';
return 'ssh -N' + method + ' ' + bindAddress + ' ' + options + ' ' + userAtHost;
return this.stripEmpty([this.executable, '-N' + method, bindAddress].concat(_toConsumableArray(options), [userAtHost]));
}
/*
*/
*/
}, {
key: 'execTunnel',
value: function execTunnel(execTunnelCb) {
var _this7 = this;
console.log(this.remotePort);
if (this.autoRemote && isNaN(this.remotePort)) this.remotePort = this.generateRandomPort();
this.execString = this.generateExecString();
this.execArgs = this.generateExecArgs();
this.currentProcess = (0, _child_process.exec)(this.execString, function (execErr, stdout, stderr) {
this.currentProcess = (0, _child_process.execFile)('/usr/bin/env', this.execArgs, function (execErr, stdout, stderr) {
if (_this7.killed) return;
if (/Address already in use/i.test(stderr)) {
@ -330,6 +343,7 @@ var AutoSSH = function (_EventEmitter) {
if (execErr) {
if (/(timeout)|(timed out)/i.test(stderr)) _this7.emitTimeout();else if (/remote port forwarding failed for listen/i.test(stderr) && _this7.autoRemote) {
_this7.remotePort = _this7.generateRandomPort();
_this7.execTunnel(function () {
return console.log('Trying another port...');
});
@ -337,11 +351,9 @@ var AutoSSH = function (_EventEmitter) {
} else _this7.emit('error', execErr);
}
if (!_this7.killed) {
_this7.execTunnel(function () {
return console.log('Restarting autossh...');
});
}
if (!_this7.killed) _this7.execTunnel(function () {
return console.log('Restarting autossh...');
});
});
if (typeof execTunnelCb === 'function') setImmediate(function () {
@ -350,7 +362,7 @@ var AutoSSH = function (_EventEmitter) {
}
/*
*/
*/
}, {
key: 'kill',
@ -372,8 +384,8 @@ module.exports = function (conf) {
var autossh = new AutoSSH(conf);
/* Create interface object
A new object creates an abstraction from class implementation
*/
A new object creates an abstraction from class implementation
*/
var autosshInterface = {
on: function on(evt) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {

View file

@ -1,16 +1,17 @@
import {
exec
execFile
} from 'child_process';
import {
EventEmitter
} from 'events';
import portfinder from 'portfinder';
/* AutoSSH class
*/
class AutoSSH extends EventEmitter {
/*
*/
*/
constructor(conf = {}) {
super();
@ -25,7 +26,7 @@ class AutoSSH extends EventEmitter {
});
process.on('exit', () => {
this.kill();
this.kill();
});
}
@ -55,17 +56,22 @@ class AutoSSH extends EventEmitter {
this.sshPort = conf.sshPort || 22;
this.privateKey = conf.privateKey || null;
this.useAutossh = conf.useAutossh || false;
this.executable = (this.useAutossh ? 'autossh' : 'ssh') || '';
this.extraOpts = conf.extraOpts || [];
}
/*
*/
*/
connect(conf) {
const port = this.localPort === 'auto' ? this.generateRandomPort() : this.localPort;
if (this.reverse || this.localHost !== 'localhost') {
this.execTunnel(() => {
this.pollConnection();
});
} else {
}
else {
portfinder.getPort({
port
}, (portfinderErr, freePort) => {
@ -87,7 +93,7 @@ class AutoSSH extends EventEmitter {
}
/*
*/
*/
getConnectionInfo() {
const infoObj = {
kill: () => this.kill,
@ -97,7 +103,7 @@ class AutoSSH extends EventEmitter {
username: this.username || null,
remotePort: parseInt(this.remotePort),
localPort: parseInt(this.localPort),
execString: this.execString || null
execArgs: this.execArgs || null
};
if (this.currentProcess)
@ -111,13 +117,13 @@ class AutoSSH extends EventEmitter {
}
/* fired when connection established
*/
*/
emitConnect() {
this.emit('connect', this.getConnectionInfo());
}
/* fired when timeout error occurs
*/
*/
emitTimeout() {
this.emit('timeout', {
kill: () => this.kill,
@ -126,12 +132,12 @@ class AutoSSH extends EventEmitter {
username: this.username,
remotePort: this.remotePort,
localPort: this.localPort,
execString: this.execString
execArgs: this.execArgs
});
}
/* starts polling the port to see if connection established
*/
*/
pollConnection() {
if (this.killed)
return;
@ -139,7 +145,8 @@ class AutoSSH extends EventEmitter {
if (this.maxPollCount && this.pollCount >= this.maxPollCount) {
this.emit('error', 'Max poll count reached. Aborting...');
this.kill();
} else {
}
else {
this.isConnectionEstablished(result => {
if (result)
this.emitConnect();
@ -154,7 +161,7 @@ class AutoSSH extends EventEmitter {
}
/* checks if connection is established at port
*/
*/
isConnectionEstablished(connEstablishedCb) {
if (this.localHost !== 'localhost' || this.reverse) {
connEstablishedCb(true);
@ -177,7 +184,7 @@ class AutoSSH extends EventEmitter {
}
/* parses the conf for errors
*/
*/
getConfErrors(conf) {
const errors = [];
if (!conf.localPort)
@ -221,7 +228,7 @@ class AutoSSH extends EventEmitter {
}
/*
*/
*/
generateRandomPort() {
const minPort = 3000;
const maxPort = 65535;
@ -229,36 +236,42 @@ class AutoSSH extends EventEmitter {
}
/*
*/
*/
generateDefaultOptions() {
const exitOnFailure = '-o ExitOnForwardFailure=yes';
const strictHostCheck = `-o StrictHostKeyChecking=no`;
return `${exitOnFailure} ${strictHostCheck}`;
return [exitOnFailure, strictHostCheck];
}
/*
*/
*/
generateServerAliveOptions() {
const serverAliveInterval = `-o ServerAliveInterval=${this.serverAliveInterval}`;
const serverAliveCountMax = `-o ServerAliveCountMax=${this.serverAliveCountMax}`;
return `${serverAliveInterval} ${serverAliveCountMax}`;
return [serverAliveInterval, serverAliveCountMax];
}
stripEmpty(arr) {
return arr.filter(elem => Boolean(elem));
}
/*
*/
*/
generateExecOptions() {
const serverAliveOpts = this.generateServerAliveOptions();
const defaultOpts = this.generateDefaultOptions();
const privateKey = this.privateKey ? `-i ${this.privateKey}` : '';
const sshPort = this.sshPort === 22 ? '' : `-p ${this.sshPort}`;
const gatewayPorts = this.localHost === 'localhost' ? '' : '-o GatewayPorts=yes';
return `${defaultOpts} ${serverAliveOpts} ${gatewayPorts} ${privateKey} ${sshPort}`;
const extraOpts = this.extraOpts;
const autosshFlags = this.useAutossh ? [ '-M 0' ] : [];
return [...autosshFlags, ...defaultOpts, ...serverAliveOpts,
gatewayPorts, privateKey, sshPort, ...extraOpts];
}
/*
*/
generateExecString() {
*/
generateExecArgs() {
const startPort = this.reverse ? this.remotePort : this.localPort;
const endPort = this.reverse ? this.localPort : this.remotePort;
const bindAddress = `${startPort}:${this.localHost}:${endPort}`;
@ -266,23 +279,21 @@ class AutoSSH extends EventEmitter {
const userAtHost = `${this.username}@${this.host}`;
const method = this.reverse ? 'R' : 'L';
return `ssh -N${method} ${bindAddress} ${options} ${userAtHost}`;
return this.stripEmpty([this.executable, `-N${method}`, bindAddress, ...options, userAtHost]);
}
/*
*/
execTunnel(execTunnelCb) {
console.log(this.remotePort);
if (this.autoRemote && isNaN(this.remotePort))
*/
execTunnel(execTunnelCb) {
if (this.autoRemote && isNaN(this.remotePort))
this.remotePort = this.generateRandomPort();
this.execString = this.generateExecString();
this.execArgs = this.generateExecArgs();
this.currentProcess = exec(this.execString, (execErr, stdout, stderr) => {
this.currentProcess = execFile(`/usr/bin/env`, this.execArgs, (execErr, stdout, stderr) => {
if (this.killed)
return;
if (/Address already in use/i.test(stderr)) {
this.kill();
this.emit('error', stderr);
@ -292,16 +303,18 @@ class AutoSSH extends EventEmitter {
if (execErr) {
if ((/(timeout)|(timed out)/i).test(stderr))
this.emitTimeout();
else if (/remote port forwarding failed for listen/i.test(stderr) && this.autoRemote) {
this.remotePort = this.generateRandomPort();
this.execTunnel(() => console.log('Trying another port...'));
return;
} else
}
else
this.emit('error', execErr);
}
if (!this.killed) {
this.execTunnel(() => console.log('Restarting autossh...'));
}
if (!this.killed)
this.execTunnel(() => console.log('Restarting autossh...'));
});
if (typeof execTunnelCb === 'function')
@ -309,7 +322,7 @@ class AutoSSH extends EventEmitter {
}
/*
*/
*/
kill() {
this.killed = true;
if (this.currentProcess && typeof this.currentProcess.kill === 'function')
@ -325,8 +338,8 @@ module.exports = function(conf) {
const autossh = new AutoSSH(conf);
/* Create interface object
A new object creates an abstraction from class implementation
*/
A new object creates an abstraction from class implementation
*/
const autosshInterface = {
on(evt, ...args) {
autossh.on(evt, ...args);