Nodejs ssh2 run multiple command only one terminal - javascript

I am in a trouble while coding ssh2 module in my project. I tried to run multiple commands on one terminal for ruling remote Linux system. For example "bc" command provides you a basic calculator and you can run it for basic operations. but that kind of processes need to be awake when you are using (it will accepts two or more input and it will give a response as a result).
I need to create a system like work with websocket and ssh. When a websocket received a command ,ssh node need to execute this message and Module need to send it's response via websocket.send()
I am using Node.js websocket,ssh2 client.
Here my code :
#!/usr/bin/node
var Connection = require('ssh2');
var conn = new Connection();
var command="";
var http = require('http');
var WebSocketServer = require('websocket').server;
var firstcom=true;
conn.on('ready', function() {
console.log('Connection :: ready');
// conn.shell(onShell);
});
var onShell = function(err, stream) {
// stream.write(command+'\n');
stream.on('data', function(data) {
console.log('STDOUT: ' + data);
});
stream.stderr.on('data', function(data) {
console.log('STDERR: ' + data);
});
}
var webSocketsServerPort=5000;
var ssh2ConnectionControl=false;
var server = http.createServer(function (req, res) {
//blahbalh
}).listen(webSocketsServerPort, function() {
console.log((new Date()) + " Server is listening on port:: " + webSocketsServerPort);
});
//console.log((new Date()) + 'server created');
wsServer = new WebSocketServer({
httpServer: server,
// autoAcceptConnections: false
});
wsServer.on('request', function(request) {
console.log((new Date()) + ' Connection from origin ' + request.origin + '.');
var wsconnection = request.accept('echo-protocol', request.origin);
console.log((new Date()) + ' Connection accepted.');
if(!ssh2ConnectionControl){
conn.connect({
host: 'localhost',
port: 22,
username: 'attilaakinci',
password: '1'
});
ssh2ConnectionControl=true;
console.log('SSH Connected.');
}
wsconnection.on('message', function(message) {
if (message.type === 'utf8') {
console.log('Received Message: ' + message.utf8Data);
command=message.utf8Data;
//if(firstcom){
// conn.shell(onShell);
// firstcom=false;
//}else{
conn.exec(message.utf8Data,onShell);
//}
wsconnection.send(message.utf8Data);
}
else{
console.log('Invalid message');
}
});
wsconnection.on('close', function(reasonCode, description) {
console.log((new Date()) + ' Peer ' + wsconnection.remoteAddress + ' disconnected.');
});
});

You should use conn.shell() instead of conn.exec() if you want a real interactive shell. conn.exec() is typically for executing one-liner commands, so it does not persist "shell state" between conn.exec() calls (e.g. working directory, etc.).
You should also be aware of possible limits by your SSH server has set up as far as how many simultaneous shell/exec requests are allowed per connection. I think the default limit for this on OpenSSH's server is 10.

This is an old question but I wanted to provide a alternative method usings sh2shell which wraps ssh2.shell by mscdex, used above. The example below only covers making the ssh connection, running the commands and processing the result.
Using ssh2shel it is possible to run any number of commands sequentually in the context of the previous commands in the same shell session and then return the output for each command (onCommandComplete event) and/or return all session text on disconnection using a callback function.
See the ssh2shell readme for examples and lots of info. There are also tested scripts for working code examples.
var host = {
//ssh2.client.connect options
server: {
host: 120.0.0.1,
port: 22,
userName: username,
password: password
},
debug: false,
//array of commands run in the same session
commands: [
"echo $(pwd)",
command1,
command2,
command3
],
//process each command response
onCommandComplete: function( command, response, sshObj) {
//handle just one command or do it for all of the each time
if (command === "echo $(pwd)"){
this.emit("msg", response);
}
}
};
//host object can be defined earlier and host.commands = [....] set repeatedly later with each reconnection.
var SSH2Shell = require ('ssh2shell');
var SSH = new SSH2Shell(host),
callback = function( sessionText ){
console.log ( "-----Callback session text:\n" + sessionText);
console.log ( "-----Callback end" );
}
SSH.connect(callback)
To see what is happening at process level set debug to true.

Related

Nodejs and WebSockets Failed to construct 'WebSocket': The subprotocol '[object Object]' is invalid

