adds reverse tunneling

This commit is contained in:
Sam Eaton 2016-05-17 09:24:27 -06:00
parent 056a2650cd
commit ec5b31f263
3 changed files with 134 additions and 72 deletions

View file

@ -224,6 +224,30 @@ autossh({
<br />
#### Setting up a Reverse (Remote) Tunnel
To set up a reverse tunnel set `reverse` to `true` in the config object.
```javascript
autossh({
host: '111.22.333.444',
username: 'root',
localPort: 22,
remotePort: 5432,
reverse: true
})
.on('error', err => {
console.error('ERROR: ', err);
})
.on('connect', connection => {
console.log('connection pid: ' + connection.pid);
});
```
When using the reverse tunnel option, the `localPort` value cannot be `'auto'`.
<br />
#### Adjusting/Disabling Max Poll Count
When first trying to establish the ssh tunnel, `autoshh` will poll the local port until the connection has been established. The default max poll count is `30`.

View file

@ -36,21 +36,7 @@ var AutoSSH = function (_EventEmitter) {
var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(AutoSSH).call(this));
_this.host = conf.host;
_this.username = conf.username || 'root';
_this.remotePort = conf.remotePort;
_this.localPort = conf.localPort || 'auto';
_this.pollCount = 0;
_this.maxPollCount = conf.maxPollCount || 30;
_this.pollTimeout = 75;
_this.serverAliveInterval = typeof conf.serverAliveInterval === 'number' ? conf.serverAliveInterval : 120;
_this.serverAliveCountMax = typeof conf.serverAliveCountMax === 'number' ? conf.serverAliveCountMax : 1;
_this.sshPort = conf.sshPort || 22;
_this.privateKey = conf.privateKey || null;
_this.configure(conf);
setImmediate(function () {
var confErrors = _this.getConfErrors(conf);
@ -68,28 +54,55 @@ var AutoSSH = function (_EventEmitter) {
return _this;
}
/*
*/
_createClass(AutoSSH, [{
key: 'configure',
value: function configure(conf) {
this.reverse = conf.reverse === true || false;
this.host = conf.host;
this.username = conf.username || 'root';
this.remotePort = conf.remotePort;
if (this.reverse) this.localPort = parseInt(conf.localPort) || 22;else this.localPort = conf.localPort || 'auto';
this.pollCount = 0;
this.maxPollCount = conf.maxPollCount || 30;
this.pollTimeout = 75;
this.serverAliveInterval = typeof conf.serverAliveInterval === 'number' ? conf.serverAliveInterval : 120;
this.serverAliveCountMax = typeof conf.serverAliveCountMax === 'number' ? conf.serverAliveCountMax : 1;
this.sshPort = conf.sshPort || 22;
this.privateKey = conf.privateKey || null;
}
/*
*/
}, {
key: 'connect',
value: function connect(conf) {
var _this2 = this;
var port = this.localPort === 'auto' ? this.generateRandomPort() : this.localPort;
_portfinder2.default.getPort({ port: port }, function (portfinderErr, freePort) {
if (_this2.killed) return;
if (portfinderErr) _this2.emit('error', 'Port error: ' + portfinderErr);
if (_this2.localPort !== 'auto' && _this2.localPort !== freePort) _this2.emit('error', 'Port ' + _this2.localPort + ' is not available');else {
_this2.localPort = freePort;
// creates tunnel and then polls port until connection is established
_this2.execTunnel(function () {
_this2.pollConnection();
});
}
});
if (this.reverse) {
this.execTunnel(function () {
_this2.pollConnection();
});
} else {
_portfinder2.default.getPort({ port: port }, function (portfinderErr, freePort) {
if (_this2.killed) return;
if (portfinderErr) _this2.emit('error', 'Port error: ' + portfinderErr);
if (_this2.localPort !== 'auto' && _this2.localPort !== freePort) _this2.emit('error', 'Port ' + _this2.localPort + ' is not available');else {
_this2.localPort = freePort;
// creates tunnel and then polls port until connection is established
_this2.execTunnel(function () {
_this2.pollConnection();
});
}
});
}
}
/*
@ -196,7 +209,8 @@ var AutoSSH = function (_EventEmitter) {
key: 'getConfErrors',
value: function getConfErrors(conf) {
var errors = [];
if (!conf.localPort) errors.push('Missing localPort');else if (isNaN(parseInt(conf.localPort)) && conf.localPort !== 'auto') errors.push('Invalid localPort');
if (!conf.localPort) errors.push('Missing localPort');
if (conf.reverse === true && (conf.localPort === 'auto' || isNaN(parseInt(conf.localPort)))) errors.push('Invalid value for localPort');else if (isNaN(parseInt(conf.localPort)) && conf.localPort !== 'auto') errors.push('Invalid value for localPort');
if (!conf.host) errors.push('Missing host');else if (typeof conf.host !== 'string') {
errors.push('host must be type "string". was given "' + _typeof(conf.host) + '"');
@ -259,7 +273,7 @@ var AutoSSH = function (_EventEmitter) {
var serverAliveOpts = this.generateServerAliveOptions();
var defaultOpts = this.generateDefaultOptions();
var privateKey = this.privateKey ? '-i ' + this.privateKey : '';
var sshPort = this.sshPort ? '-p ' + this.sshPort : '';
var sshPort = this.sshPort === 22 ? '' : '-p ' + this.sshPort;
return defaultOpts + ' ' + serverAliveOpts + ' ' + privateKey + ' ' + sshPort;
}
@ -270,11 +284,14 @@ var AutoSSH = function (_EventEmitter) {
}, {
key: 'generateExecString',
value: function generateExecString() {
var bindAddress = this.localPort + ':localhost:' + this.remotePort;
var startPort = this.reverse ? this.remotePort : this.localPort;
var endPort = this.reverse ? this.localPort : this.remotePort;
var bindAddress = startPort + ':localhost:' + endPort;
var options = this.generateExecOptions();
var userAtHost = this.username + '@' + this.host;
var method = this.reverse ? 'R' : 'L';
return 'ssh -NL ' + bindAddress + ' ' + options + ' ' + userAtHost;
return 'ssh -N' + method + ' ' + bindAddress + ' ' + options + ' ' + userAtHost;
}
/*

View file

@ -10,23 +10,7 @@ class AutoSSH extends EventEmitter {
constructor(conf = {}) {
super();
this.host = conf.host;
this.username = conf.username || 'root';
this.remotePort = conf.remotePort;
this.localPort = conf.localPort || 'auto';
this.pollCount = 0;
this.maxPollCount = conf.maxPollCount || 30;
this.pollTimeout = 75;
this.serverAliveInterval = typeof conf.serverAliveInterval === 'number' ?
conf.serverAliveInterval : 120;
this.serverAliveCountMax = typeof conf.serverAliveCountMax === 'number' ?
conf.serverAliveCountMax : 1;
this.sshPort = conf.sshPort || 22;
this.privateKey = conf.privateKey || null;
this.configure(conf);
setImmediate(() => {
const confErrors = this.getConfErrors(conf);
@ -42,26 +26,58 @@ class AutoSSH extends EventEmitter {
});
}
configure(conf) {
this.reverse = conf.reverse === true || false;
this.host = conf.host;
this.username = conf.username || 'root';
this.remotePort = conf.remotePort;
if (this.reverse)
this.localPort = parseInt(conf.localPort) || 22;
else
this.localPort = conf.localPort || 'auto';
this.pollCount = 0;
this.maxPollCount = conf.maxPollCount || 30;
this.pollTimeout = 75;
this.serverAliveInterval = typeof conf.serverAliveInterval === 'number' ?
conf.serverAliveInterval : 120;
this.serverAliveCountMax = typeof conf.serverAliveCountMax === 'number' ?
conf.serverAliveCountMax : 1;
this.sshPort = conf.sshPort || 22;
this.privateKey = conf.privateKey || null;
}
/*
*/
connect(conf) {
const port = this.localPort === 'auto' ? this.generateRandomPort() : this.localPort;
portfinder.getPort({ port }, (portfinderErr, freePort) => {
if (this.killed)
return;
if (portfinderErr)
this.emit('error', 'Port error: ' + portfinderErr);
if (this.localPort !== 'auto' && this.localPort !== freePort)
this.emit('error', `Port ${this.localPort} is not available`);
else {
this.localPort = freePort;
// creates tunnel and then polls port until connection is established
this.execTunnel(() => {
this.pollConnection();
});
}
});
if (this.reverse) {
this.execTunnel(() => {
this.pollConnection();
});
}
else {
portfinder.getPort({ port }, (portfinderErr, freePort) => {
if (this.killed)
return;
if (portfinderErr)
this.emit('error', 'Port error: ' + portfinderErr);
if (this.localPort !== 'auto' && this.localPort !== freePort)
this.emit('error', `Port ${this.localPort} is not available`);
else {
this.localPort = freePort;
// creates tunnel and then polls port until connection is established
this.execTunnel(() => {
this.pollConnection();
});
}
});
}
}
/*
@ -151,8 +167,10 @@ class AutoSSH extends EventEmitter {
const errors = [];
if (!conf.localPort)
errors.push('Missing localPort');
if (conf.reverse === true && (conf.localPort === 'auto' || isNaN(parseInt(conf.localPort))))
errors.push('Invalid value for localPort');
else if (isNaN(parseInt(conf.localPort)) && conf.localPort !== 'auto')
errors.push('Invalid localPort');
errors.push('Invalid value for localPort');
if (!conf.host)
errors.push('Missing host');
@ -217,7 +235,7 @@ class AutoSSH extends EventEmitter {
const serverAliveOpts = this.generateServerAliveOptions();
const defaultOpts = this.generateDefaultOptions();
const privateKey = this.privateKey ? `-i ${this.privateKey}` : '';
const sshPort = this.sshPort ? `-p ${this.sshPort}` : '';
const sshPort = this.sshPort === 22 ? '' : `-p ${this.sshPort}`;
return `${defaultOpts} ${serverAliveOpts} ${privateKey} ${sshPort}`;
}
@ -225,11 +243,14 @@ class AutoSSH extends EventEmitter {
/*
*/
generateExecString() {
const bindAddress = `${this.localPort}:localhost:${this.remotePort}`;
const startPort = this.reverse ? this.remotePort : this.localPort;
const endPort = this.reverse ? this.localPort : this.remotePort;
const bindAddress = `${startPort}:localhost:${endPort}`;
const options = this.generateExecOptions();
const userAtHost = `${this.username}@${this.host}`;
const method = this.reverse ? 'R' : 'L';
return `ssh -NL ${bindAddress} ${options} ${userAtHost}`;
return `ssh -N${method} ${bindAddress} ${options} ${userAtHost}`;
}
/*