mirror of
https://github.com/vale981/autossh
synced 2025-03-05 09:21:40 -05:00
adds reverse tunneling
This commit is contained in:
parent
056a2650cd
commit
ec5b31f263
3 changed files with 134 additions and 72 deletions
24
README.md
24
README.md
|
@ -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`.
|
||||
|
|
87
index.js
87
index.js
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
95
src/index.js
95
src/index.js
|
@ -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}`;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Reference in a new issue