So my main webpage example.com is run through cloudflare and has a edge certificate from Origin -> CF Edge (origin cert) and an edge certificate CF Edge -> Client. I'm bypassing this for my websocket by using a subdomain, dt.example.com which uses cloudflare although using this link resolves the origin server address rather than the cloudflare edge server address (which i've found solves some issues for me, or maybe it's counterproductive to use this method?). Anyway, I am using a free ssl certificate for secure websockets -
'use strict';
var https = require('https');
var fs= require('fs');
var express = require('express');
var WebSocket = require('ws');
var server = https.createServer({
cert: fs.readFileSync('../ssl/wss/new/certificate.crt'),
key: fs.readFileSync('../ssl/wss/new/private.pem'),
ca: fs.readFileSync('../ssl/wss/new/ca_bundle.crt')
});
const wss = new WebSocket.Server({server});
wss.on('connection', function connection (ws) {
ws.on('message', function message (msg) {
console.log(msg);
});
});
server.listen(58443, function listening () {
const ws = new WebSocket('wss://dt.example.com:58443', {
rejectUnauthorized: false
});
ws.on('open', function open () {
ws.send('Workin baby');
});
});
-and using a websocket client plugin for chrome allows me to connect to the socket, however i cannot on example.com/webpage where the follow code is:
var ws = new window.WebSocket('wss://dt.example.com:58443/', {
rejectUnauthorized: false
});
ws.on('open', function open () {
ws.send('What\'s crackin?');
});
Although in browser (Chrome) when the client script executes it exits with the following error Uncaught DOMException: Failed to construct 'WebSocket': The subprotocol '[object Object]' is invalid. (on line 1)
I managed to solve this by stumbling across something intriguing in a post elswhere.
Essentially I just moved the rejectUnauthorized into the server code and then retried running on the client and it connected to the server :)
So there are two ways of doing this i'll list out both of them ,for more information you can visit https://www.npmjs.com/package/websocket
Using W3CWebSocket
var ws= require('websocket').w3cwebsocket;
var client = new W3CWebSocket('wss://dt.example.com:58443/'{
rejectUnauthorized: false
}, 'echo-protocol');
client.onerror = function() {
console.log('Connection Error');
};C
client.onopen = function open () {
ws.send('What\'s crackin mate?');
};
client.onclose = function() {
console.log('echo-protocol Client Closed');
};
client.onmessage = function(e) {
if (typeof e.data === 'string') {
console.log("Received: '" + e.data + "'");
}
};
Using a normal websocket client
var WebSocketClient = require('websocket').client;
var client = new WebSocketClient();
client.on('connectFailed', function(error) {
console.log('Connect Error: ' + error.toString());
});
client.on('connect', function(connection) {
console.log('WebSocket Client Connected');
connection.on('error', function(error) {
console.log("Connection Error: " + error.toString());
});
connection.on('close', function() {
console.log('echo-protocol Connection Closed');
});
connection.on('message', function(message) {
if (message.type === 'utf8') {
console.log("Received: '" + message.utf8Data + "'");
}
});
});
client.connect('ws://localhost:8080/', 'echo-protocol');
You can solve this problem by adding corresponding protocol value in front side to the response header in back-end side with key = "Sec-WebSocket-Protocol".
In your case , you should add a HTTP header with key "Sec-WebSocket-Protocol" and with value "Chat-1.0"

Node.js TCP Connections

