Search code examples
node.jssshremote-accessopenwrtdropbear

NodeJS remote terminal to Dropbear OpenWRT-Server


I am wandering whether there is a valid solution to have a remote terminal to a OpenWRT-Box out of an NodeJS-APP?

Connecting from terminal works: ssh -i ~/.myKeys/id_rsa [email protected]

BusyBox v1.23.2 (2015-04-22 23:25:48 UTC) built-in shell (ash)

root@openwrt:~#

The only interactive ssh solution for NodeJS doesn't do the interactive part as described in the README.md as following:

var Client = require('ssh2').Client;

var conn = new Client();
conn.on('ready', function() {
  console.log('Client :: ready');
  conn.shell(function(err, stream) {
    if (err) throw err;
    stream.on('close', function() {
      console.log('Stream :: close');
      conn.end();
    }).on('data', function(data) {
      console.log('STDOUT: ' + data);
    }).stderr.on('data', function(data) {
      console.log('STDERR: ' + data);
    });
    stream.end('ls -l\nexit\n');
  });
}).connect({
  host: '192.168.100.100',
  port: 22,
  username: 'frylock',
  privateKey: require('fs').readFileSync('/here/is/my/key')
});

It is only tested against OpenSSH. Also a solution setting atop of this ssh2 node lib doesn't work. It was build to identify the prompt (e.g.)

So my next idea had been, to execute a shell command with stdin and stdout as child_process

var spawn = require('child_process').spawn;
               var ssh    = spawn('ssh', ['-tt', 'root@'+host]);
                    process.stdin.resume();
                    process.stdin.on('data', function (chunk) {
                      ssh.stdin.write(chunk);
                    });

... hangs also like the first solution.

My last idea was to exit the NodeJS-App and execute the operating systems ssh command with params out of the terminated NodeJS-App. But I couldn't find a way to do this. After thinking about, I noticed ... it is only an error code nothing else what comes back from a terminated process. So it has to be a child_process what gains full stdin/stdout/stderr ... but what is the right way to do this?

And does it work with Dropbear-Servers ?

Here you can find the virtual machine I am testing against.


Solution

  • If you want the "interactive part" with ssh2, you need to actually pipe between the remote shell process and the local stdin/stdout/stderr as that is not done automatically:

    var fs = require('fs');
    var Client = require('ssh2').Client;
    
    var conn = new Client();
    conn.on('ready', function() {
      console.log('Client :: ready');
      conn.shell(function(err, stream) {
        if (err) throw err;
        stream.on('close', function() {
          console.log('Stream :: close');
          conn.end();
        });
        stream.pipe(process.stdout);
        stream.stderr.pipe(process.stderr);
        process.stdin.pipe(stream);
      });
    }).connect({
      host: '192.168.178.39',
      port: 22,
      username: 'root',
      privateKey: fs.readFileSync('/home/' + process.env.USER + '/.myKeys/id_rsa')
    });