tunnel-ssh
Advanced tools
Comparing version 4.1.6 to 5.0.0
140
index.js
@@ -1,112 +0,62 @@ | ||
var net = require('net'); | ||
var debug = require('debug')('tunnel-ssh'); | ||
var Connection = require('ssh2').Client; | ||
var createConfig = require('./lib/config'); | ||
var events = require('events'); | ||
var noop = function () { | ||
}; | ||
const net = require('net'); | ||
const { Client } = require('ssh2'); | ||
function bindSSHConnection(config, netConnection) { | ||
var sshConnection = new Connection(); | ||
netConnection.on('close', sshConnection.end.bind(sshConnection)); | ||
sshConnection.on('ready', function () { | ||
debug('sshConnection:ready'); | ||
netConnection.emit('sshConnection', sshConnection, netConnection); | ||
sshConnection.forwardOut(config.srcHost, config.srcPort, config.dstHost, config.dstPort, function (err, sshStream) { | ||
if (err) { | ||
// Bubble up the error => netConnection => server | ||
netConnection.emit('error', err); | ||
debug('Destination port:', err); | ||
return; | ||
function autoClose(server){ | ||
let interval = setInterval(()=>{ | ||
server.getConnections((error, count)=>{ | ||
if(count === 0){ | ||
server.close(); | ||
clearInterval(interval); | ||
} | ||
}); | ||
}, 1000); | ||
} | ||
debug('sshStream:create'); | ||
netConnection.emit('sshStream', sshStream); | ||
netConnection.pipe(sshStream).pipe(netConnection); | ||
}); | ||
async function createServer(options){ | ||
return new Promise(function(resolve, reject){ | ||
let server = net.createServer(); | ||
server.listen(options); | ||
server.on('listening', ()=> resolve(server)); | ||
server.on('error', reject); | ||
}); | ||
return sshConnection; | ||
} | ||
function omit(obj, keys) { | ||
return keys.reduce(function (copyObj, key) { | ||
delete copyObj[key]; | ||
return copyObj; | ||
}, Object.assign({}, obj)); | ||
async function createClient(config){ | ||
return new Promise(function(resolve, reject){ | ||
let conn = new Client(); | ||
conn.on('ready', () => resolve(conn)); | ||
conn.on('error', reject); | ||
conn.connect(config); | ||
}); | ||
} | ||
function createServer(config) { | ||
var server; | ||
var connections = []; | ||
var connectionCount = 0; | ||
async function createTunnel(tunnelOptions, serverOptions, sshOptions, forwardOptions){ | ||
server = net.createServer(function (netConnection) { | ||
var sshConnection; | ||
connectionCount++; | ||
netConnection.on('error', server.emit.bind(server, 'error')); | ||
netConnection.on('close', function () { | ||
connectionCount--; | ||
if (connectionCount === 0) { | ||
if (!config.keepAlive) { | ||
setTimeout(function () { | ||
if (connectionCount === 0) { | ||
server.close(); | ||
} | ||
}, 2); | ||
} | ||
} | ||
}); | ||
let isVirginConnection = true; | ||
server.emit('netConnection', netConnection, server); | ||
sshConnection = bindSSHConnection(config, netConnection); | ||
sshConnection.on('error', server.emit.bind(server, 'error')); | ||
return new Promise(function(resolve, reject){ | ||
createServer(serverOptions).then(function(server, reject){ | ||
createClient(sshOptions).then(function(conn){ | ||
server.on('connection',(connection)=>{ | ||
if(isVirginConnection && tunnelOptions.autoClose){ | ||
isVirginConnection = false; | ||
autoClose(server); | ||
} | ||
netConnection.on('sshStream', function (sshStream) { | ||
sshStream.on('error', function () { | ||
server.close(); | ||
conn.forwardOut( | ||
forwardOptions.srcAddr, | ||
forwardOptions.srcPort, | ||
forwardOptions.dstAddr, | ||
forwardOptions.dstPort, (err, stream) => { | ||
connection.pipe(stream).pipe(connection); | ||
}); | ||
}); | ||
server.on('close',()=> conn.end()); | ||
resolve([server, conn]); | ||
}); | ||
}); | ||
connections.push(sshConnection, netConnection); | ||
try { | ||
sshConnection.connect(omit(config, ['localPort', 'localHost'])); | ||
} catch (error) { | ||
server.emit('error', error); | ||
} | ||
}); | ||
server.on('close', function () { | ||
connections.forEach(function (connection) { | ||
connection.end(); | ||
}); | ||
}); | ||
return server; | ||
} | ||
function tunnel(configArgs, callback) { | ||
var server; | ||
var config; | ||
if (!callback) { | ||
callback = noop; | ||
} | ||
try { | ||
config = createConfig(configArgs); | ||
server = createServer(config); | ||
server.listen(config.localPort, config.localHost, function (error) { | ||
callback(error, server); | ||
}); | ||
} catch (e) { | ||
server = new events.EventEmitter(); | ||
setImmediate(function () { | ||
callback(e); | ||
server.emit('error', e); | ||
}); | ||
} | ||
return server; | ||
} | ||
module.exports = tunnel; | ||
exports.createTunnel = createTunnel; |
{ | ||
"name": "tunnel-ssh", | ||
"version": "4.1.6", | ||
"version": "5.0.0", | ||
"description": "Easy extendable SSH tunnel", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "mocha && eslint ." | ||
"publishConfig":{ | ||
"registry":"https://registry.npmjs.org" | ||
}, | ||
"scripts": {}, | ||
"repository": { | ||
@@ -18,3 +19,5 @@ "type": "git", | ||
"develop", | ||
"net" | ||
"net", | ||
"ssh-tunnel", | ||
"network" | ||
], | ||
@@ -27,24 +30,4 @@ "author": { | ||
"dependencies": { | ||
"debug": "2.6.9", | ||
"lodash.defaults": "^4.1.0", | ||
"ssh2": "1.4.0" | ||
}, | ||
"devDependencies": { | ||
"chai": "3.5.0", | ||
"eslint": "^3.2.2", | ||
"eslint-config-xo": "^0.17.0", | ||
"mocha": "^3.5.3" | ||
}, | ||
"eslintConfig": { | ||
"extends": "xo", | ||
"env": { | ||
"mocha": true | ||
}, | ||
"rules": { | ||
"indent": [ | ||
"error", | ||
4 | ||
] | ||
} | ||
"ssh2": "^1.11.0" | ||
} | ||
} |
@@ -11,17 +11,31 @@ Tunnel-SSH | ||
### Latest Relese 4.1.3 | ||
### Latest Relese 5.0.0 | ||
## Release notes | ||
* Closing sshconnections correctly thx @actionshrimp | ||
* Improved readme | ||
* Updated modules | ||
### Breaking change in 5.0.0 | ||
Please note that release 5.0.0 uses a complete different approch for configuration and is not compatible to prio versions. | ||
Special thanks to | ||
@vweevers and @dickeyxxx | ||
## Concept | ||
Tunnel-ssh v5 is designed to be very extendable and does not provide as much sematic sugar as prio versions. | ||
The design goal was to use the original settings for each part used in the project to be able to use all possible | ||
binding features from client and server. | ||
The configuration is separated in the following parts: | ||
### Related projects | ||
* [If you don't want to wrap a tunnel around your code: inject-tunnel-ssh](https://github.com/agebrock/inject-tunnel-ssh) | ||
* [If you need it the other way around: reverse-tunnel-ssh](https://github.com/agebrock/reverse-tunnel-ssh) | ||
* Tunnel server | ||
* TCP Server | ||
* SSH Client | ||
* SSH Forwarding | ||
### Tunnel Server Settings | ||
This configuration controls be behaviour of the tunnel server. | ||
Currently there is only one option available. | ||
``` | ||
const tunnelOptions = { | ||
autoClose:true | ||
} | ||
``` | ||
### Integration | ||
@@ -28,0 +42,0 @@ By default tunnel-ssh will close the tunnel after a client disconnects, so your cli tools should work in the same way, they do if you connect directly. |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
1
0
154
0
2
7772
5
52
+ Addedbuildcheck@0.0.6(transitive)
+ Addedcpu-features@0.0.10(transitive)
+ Addednan@2.22.0(transitive)
+ Addedssh2@1.16.0(transitive)
- Removeddebug@2.6.9
- Removedlodash.defaults@^4.1.0
- Removedcpu-features@0.0.2(transitive)
- Removeddebug@2.6.9(transitive)
- Removedlodash.defaults@4.2.0(transitive)
- Removedms@2.0.0(transitive)
- Removednan@2.22.2(transitive)
- Removedssh2@1.4.0(transitive)
Updatedssh2@^1.11.0