{"action":"created","issue":{"url":"https://api.github.com/repos/mscdex/ssh2/issues/64","repository_url":"https://api.github.com/repos/mscdex/ssh2","labels_url":"https://api.github.com/repos/mscdex/ssh2/issues/64/labels{/name}","comments_url":"https://api.github.com/repos/mscdex/ssh2/issues/64/comments","events_url":"https://api.github.com/repos/mscdex/ssh2/issues/64/events","html_url":"https://github.com/mscdex/ssh2/issues/64","id":16844282,"number":64,"title":"Tunnel with forwardOut question.","user":{"login":"matouka","id":3212312,"avatar_url":"https://avatars1.githubusercontent.com/u/3212312?v=4","gravatar_id":"","url":"https://api.github.com/users/matouka","html_url":"https://github.com/matouka","followers_url":"https://api.github.com/users/matouka/followers","following_url":"https://api.github.com/users/matouka/following{/other_user}","gists_url":"https://api.github.com/users/matouka/gists{/gist_id}","starred_url":"https://api.github.com/users/matouka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/matouka/subscriptions","organizations_url":"https://api.github.com/users/matouka/orgs","repos_url":"https://api.github.com/users/matouka/repos","events_url":"https://api.github.com/users/matouka/events{/privacy}","received_events_url":"https://api.github.com/users/matouka/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":9,"created_at":"2013-07-17T02:02:58Z","updated_at":"2017-09-28T04:49:11Z","closed_at":"2013-07-17T05:57:03Z","author_association":"NONE","body":"Hi,\n\nFirst I wanted to say that I am loving this library. Fantastic work!!\n\nI have a question because I have a server at a remote location that I would like to tunnel through to. I'm not sure that it's that unusual and I'm pretty sure I must be missing something here. There is a firewall in between that uses a key on port 222. Anyway, the way I normally do it is with a command like:\n\n``` bash\nssh -L localhost:2221:[SERVER IP]:22 -p 222 [F/WALL UNAME]@[F/WALL IP]\n```\n\nThen I just ssh into it:\n\n``` bash\nssh -p 2221 [SERVER UNAME]@localhost\n```\n\n This is an example of what I'm trying to do.\n\n``` javascript\nvar  fs = require('fs'),\n     Connection = require('ssh2');\n\nvar c1 = new Connection();\n\nc1.connect({\n  host: '[F/WALL IP]', \n  port: 222, \n  username: '[F/WALL UNAME]', \n  privateKey: require('fs').readFileSync('./keys/sample.key') \n});\n\nc1.on('ready', function(){\n  c1.forwardOut('localhost', 2221, '[SERVER IP]', 22, function(err, stream) {\n\n    if(err) throw err;\n    console.log('ForwardOut Ready!');\n\n    var c2 = new Connection();\n\n    c2.connect({\n      host: 'localhost', \n      port: 2221, \n      username: '[SERVER UNAME]', \n      password: '[SERVER PASSWORD]' \n    });\n\n    c2.on('ready', function(){\n      console.log('Connected!');\n    });\n\n    c2.on('error', function(err) {\n      console.log('Connection :: error :: ' + err);\n    });\n  })\n});\n\nc1.on('error', function(err) {\n  console.log('Connection :: error :: ' + err);\n});\n```\n\nThe ouput I get is:\n\nForwardOut Ready!\nConnection :: error :: Error: connect ECONNREFUSED\n\nIs there anything glaring that you can see I'm missing?\n\nCheers,\nPaul\n"},"comment":{"url":"https://api.github.com/repos/mscdex/ssh2/issues/comments/332726892","html_url":"https://github.com/mscdex/ssh2/issues/64#issuecomment-332726892","issue_url":"https://api.github.com/repos/mscdex/ssh2/issues/64","id":332726892,"user":{"login":"mscdex","id":54666,"avatar_url":"https://avatars0.githubusercontent.com/u/54666?v=4","gravatar_id":"","url":"https://api.github.com/users/mscdex","html_url":"https://github.com/mscdex","followers_url":"https://api.github.com/users/mscdex/followers","following_url":"https://api.github.com/users/mscdex/following{/other_user}","gists_url":"https://api.github.com/users/mscdex/gists{/gist_id}","starred_url":"https://api.github.com/users/mscdex/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mscdex/subscriptions","organizations_url":"https://api.github.com/users/mscdex/orgs","repos_url":"https://api.github.com/users/mscdex/repos","events_url":"https://api.github.com/users/mscdex/events{/privacy}","received_events_url":"https://api.github.com/users/mscdex/received_events","type":"User","site_admin":false},"created_at":"2017-09-28T04:49:10Z","updated_at":"2017-09-28T04:49:10Z","author_association":"OWNER","body":"@jpillora and anyone else who may be interested:\r\n\r\nHere's an example HTTP/HTTPS Agent implementation that tunnels requests over SSH. It could be improved a bit (e.g. actual/proper `ref()`/`unref()` handling) and it might be possible to simplify it a bit because for example, I *think* node may retry requests that never received a socket, so we may not need to manually handle the `'ready'` event handlers.\r\n\r\n```js\r\nvar HttpAgent = require('http').Agent;\r\nvar HttpsAgent = require('https').Agent;\r\nvar inherits = require('util').inherits;\r\n\r\nvar Client = require('ssh2').Client;\r\n\r\n[HttpAgent, HttpsAgent].forEach(function(ctor) {\r\n  function SSHAgent(connectCfg, agentOptions) {\r\n    if (!(this instanceof SSHAgent))\r\n      return new SSHAgent(connectCfg, agentOptions);\r\n\r\n    ctor.call(this, agentOptions);\r\n\r\n    createSSH(this, connectCfg);\r\n    this._defaultSrcIP = (agentOptions && agentOptions.srcIP) || 'localhost';\r\n    this._defaultDestIP = 'localhost';\r\n  }\r\n  inherits(SSHAgent, ctor);\r\n\r\n  SSHAgent.prototype.createConnection = createConnection;\r\n\r\n  exports[ctor === HttpAgent ? 'SSHTTPAgent' : 'SSHTTPSAgent'] = SSHAgent;\r\n});\r\n\r\nfunction createConnection(options, cb) {\r\n  if (!this._ready) {\r\n    const onReady = () => { this.createConnection(options, cb); };\r\n    onReady.httpCb = cb;\r\n    this._client.once('ready', onReady);\r\n    return;\r\n  }\r\n\r\n  var srcIP = (options && options.localAddress) || this._defaultSrcIP;\r\n  var srcPort = (options && options.localPort) || 0;\r\n  var dstIP = options.host || this._defaultDestIP;\r\n  var dstPort = options.port// || this._defaultDestPort;\r\n\r\n  this._client.forwardOut(srcIP, srcPort, dstIP, dstPort, (err, stream) => {\r\n    if (err)\r\n      return cb(err);\r\n    cb(null, decorateStream(stream));\r\n  });\r\n}\r\n\r\nfunction createSSH(agent, config) {\r\n  agent._ready = false;\r\n  agent._client = new Client();\r\n  agent._client.on('ready', function() {\r\n    agent._ready = true;\r\n  }).on('error', function(err) {\r\n    // Treat all errors has fatal, canceling pending http\r\n    // requests\r\n    const readies = this.listeners('ready');\r\n    for (var i = 0; i < readies.length; ++i) {\r\n      const fn = readies[i];\r\n      if (typeof fn.httpCb === 'function')\r\n        fn.httpCb(err);\r\n    }\r\n    this.removeAllListeners('ready');\r\n  }).on('close', function() {\r\n    createSSH(agent, config);\r\n\r\n    // Re-add callbacks for http requests that were waiting\r\n    // for an SSH connection\r\n    const readies = this.listeners('ready');\r\n    for (var i = 0; i < readies.length; ++i) {\r\n      const fn = readies[i];\r\n      if (typeof fn.httpCb === 'function')\r\n        agent._client.once('ready', fn);\r\n    }\r\n  }).connect(config);\r\n}\r\n\r\nfunction decorateStream(stream) {\r\n  stream.setKeepAlive = noop;\r\n  stream.setNoDelay = noop;\r\n  stream.setTimeout = noop;\r\n  stream.ref = noop;\r\n  stream.unref = noop;\r\n  stream.destroySoon = stream.destroy;\r\n  return stream;\r\n}\r\n\r\nfunction noop() {}\r\n```\r\n\r\nThen use like:\r\n```js\r\n// Or use `SSHTTPSAgent` for HTTPS\r\nconst httpAgent = new SSHTTPAgent({\r\n  host: '192.168.100.1',\r\n  username: 'foo',\r\n  agent: process.env.SSH_AUTH_SOCK\r\n});\r\n\r\nrequire('http').get({\r\n  host: '192.168.200.1',\r\n  agent: httpAgent\r\n}, (res) => {\r\n  console.log(res.statusCode);\r\n  console.dir(res.headers);\r\n  res.resume();\r\n});\r\n```"}}
{"actor":{"display_login":"mscdex"}}