├── .gitignore ├── LICENSE ├── README.md ├── examples └── reverse.js ├── index.js ├── lib └── config.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | .idea 5 | .DS_STORE 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # Compiled binary addons (http://nodejs.org/api/addons.html) 21 | build/Release 22 | 23 | # Dependency directory 24 | # Deployed apps should consider commenting this line out: 25 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git 26 | node_modules 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Christoph Hagenbrock 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # reverse-tunnel-ssh 2 | Easy ssh reverse tunnel 3 | 4 | ![Tunnel-SSH Logo](https://i.imgur.com/2pdoADB.png) 5 | 6 | 7 | ##How to use 8 | ```sh 9 | npm i reverse-tunnel-ssh (--save) 10 | ``` 11 | 12 | ```js 13 | 14 | // Tunnel your local port 8000 to tunneltest.com:8000 15 | 16 | //tunnel is a ssh2 clientConnection object 17 | var tunnel = require('reverse-tunnel-ssh'); 18 | tunnel({ 19 | host: 'tunneltest.com', 20 | username: 'root', 21 | dstHost: '0.0.0.0', // bind to all IPv4 interfaces 22 | dstPort: 8000, 23 | //srcHost: '127.0.0.1', // default 24 | //srcPort: dstPort // default is the same as dstPort 25 | }, function(error, clientConnection) { 26 | // 27 | }); 28 | 29 | // Tunnel your local port 8000 to a free port on tunneltest.com 30 | 31 | var conn = tunnel({ 32 | host: 'tunneltest.com', 33 | username: 'somebody', 34 | dstHost: '0.0.0.0', // bind to all IPv4 interfaces 35 | dstPort: 0, // dynamically choose an open port on tunneltest.com 36 | //srcHost: '127.0.0.1', // default 37 | srcPort: 8000, // must be specified if dstPort=0 38 | }, function (error, clientConnection) { 39 | // 40 | }); 41 | conn.on('forward-in', function (port) { 42 | console.log('Forwarding from tunneltest.com:' + port); 43 | }); 44 | ``` 45 | 46 | If you plan to expose a local port on a remote machine (external interface) you need to enable the "GatewayPorts" option in your 'sshd_config' 47 | 48 | ```sh 49 | # What ports, IPs and protocols we listen for 50 | Port 22 51 | GatewayPorts yes 52 | ``` 53 | -------------------------------------------------------------------------------- /examples/reverse.js: -------------------------------------------------------------------------------- 1 | var tunnel = require('reverse-tunnel-ssh'); 2 | 3 | 4 | // This is a very handy way to test your next webhook ! 5 | 6 | // Please set up your /etc/hosts or change the hostname befor 7 | // running the example. 8 | 9 | 10 | var config = { 11 | host: 'tunneltest.com', 12 | username: 'root', 13 | dstHost: '0.0.0.0', // bind to all interfaces (see hint in the readme) 14 | dstPort: 8000, 15 | //srcHost: '127.0.0.1', // default 16 | //srcPort: dstPort // default is the same as dstPort 17 | } 18 | tunnel(config, function(error, clientConnection) { 19 | console.log(clientConnection._forwarding); 20 | }); 21 | 22 | require('http').createServer(function(res, res){ 23 | res.end('SSH-TUNNEL: Gate to heaven !'); 24 | }).listen(config.dstPort); 25 | 26 | console.log('Tunnel created: http://'+config.host+':'+config.dstPort); 27 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var Client = require('ssh2').Client; 2 | var Socket = require('net').Socket; 3 | var debug = require('debug')('reverse-tunnel-ssh'); 4 | 5 | var createConfig = require('./lib/config'); 6 | 7 | function createClient(rawConfig, callback) { 8 | var config = createConfig(rawConfig); 9 | var remoteHost = config.dstHost; 10 | var remotePort = config.dstPort; 11 | var srcHost = config.srcHost; 12 | var srcPort = config.srcPort; 13 | 14 | var conn = new Client(); 15 | var errors = []; 16 | 17 | conn.on('ready', function() { 18 | debug('ready'); 19 | conn.forwardIn(remoteHost, remotePort, function(err, port) { 20 | if (err) { 21 | errors.push(err); 22 | throw err; 23 | } 24 | conn.emit('forward-in', port); 25 | }); 26 | }); 27 | 28 | conn.on('tcp connection', function(info, accept, reject) { 29 | var remote; 30 | var srcSocket = new Socket(); 31 | 32 | debug('tcp connection', info); 33 | srcSocket.on('error', function(err) { 34 | errors.push(err); 35 | if (remote === undefined) { 36 | reject(); 37 | } else { 38 | remote.end(); 39 | } 40 | }); 41 | 42 | srcSocket.connect(srcPort, srcHost, function() { 43 | remote = accept(); 44 | debug('accept remote connection'); 45 | srcSocket.pipe(remote).pipe(srcSocket); 46 | if (errors.length === 0) { 47 | callback(null, conn); 48 | } else { 49 | callback(errors, null); 50 | } 51 | }); 52 | 53 | }); 54 | conn.connect(config); 55 | return conn; 56 | } 57 | 58 | module.exports = createClient; 59 | -------------------------------------------------------------------------------- /lib/config.js: -------------------------------------------------------------------------------- 1 | var defaults = require('lodash.defaults'); 2 | 3 | function createConfig(userConfig) { 4 | var env = process.env; 5 | 6 | var config = defaults(userConfig || {}, { 7 | username: env.TUNNELSSH_USER || env.USER || env.USERNAME, 8 | sshPort: 22, 9 | srcHost: 'localhost', 10 | dstPort: null, 11 | dstHost: 'localhost', 12 | localHost: 'localhost' 13 | }); 14 | 15 | // Try to use ssh-agent if no auth information was set 16 | if (!config.password && !config.privateKey) { 17 | config.agent = config.agent || process.env.SSH_AUTH_SOCK; 18 | } 19 | 20 | // No local route, no remote route.. exit here 21 | if (config.dstPort === null || !config.dstHost || !config.host) { 22 | throw new Error('invalid configuration.'); 23 | } 24 | 25 | // Use the same port number local 26 | if (config.srcPort === undefined) { 27 | if (!config.dstPort) { 28 | throw new Error('must specify srcPort or dstPort'); 29 | } 30 | config.srcPort = config.dstPort; 31 | } 32 | 33 | return config; 34 | }; 35 | 36 | module.exports = createConfig; 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reverse-tunnel-ssh", 3 | "version": "1.1.0", 4 | "description": "Easy reverse ssh tunnel ", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "npm test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+ssh://git@github.com/agebrock/reverse-tunnel-ssh.git" 12 | }, 13 | "keywords": [ 14 | "ssh", 15 | "tunnel", 16 | "reverse", 17 | "webhooks", 18 | "develop" 19 | ], 20 | "author": "christoph.hagenbrock@googlemail.com", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/agebrock/reverse-tunnel-ssh/issues" 24 | }, 25 | "homepage": "https://github.com/agebrock/reverse-tunnel-ssh#readme", 26 | "dependencies": { 27 | "debug": "2.2.0", 28 | "lodash.defaults": "^4.2.0", 29 | "ssh2": "0.5.2" 30 | } 31 | } 32 | --------------------------------------------------------------------------------