Ssh2
SSH2 client and server modules written in pure JavaScript for node.js
Install / Use
/learn @mscdex/Ssh2README
Description
SSH2 client and server modules written in pure JavaScript for node.js.
Development/testing is done against OpenSSH (8.7 currently).
Changes (breaking or otherwise) in v1.0.0 can be found here.
Table of Contents
- Requirements
- Installation
- Client Examples
- Execute 'uptime' on a server
- Start an interactive shell session
- Send a raw HTTP request to port 80 on the server
- Forward local connections to port 8000 on the server to us
- Get a directory listing via SFTP
- Connection hopping
- Forward remote X11 connections
- Dynamic (1:1) port forwarding using a SOCKSv5 proxy (using
socksv5) - Make HTTP(S) connections easily using a custom http(s).Agent
- Invoke an arbitrary subsystem (e.g. netconf)
- Server Examples
- Other Examples
- API
Requirements
- node.js -- v10.16.0 or newer
- node v12.0.0 or newer for Ed25519 key support
- (Optional)
cpu-featuresis set as an optional package dependency (you do not need to install it explicitly/separately fromssh2) that will be automatically built and used if possible. See the project's documentation for its own requirements.- This addon is currently used to help generate an optimal default cipher list
Installation
npm install ssh2
Client Examples
Execute 'uptime' on a server
const { readFileSync } = require('fs');
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
console.log('Client :: ready');
conn.exec('uptime', (err, stream) => {
if (err) throw err;
stream.on('close', (code, signal) => {
console.log('Stream :: close :: code: ' + code + ', signal: ' + signal);
conn.end();
}).on('data', (data) => {
console.log('STDOUT: ' + data);
}).stderr.on('data', (data) => {
console.log('STDERR: ' + data);
});
});
}).connect({
host: '192.168.100.100',
port: 22,
username: 'frylock',
privateKey: readFileSync('/path/to/my/key')
});
// example output:
// Client :: ready
// STDOUT: 17:41:15 up 22 days, 18:09, 1 user, load average: 0.00, 0.01, 0.05
//
// Stream :: exit :: code: 0, signal: undefined
// Stream :: close
Start an interactive shell session
const { readFileSync } = require('fs');
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
console.log('Client :: ready');
conn.shell((err, stream) => {
if (err) throw err;
stream.on('close', () => {
console.log('Stream :: close');
conn.end();
}).on('data', (data) => {
console.log('OUTPUT: ' + data);
});
stream.end('ls -l\nexit\n');
});
}).connect({
host: '192.168.100.100',
port: 22,
username: 'frylock',
privateKey: readFileSync('/path/to/my/key')
});
// example output:
// Client :: ready
// STDOUT: Last login: Sun Jun 15 09:37:21 2014 from 192.168.100.100
//
// STDOUT: ls -l
// exit
//
// STDOUT: frylock@athf:~$ ls -l
//
// STDOUT: total 8
//
// STDOUT: drwxr-xr-x 2 frylock frylock 4096 Nov 18 2012 mydir
//
// STDOUT: -rw-r--r-- 1 frylock frylock 25 Apr 11 2013 test.txt
//
// STDOUT: frylock@athf:~$ exit
//
// STDOUT: logout
//
// Stream :: close
Send a raw HTTP request to port 80 on the server
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
console.log('Client :: ready');
conn.forwardOut('192.168.100.102', 8000, '127.0.0.1', 80, (err, stream) => {
if (err) throw err;
stream.on('close', () => {
console.log('TCP :: CLOSED');
conn.end();
}).on('data', (data) => {
console.log('TCP :: DATA: ' + data);
}).end([
'HEAD / HTTP/1.1',
'User-Agent: curl/7.27.0',
'Host: 127.0.0.1',
'Accept: */*',
'Connection: close',
'',
''
].join('\r\n'));
});
}).connect({
host: '192.168.100.100',
port: 22,
username: 'frylock',
password: 'nodejsrules'
});
// example output:
// Client :: ready
// TCP :: DATA: HTTP/1.1 200 OK
// Date: Thu, 15 Nov 2012 13:52:58 GMT
// Server: Apache/2.2.22 (Ubuntu)
// X-Powered-By: PHP/5.4.6-1ubuntu1
// Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT
// Content-Encoding: gzip
// Vary: Accept-Encoding
// Connection: close
// Content-Type: text/html; charset=UTF-8
//
//
// TCP :: CLOSED
Forward local connections to port 8000 on the server to us
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
console.log('Client :: ready');
conn.forwardIn('127.0.0.1', 8000, (err) => {
if (err) throw err;
console.log('Listening for connections on server on port 8000!');
});
}).on('tcp connection', (info, accept, reject) => {
console.log('TCP :: INCOMING CONNECTION:');
console.dir(info);
accept().on('close', () => {
console.log('TCP :: CLOSED');
}).on('data', (data) => {
console.log('TCP :: DATA: ' + data);
}).end([
'HTTP/1.1 404 Not Found',
'Date: Thu, 15 Nov 2012 02:07:58 GMT',
'Server: ForwardedConnection',
'Content-Length: 0',
'Connection: close',
'',
''
].join('\r\n'));
}).connect({
host: '192.168.100.100',
port: 22,
username: 'frylock',
password: 'nodejsrules'
});
// example output:
// Client :: ready
// Listening for connections on server on port 8000!
// (.... then from another terminal on the server: `curl -I http://127.0.0.1:8000`)
// TCP :: INCOMING CONNECTION: { destIP: '127.0.0.1',
// destPort: 8000,
// srcIP: '127.0.0.1',
// srcPort: 41969 }
// TCP DATA: HEAD / HTTP/1.1
// User-Agent: curl/7.27.0
// Host: 127.0.0.1:8000
// Accept: */*
//
//
// TCP :: CLOSED
Get a directory listing via SFTP
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
console.log('Client :: ready');
conn.sftp((err, sftp) => {
if (err) throw err;
sftp.readdir('foo', (err, list) => {
if (err) throw err;
console.dir(list);
conn.end();
});
});
}).connect({
host: '192.168.100.100',
port: 22,
username: 'frylock',
password: 'nodejsrules'
});
// example output:
// Client :: ready
// [ { filename: 'test.txt',
// longname: '-rw-r--r-- 1 frylock frylock 12 Nov 18 11:05 test.txt',
// attrs:
// { size: 12,
// uid: 1000,
// gid: 1000,
// mode: 33188,
// atime: 1353254750,
// mtime: 1353254744 } },
// { filename: 'mydir',
// longname: 'drwxr-xr-x 2 frylock frylock 4096 Nov 18 15:03 mydir',
// attrs:
// { size: 1048576,
// uid: 1000,
// gid: 1000,
// mode: 16877,
// atime: 1353269007,
// mtime: 1353269007 } } ]
Connection hopping
const { Client } = require('ssh2');
const conn1 = new Client();
const conn2 = new Client();
// Checks uptime on 10.1.1.40 via 192.168.1.1
conn1.on('ready', () => {
console.log('FIRST :: connection ready');
// 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, '10.1.1.40', 22, (err, stream) => {
if (err) {
console.log('FIRST :: forwardOut error: ' + err);
return conn1.end();
}
conn2.connect({
sock: stream,
username: 'user2',
password: 'password2',
});
});
}).connect({
host: '192.168.1.1',
username: 'user1',
password: 'password1',
});
conn2.on('ready', () => {
// This connection is the one to 10.1.1.40
console.log('SECOND :: connection ready');
conn2.exec('uptime', (err, stream) => {
if (err) {
console.log('SECOND :: exec error: ' + err);
return conn1.end();
}
stream.on('close', () => {
conn1.end(); // close parent (and this) connection
}).on('data', (data) => {
console.log(data.toString());
});
});
});
Forward remote X11 connections
const { Socket } = require('net');
const { Client } = require('ssh2');
const conn = new Client();
conn.on('x11', (info, accept, reject) => {
const xserversock = new net.Socket();
xserversock.on('connect', () => {
const xclientsock = accept();
xclientsock.pipe(xserversock).pipe(xclientsock);
});
// connects to localhost:0.0
xserversock.connect(6000, 'localhost');
});
conn.on('ready', () => {
conn.exec('xeyes', { x11: true }, (err, stream) => {
if (err) throw err;
let code = 0;
stream.on('close', ()
