diff --git a/app/index.js b/app/index.js index 436a4d49..87940396 100644 --- a/app/index.js +++ b/app/index.js @@ -17,6 +17,7 @@ server.listen({ host: config.listen.ip, port: config.listen.port }); // eslint-disable-next-line no-console console.log(`WebSSH2 service listening on ${config.listen.ip}:${config.listen.port}`); +console.log(`SSH proxy support is ${config.ssh_proxy.ssh_proxy_enabled}`); server.on('error', (err) => { if (err.code === 'EADDRINUSE') { diff --git a/app/server/config.js b/app/server/config.js index bb3639bc..5ee0a51f 100644 --- a/app/server/config.js +++ b/app/server/config.js @@ -22,6 +22,13 @@ const configDefault = { path: '/ssh/socket.io', origins: ['localhost:2222'], }, + ssh_proxy: { + ssh_proxy_enabled: false, + ssh_proxy_host: null, + ssh_proxy_user: null, + ssh_proxy_password: null, + ssh_proxy_privatekey: null, + }, express: { secret: crypto.randomBytes(20).toString('hex'), name: 'WebSSH2', diff --git a/app/server/socket.js b/app/server/socket.js index 9f49dc8d..b1b4e885 100644 --- a/app/server/socket.js +++ b/app/server/socket.js @@ -12,6 +12,8 @@ const validator = require('validator'); const dnsPromises = require('dns').promises; const util = require('util'); const { webssh2debug, auditLog, logError } = require('./logging'); +const { readFileSync } = require('fs'); +const config = require('./config'); /** * parse conn errors @@ -99,6 +101,7 @@ module.exports = function appSocket(socket) { } const conn = new SSH(); + const conn1 = new SSH(); conn.on('banner', (data) => { // need to convert to cr/lf for proper formatting @@ -200,11 +203,19 @@ module.exports = function appSocket(socket) { conn.on('end', (err) => { if (err) logError(socket, 'CONN END BY HOST', err); webssh2debug(socket, 'CONN END BY HOST'); + if (config.ssh_proxy.ssh_proxy_enabled ) { + conn1.end(); + } socket.disconnect(true); }); + conn.on('close', (err) => { if (err) logError(socket, 'CONN CLOSE', err); webssh2debug(socket, 'CONN CLOSE'); + if (config.ssh_proxy.ssh_proxy_enabled ) { + conn1.end(); + } + socket.disconnect(true); }); conn.on('error', (err) => connError(socket, err)); @@ -219,12 +230,42 @@ module.exports = function appSocket(socket) { socket.request.session.ssh ) { // console.log('hostkeys: ' + hostkeys[0].[0]) + const { ssh } = socket.request.session; ssh.username = socket.request.session.username; ssh.password = socket.request.session.userpassword; ssh.tryKeyboard = true; ssh.debug = debug('ssh2'); - conn.connect(ssh); + + if ( config.ssh_proxy.ssh_proxy_enabled ) { + conn1.on('ready', () => { + console.log(`vpn.cw :: connection ready over ${config.ssh_proxy.ssh_proxy_host} with user ${config.ssh_proxy.ssh_proxy_user} using ssh key auth`); + // Alternatively, you could use something like netcat or socat with exec() + // instead of forwardOut(), depending on what the server allows + conn1.forwardOut('127.0.0.1', 12345, socket.request.session.ssh.host, 22, (err, stream) => { + if (err) { + console.log('vpn.cw :: forwardOut error: ' + err); + return conn1.end(); + } + + console.log('Forwarding connection to '+ socket.request.session.ssh.host) + + const { ssh } = socket.request.session; + ssh.sock = stream + conn.connect( + ssh + ); + }); + }).connect({ + host: config.ssh_proxy.ssh_proxy_host, + username: config.ssh_proxy.ssh_proxy_user, + privateKey: readFileSync(config.ssh_proxy.ssh_proxy_privatekey), + }); + } else { + conn.connect( + ssh + ); + } } else { webssh2debug( socket,