diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..20fe066 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Walter Vargas + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..10794c2 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# ewtunnel +Enterprise SSH Tunnel Tool Example + +## Download + +[ewtunnel releases](https://github.com/waltervargas/ewtunnel/releases "ewtunnel releases") + +## Usage + +1. Connect via RDP/SSH to a windows machine behind a ssh bastion. + + ``` + ewtunnel.exe --bastion bastion1.example.com --remotehost windows1.example.corp --rdpopen + ``` + +1. Connect via RDP/SSH to 2 windows machines behind a ssh bastion. + + ``` + ewtunnel.exe --localport 3388 --bastion bastion1.example.com --remotehost windows1.example.corp --rdpopen + ewtunnel.exe --localport 3390 --bastion bastion1.example.com --remotehost windows2.example.corp --rdpopen + ``` + +1. Connect via RDP/SSH using different user credentials + + ``` + ewtunnel.exe --user ANT\username --bastion bastion1.example.com --remotehost windows1.example.corp --rdpopen + ``` + +1. Connect via RDP/SSH using a different port on remote host + + ``` + ewtunnel.exe --bastion bastion1.example.com --remotehost windows1.example.corp --remoteport 3388 --rdpopen + ``` + +1. Connect via RDP/SSH using a different ssh port on the ssh bastion. + + ``` + ewtunnel.exe --bastion bastion1.example.com --bastionport 2222 --remotehost windows1.example.corp --remoteport 3388 --rdpopen + ``` diff --git a/ewtunnel.js b/ewtunnel.js new file mode 100644 index 0000000..d0147d7 --- /dev/null +++ b/ewtunnel.js @@ -0,0 +1,106 @@ +const tunnel = require('tunnel-ssh'); +const program = require('commander'); +const read = require('read'); +const { exec } = require('child_process'); +const fs = require('fs'); + +const username = process.env.USERDNSDOMAIN + "\\" + process.env.USERNAME; +const domain = process.env.USERDNSDOMAIN; +const user = process.env.USERNAME; +var rdp; + +program +.version('0.1.0') +.option('-u, --user [user]', 'Bastion User') +.option('-l, --localhost <127.0.0.1>', 'Local host') +.option('-lp, --localport ', 'Local Port', '3388') +.option('-b, --bastion ', 'Bastion Host') +.option('-bp, --bastionport <22>', 'Bastion Port') +.option('-r, --remotehost ', 'Remote Host') +.option('-rp, --remoteport <3389>', 'Remote Port') +.option('-rdp, --rdpopen', 'Open mstsc.exe on given host and port') +.parse(process.argv); + +read({ prompt: 'Password: ', silent: true }, function(er, password) { + + const config = { + keepAlive: true, + username: program.user || process.env.USERDNSDOMAIN + "\\" + process.env.USERNAME, + host: program.bastion, + port: program.bastionport || '22', + dstHost: program.remotehost, + dstPort: program.remoteport || '3389', + localHost: program.localhost || '127.0.0.1', + localPort: program.localport || '3388', + tryKeyboard: true, + password: password + }; + + const server = tunnel(config, (err, server) => { + if(err){ + console.log(err); + //catch configuration and startup errors here. + } else { + console.log("Connection Established - [" + config.host + "]"); + if (program.rdpopen) { + console.log("Opening RDP Session to: " + config.localHost + ":" + config.localPort); + console.log(config.localHost + ":" + config.localPort + " -> " + config.dstHost + ":" + config.dstPort); + // creates rdp2.rdp file + const rdpfile = process.cwd() + "\\rdp-" + config.dstHost + ".rdp"; + console.log(rdpfile); + fs.writeFile(rdpfile, "full address:s:localhost:3388\rusername:s:"+ user +"\rdomain:s:" + domain , function(err) { + if(err) { + return console.log(err); + } + console.log(rdpfile + " file was saved!"); + fs.stat(rdpfile, function (err, stats) { + if (err) { + return console.error(err); + } + rdp = exec("mstsc " + rdpfile, { + cwd: process.cwd(), + }, (err, stdout, stderr) => { + if (err) console.error(err); + }); + + rdp.on('exit', () => { + server.close(); + fs.unlink(rdpfile, (err) => { + if (err) throw err; + console.log(rdpfile + ': clean-up'); + process.exit(); + }); + }); + }); + }); + } + } + }); + + // Use a listener to handle errors outside the callback + server.on('error', function(err){ + + // Password Error + if (err.level && err.level === "client-authentication") { + console.log(" "); + console.log("--"); + console.log("ERROR: [EA01] SSH AUTHENTICATION ERROR"); + console.log("--"); + } + + // Reconnection + if (err.code && err.code === "ECONNRESET") { + // Ignore + } + }); + + process.on('SIGINT', function() { + close(server); + }); + +}); + +function close(server) { + server.close(); + process.exit(); +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..c2b87c7 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "ewtunnel", + "version": "1.0.0", + "description": "Enterprise SSH Tunnel Example", + "main": "ewtunnel.js", + "bin": { + "ewtunnel": "./ewtunnel.js" + }, + "author": "Walter Vargas", + "license": "ISC", + "dependencies": { + "commander": "^2.15.1", + "read": "^1.0.7", + "tcp-ping": "^0.1.1", + "tunnel-ssh": "^4.1.4" + }, + "pkg": { + "targets": [ + "win" + ] + } +}