I am trying to write a Node.js app that will perform TCP connections to some TCP/IP modules we use in the office. These modules are installed in old consoles and therefore the software to manage them is very old and it is no longer supported. The way we operate them now is to use the command prompt in Windows and connect to them that way. Here is how we are currently doing it.
>telnet <XX.XX.XX.XX> <PORT>
if the connection is successful then we get a blank screen in which we then type
<Ctrl+A> 200
Where is holding the Ctrl key and the A key at the same time, followed by the number 200. It then pops out some simple details about the module, which is what we want. This method works for us, but the problem is that it is not practical when you have 20+ of these modules each with different IPs. We have to connect to them every week to make sure they are working and doing 20 of them really takes up a lot of your time, so we want to optimize the process. We began writing a mini app in Node.js that takes care of the connections
var net = require('net');
var HOST_ARR = ['XX.XX.XX.XX'];
var PORT = 10001;
var client = new net.Socket();
var spawn = require('child_process').spawn('cmd');
var exec = require('child_process').exec;
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function connect(host, port){
return new Promise(function(resolve, reject){
client.connect(port, host, function() {
// Write a message to the socket as soon as the client is connected
console.log('CONNECTED TO: ' + host + ':' + port);
/*** EXECUTE <Ctrl+A> 200 COMMAND BEFORE CLOSING THE CONNECTION ***/
resolve('Success');
//end connection
client.destroy();
});
//handle errors
client.on('error', function(err) {
reject(err.code);
});
});
}
We are able to connect to the modules just fine, and the process is extremely fast. We are just stuck on how to execute the command <Ctrl+A> 200 once the connection starts. Any suggestions?
I tried
exec('\0x01200', function(error, stdout, stderr) { //ASCII for <Ctrl+A> is \0x01
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
but did not work. Thanks in advance
How about just sending <Ctrl+A>200 by client after connected Like:
client.write(new Buffer([
0x01, // Ctrl-A
0x32, // 2
0x30, // 0
0x30, // 0
// uncomment if necessary
// 0x0d, // \r
// 0x0a, // \n
]));

fail to connect localhost:8081 using node.js

I have opened the server.js and the address:http://localhost:8081 on my browser. But then a text "Upgrade Required" appeared at the top left conern of the website.
What is the problem of that? What else do I need to upgrade?
Here is the server.js:
var serialport = require('serialport');
var WebSocketServer = require('ws').Server;
var SERVER_PORT = 8081;
var wss = new WebSocketServer({
port: SERVER_PORT
});
var connections = new Array;
SerialPort = serialport.SerialPort,
portName = process.argv[2],
serialOptions = {
baudRate: 9600,
parser: serialport.parsers.readline('\n')
};
if (typeof portName === "undefined") {
console.log("You need to specify the serial port when you launch this script, like so:\n");
console.log(" node wsServer.js <portname>");
console.log("\n Fill in the name of your serial port in place of <portname> \n");
process.exit(1);
}
var myPort = new SerialPort(portName, serialOptions);
myPort.on('open', showPortOpen);
myPort.on('data', sendSerialData);
myPort.on('close', showPortClose);
myPort.on('error', showError);
function showPortOpen() {
console.log('port open. Data rate: ' + myPort.options.baudRate);
}
function sendSerialData(data) {
if (connections.length > 0) {
broadcast(data);
}
}
function showPortClose() {
console.log('port closed.');
}
function showError(error) {
console.log('Serial port error: ' + error);
}
function sendToSerial(data) {
console.log("sending to serial: " + data);
myPort.write(data);
}
wss.on('connection', handleConnection);
function handleConnection(client) {
console.log("New Connection");
connections.push(client);
client.on('message', sendToSerial);
client.on('close', function () {
console.log("connection closed");
var position = connections.indexOf(client);
connections.splice(position, 1);
});
}
function broadcast(data) {
for (c in connections) {
connections[c].send(data);
}
}
OK, websockets...
The "upgrade required" status marks the start of a websocket handshake. Normally your client sends this first to the WS server. The server answers in a pretty similar manner (details here : https://www.rfc-editor.org/rfc/rfc6455 ), and then proceed to pipe the actual data.
Here, you're opening a connection from your client as regular http, sending a simple GET. What you see on the screen is the server dumbly proceeding with an already corrupted handshake.
That's not how you open a WS client side connection. You don't usually open WS pages from the browser. It ought to be opened from a JavaScript call, such as new WebSocket(uri). So what you want is a regular http server on another port, that serves a page containing the necessary Javascript to open the actual WS connection and do something useful with its data. You'll find a clean example here : http://www.websocket.org/echo.html

Duplicate Events Socket.io and Node.js over STOMP

I need some help about my node.js+socket.io implementation.
This service expose a server that connects to an ActiveMQ broker over the STOMP protocol, using the stomp-js node.js module to receive events; that then are displayed in a web front end through websockets using socket.io.
So, everything was fine until I started use the Filters feature of ActiveMQ, but this was not the failure point because of my and my team researching, we found the way to ensure the implementation was fine, the problem comes with the connections: So here's the thing, I receive the filters to subscribe, I successfully subscribe to but when I receive a new set of filters is when comes the duplicated, triplicated and more and more messages depending the number of times that I subscribe-unsubscribe to.
So making some debug, I cannot see what's the problem but I'm almost sure that is some bad implementation of the callbacks or the program flow, I'll attach my code to read your comments about it.
Thanks a lot!
var sys = require('util');
var stomp = require('stomp');
var io = require('socket.io').listen(3000);
var socket = io.sockets.on('connection', function (socket) {
var stomp_args = {
port: 61616,
host: 'IP.ADDRESS',
debug: true,
};
var headers;
var client = new stomp.Stomp(stomp_args);
var setFilters = false;
socket.on('filtros', function (message) {
console.log('DEBUG: Getting filters');
if(setFilters){
client.unsubscribe(headers);
}
else{
client.connect();
}
var selector = '';
headers = '';
for(var attributename in message){
console.log(attributename+" : " + message[attributename]);
if(message[attributename] != ''){
selector += ' ' + attributename + '=\'' + message[attributename] + '\' AND ';
}
}
selector = selector.substring(0, selector.length - 4)
console.log('DEBUG: Selector String: ' + selector);
headers = {
destination: '/topic/virtualtopic',
ack: 'client',
selector: selector
};
if(setFilters)
client.subscribe(headers);
client.on('connected', function() {
client.subscribe(headers);
console.log('DEBUG: Client Connected');
setFilters = true;
});
});
var bufferMessage;
client.on('message', function(message) {
console.log("Got message: " + message.headers['message-id']);
var jsonMessage = JSON.parse(message.body);
if(bufferMessage === jsonMessage){
console.log('DEBUG: recibo un mensaje repetido');
return 0;
}
else{
console.log('DEBUG: Cool');
socket.emit('eventoCajero', jsonMessage);
}
client.ack(message.headers['message-id']);
bufferMessage = jsonMessage;
});
socket.on('disconnect', function(){
console.log('DEBUG: Client disconnected');
if(setFilters){
console.log('DEBUG: Consumer disconnected');
client.disconnect();
}
});
client.on('error', function(error_frame) {
console.log(error_frame.body);
});
});
Looking in the Socket.IO documentation, I've found that this is a known issue (I think critical known issue) and they have not fixed it yet. So, to correct this is necessary to reconnect to the socket in the client side to avoid duplicate messages, using:
socket.socket.reconnect();
function to force reconnection explicitly.

Send Broadcast datagram

I need to send a broadcast datagram to all machine (servers) connected to my network.
I'm using NodeJS Multicast
Client
var dgram = require('dgram');
var message = new Buffer("Some bytes");
var client = dgram.createSocket("udp4");
client.send(message, 0, message.length, 41234, "localhost");
// If I'm in the same machine 'localhost' works
// I need to do something 192.168.0.255 or 255.255.255
client.close();
Servers
var dgram = require("dgram");
var server = dgram.createSocket("udp4");
server.on("message", function (msg, rinfo) {
console.log("server got: " + msg + " from " +
rinfo.address + ":" + rinfo.port);
});
server.on("listening", function () {
var address = server.address();
console.log("server listening " + address.address + ":" + address.port);
});
server.bind(41234);
Thanks.
I spent a lot of time trying to be able to do UDP broadcasting and multicasting between computers. Hopefully this makes it easier for others since this topic is quite difficult to find answers for on the web. These solutions work in Node versions 6.x-12.x:
UDP Broadcasting
Calculate the broadcast address
Broadcast address = (~subnet mask) | (host's IP address) - see Wikipedia. Use ipconfig(Windows) or ifconfig(Linux), or checkout the netmask module.
Server (remember to change BROADCAST_ADDR to the correct broadcast address)
var PORT = 6024;
var BROADCAST_ADDR = "58.65.67.255";
var dgram = require('dgram');
var server = dgram.createSocket("udp4");
server.bind(function() {
server.setBroadcast(true);
setInterval(broadcastNew, 3000);
});
function broadcastNew() {
var message = Buffer.from("Broadcast message!");
server.send(message, 0, message.length, PORT, BROADCAST_ADDR, function() {
console.log("Sent '" + message + "'");
});
}
Client
var PORT = 6024;
var dgram = require('dgram');
var client = dgram.createSocket('udp4');
client.on('listening', function () {
var address = client.address();
console.log('UDP Client listening on ' + address.address + ":" + address.port);
client.setBroadcast(true);
});
client.on('message', function (message, rinfo) {
console.log('Message from: ' + rinfo.address + ':' + rinfo.port +' - ' + message);
});
client.bind(PORT);
UDP Multicasting
Multicast addresses
Looking at the IPv4 Multicast Address Space Registry and more in-depth clarification in the RFC 2365 manual section 6, we find the appropriate local scope multicast addresses are 239.255.0.0/16 and 239.192.0.0/14 (that is, unless you obtain permission to use other ones).
The multicast code below works just fine on Linux (and many other platforms) with these addresses.
Most operating systems send and listen for multicasts via specific interfaces, and by default they will often choose the wrong interface if multiple interfaces are available, so you never receive multicasts on another machine (you only receive them on localhost). Read more in the Node.js docs. For the code to work reliably, change the code so you specify the host's IP address for the interface you wish to use, as follows:
Server - server.bind(SRC_PORT, HOST_IP_ADDRESS, function() ...
Client - client.addMembership(MULTICAST_ADDR, HOST_IP_ADDRESS);
Take a look at these supporting sources: NodeJS, Java, C#, and a helpful command to see which multicast addresses you are subscribed to - netsh interface ipv4 show joins.
Server
var SRC_PORT = 6025;
var PORT = 6024;
var MULTICAST_ADDR = '239.255.255.250';
var dgram = require('dgram');
var server = dgram.createSocket("udp4");
server.bind(SRC_PORT, function () { // Add the HOST_IP_ADDRESS for reliability
setInterval(multicastNew, 4000);
});
function multicastNew() {
var message = Buffer.from("Multicast message!");
server.send(message, 0, message.length, PORT, MULTICAST_ADDR, function () {
console.log("Sent '" + message + "'");
});
}
Client
var PORT = 6024;
var MULTICAST_ADDR = '239.255.255.250';
var dgram = require('dgram');
var client = dgram.createSocket('udp4');
client.on('listening', function () {
var address = client.address();
console.log('UDP Client listening on ' + address.address + ":" + address.port);
});
client.on('message', function (message, rinfo) {
console.log('Message from: ' + rinfo.address + ':' + rinfo.port + ' - ' + message);
});
client.bind(PORT, function () {
client.addMembership(MULTICAST_ADDR); // Add the HOST_IP_ADDRESS for reliability
});
UPDATE: There are additional options for server.send (named socket.send in the docs). You can use a string for the msg instead of a Buffer, and depending on your version, several parameters are optional. You can also check whether an error has occurred in the callback function.
UPDATE: Since Node.js v6, new Buffer(str) is deprecated in favor of Buffer.from(str). The code above has been updated to reflect this change. If you are using an earlier version of Node, use the former syntax.
I never used Node.js, but I do recall that with Berkely sockets (which seem to be the most widely used implementation of sockets) you need to enable the SO_BROADCAST socket option to be able to send datagrams to the broadcast address. Looking up the dgram documentation, there seems to be a function for it.
var client = dgram.createSocket("udp4");
client.setBroadcast(true);
client.send(message, 0, message.length, 41234, "192.168.0.255");
You might want to find out the broadcast address programmatically, but I can't help you with that.
I think since node 0.10.0 some things has changed this works for me now:
//var broadcastAddress = "127.255.255.255";
var broadcastAddress = "192.168.0.255";
var message = new Buffer("Some bytes");
var client = dgram.createSocket("udp4");
client.bind();
client.on("listening", function () {
client.setBroadcast(true);
client.send(message, 0, message.length, 6623, broadcastAddress, function(err, bytes) {
client.close();
});
});
Hope this helps somebody ;)
If you want a AUTOMATIC BROADCAST ADDRESS yo can do:
const broadcastAddress = require('broadcast-address');
const os = require("os")
var PORT = 1234;
var dgram = require('dgram');
var server = dgram.createSocket("udp4");
server.bind(function() {
server.setBroadcast(true);
setInterval(broadcastNew, 5000);
});
function broadcastNew() {
var message = Buffer.from("Broadcast message!");
Object.keys(os.networkInterfaces()).forEach(it=>{
console.log(broadcastAddress(it));
server.send(message, 0, message.length, PORT, broadcastAddress(it), function() {
console.log("Sent '" + message + "'");
});
})
}
This code will get a broadcast address for each interface on you server and send a message.
;) reguards
NOTE: dont forget install broadcast-address = "npm i broadcast-address"

Categories