Truncated Output from Nodejs ssh2-exec - node.js

Can someone please help me understand why the ssh command output is getting truncated when using result[ip] = data.toString(); but not console.log(data.toString());? I only get the first 50 bytes or so for the object assignment, but console.log gets everything. The reason I'm using Promise/await is because I'm planning to eventually have this reach out to several hosts simultaneously and get the results using Promise.all before moving on.
#!/usr/local/bin/node
var fs = require('fs');
var ssh_client = require('ssh2').Client;
var ssh_config = {
port: 22,
username: 'username',
password: 'password',
readyTimeout: 5000 };
var cmd = 'find /home/username -type f -iname "*.txt"';
async function main() {
let ip = '10.10.10.110';
let result = await sshExec(ip);
console.log(result[ip]);
}
function sshExec(ip) {
return new Promise(function(resolve, reject) {
let ssh = new ssh_client();
let config = Object.assign(ssh_config, {'host': ip});
let result = {};
ssh.connect(config);
ssh.on('ready', function() {
console.log("Connected to " + ip + ".");
ssh.exec(cmd, function(err, stream) {
if (err) throw err;
stream.on('data', function(data) {
//console.log(data.toString());
result[ip] = data.toString();
}).stderr.on('data', function(data) {
console.log('STDERR: ' + data);
}).on('close', function(code, signal) {
ssh.end();
});
});
});
ssh.on('error', function(e) {
console.log(ip + ', connection failed, ' + e.message);
});
ssh.on('close', function(hadError) {
if (!hadError) {
console.log('Connection to ' + ip + ' closed without errors.');
resolve(result);
}
else {
console.log('Connection to ' + ip + ' closed with errors.');
reject(result.ip = 'failure');
}
});
});
}
main();

Related

Node.js net socket

I'm using the net module to create a listener but I've experienced some issues. I'm trying to make it wait till it's done writing the "text" to the client before the client can type again. If I'm not doing this and I hold in enter it'll just make you able to write enters between text leading to weird formatting etc.
So how could I make it wait till it's written to the client?
Code:
const net = require('net');
const server = new net.Server();
server.on('connection', async function (socket) {
console.log("Client connected!");
socket.on('data', async function (data) {
socket.setEncoding('utf8');
let input = data.toString().replace(/(\r\n|\n|\r)/gm, "");
if (input == "echo")
socket.write("$ ");
else
socket.write("invalid command");
});
});
server.listen(1337, function() {
console.log("listening");
});
Picture:
https://imgur.com/a/lc21Y13
Edit:
This is on localhost, let's say I'd host it on a server so there's a higher ping it's way worse.
Edit:
Here a picture from when it's hosted on a server:
https://imgur.com/a/LIKRRr9
Edit:
I've tried using SSH instead of telnet and raw and got basically the same result now.
Picture:
https://imgur.com/a/XJmpGSa
Code:
var fs = require('fs');
var username = null;
var ssh2 = require('ssh2');
new ssh2.Server({
hostKeys: [fs.readFileSync('ssh.key')]
}, function (client) {
console.log('Client connected!');
client.on('authentication', function (ctx) {
if (ctx.method !== 'password') return ctx.reject(['password']);
if (ctx.method === 'password') {
username = ctx.username;
console.log(username);
console.log(ctx.password);
ctx.accept();
}
else {
console.log("rejected.");
ctx.reject();
}
}).on('ready', function () {
console.log('Client authenticated!');
client.on('session', function (accept, reject) {
var session = accept();
session.once('shell', function (accept, reject, info) {
var stream = accept();
stream.write("$ ");
stream.on('data', function (data) {
var args = data.toString().split(" ");
console.log(args);
switch (args[0]) {
case "echo":
args.shift();
stream.write(args.join(" ") + "\r\n");
break;
case "whoami":
stream.write(username + "\r\n");
break;
case "exit":
stream.exit(0);
stream.end();
stream = undefined;
break;
default:
stream.stderr.write(args[0] + ": No such command!\r\n");
break;
}
if (typeof stream != 'undefined') {
stream.write("$ ");
}
});
});
});
}).on('end', function () {
console.log('Client disconnected');
});
}).listen(1337, function () {
console.log('Listening on port ' + this.address().port);
});
Try This. What this code does is simply buffering until \n enter is received from a client.
const net = require("net");
const readline = require("readline");
const execCommand = (command, args, socket) => {
return new Promise((res, rej) => {
setTimeout(() => {
// to clear the terminal
socket.write("\u001B[2J\u001B[0;0f");
socket.write(
`Executed command: ${command} with args: ${args} and result was: ${Math.random()}`
);
socket.write('\n>')
res();
}, 3000);
});
};
const server = net.createServer((socket) => {
socket.write("Connected");
// nice prompt
socket.write("\n>");
const rl = readline.createInterface({
input: socket,
output: socket,
});
rl.on("line", (line) => {
if (line.length === 0) {
socket.write("No command to execute!");
socket.write('\n>')
return;
}
// destructuring command and args
// E.g. command arg1 arg2 ....
const [command, ...args] = line.split(" ");
execCommand(command, args, socket);
});
});
server.listen(1337, "127.0.0.1");

Node does not send response after child process exits

I have the following route:
app.get('/downloadSentinel', function (req,res){
var promObj = {};
var data = req.query.data;
var Name = req.query.name;
namesArray = [];
for(var i =0;i<Name.length;i++){
namesArray.push(Name[i]);
}
promObj['Name'] = namesArray;
console.log(promObj.Name);
requestarray = [];
for (i=0; i<data.length;i++) {
requestarray.push(data[i]);
promObj['requestURLS'] = requestarray;
}
createResultFolder(promObj)
.then(downloadSentinel)
.then(resp => {
console.log("THEN:", resp);
res.send(resp);
}).catch((err) => {
console.log("CATCH:", err)
res.send(err);
})
});
The function downloadSentinel calls a Node child process and looks like this:
function downloadSentinel(promObj){
return new Promise((resolve,reject) =>{
var sys = require('util'),
exec = require('child_process').exec,
child;
var urls = parseArrayForBash(promObj.requestURLS);
var names = parseArrayForBash(promObj.Name);
console.log("executing:", './downloadProducts.sh ' + urls + ' ' + names);
child = exec('bash downloadProducts.sh '+ urls + ' ' + names, [{stdio:'inherit'}]);
child.stderr.pipe(process.stderr);
child.stdout.pipe(process.stdout);
child.on("error", function (error) {
console.log("child error:", error);
reject(promObj)
})
child.on('data', function (data) {
console.log(data.toString());
});
child.on('exit', function (exit) {
console.log("child exit:", exit);
resolve(promObj);
})
}
})
}
The output of downloadSentinel is :
child exit: 0
THEN: { Name:
[ 'S2A_MSIL1C_20180315T041541_N0206_R090_T46QEH_20180315T075531',
'S2A_MSIL1C_20180315T041541_N0206_R090_T46QEK_20180315T075531' ],
requestURLS:
[ 'bb5f4946-ce18-4b50-97ba-7ac9a94d9f1e',
'ec15c5d4-0cc6-44d4-a11f-6c2e9055f2e4' ] }
So I think that everything works as expected. But after the child process has exited with code 0, the response res.send(resp); is not sent to the client and I never get the sucess message.
What am I doing wrong?
P.S.: Sorry for the large amount of code, but I don't know what I made wrong so I provided everything.
EDIT
For the client part I am using this jQuery Ajax Request:
function downloadSentinelData(ID,Name){
var url = encodeURI('/downloadSentinel?');
$.ajax({
type: 'GET',
url: url,
timeout:5000,
dataType:'json',
data: {
data: ID,
name: Name
},
success: function(data,status){
console.log(data);
console.log(status);
alert('Products downloaded. Processing now.');
},
error: function (errorMessage) {
}
});
}
Could there be a mistake?
If you are using express.js, you should do res.end() after the res.send

How to use openvpn in nodejs?

I have NodeJS App and want to start use OpenVPN connection in it.
To do that I found 2 modules on npm (openvpn-client and openvpn-bin) - but any of them has no good docs and examples, but I try as I can to use them and it was unsuccessful.
I have Ipvanish account (login/password) with 540 .opvn files, which I can use. I try this:
var openvpnmanager = require('node-openvpn');
var openvpnBin = require('openvpn-bin');
var path = require('path');
var filePath = path.normalize('../geo/ipvanish/ipvanish-AU-Sydney-syd-a16.ovpn');
var opts = {
host: 'syd-a16.ipvanish.com', // normally '127.0.0.1', will default to if undefined
port: 443, //port openvpn management console
timeout: 60000, //timeout for connection - optional, will default to 1500ms if undefined
config: filePath
};
var auth = {
user: 'email#gmail.com',
pass: 'password'
};
var openvpn = openvpnmanager.connect(opts)
openvpn.on('connected', function() {
// will be emited on successful interfacing with openvpn instance
console.log('connected')
openvpnmanager.authorize(auth).then(function(res){
});
});
I use this, more effective way (with it I can handle OpenVPN connection as child process, close and reconnect on the fly).
var exec = require('child_process').exec;
var psTree = require('ps-tree');
var kill = function (pid, signal, callback) {
signal = signal || 'SIGKILL';
callback = callback || function () {};
var killTree = true;
if(killTree) {
psTree(pid, function (err, children) {
[pid].concat(
children.map(function (p) {
return p.PID;
})
).forEach(function (tpid) {
try { process.kill(tpid, signal) }
catch (ex) { }
});
callback();
});
} else {
try { process.kill(pid, signal) }
catch (ex) { }
callback();
}
};
var ovpnProcess = null;
if(ovpnProcess != null){
console.log('close connection');
var isWin = /^win/.test(ovpnProcess.platform);
if(!isWin) {
kill(ovpnProcess.pid);
} else {
var cp = require('child_process');
cp.exec('taskkill /PID ' + ovpnProcess.pid + ' /T /F', function (error, stdout, stderr) {
// more debug if you need
// console.log('stdout: ' + stdout);
// console.log('stderr: ' + stderr);
// if(error !== null) {
// console.log('exec error: ' + error);
// }
});
}
}
// to open connection I use this code:
ovpnProcess = exec('openvpn ipvanish/'+account.ip+'.ovpn');
ovpnProcess.stdout.on('data', function(data) {
console.log('stdout: ' + data);
});
ovpnProcess.stderr.on('data', function(data) {
console.log('stdout: ' + data);
});
ovpnProcess.on('close', function(code) {
console.log('closing code: ' + code);
});
you can get help from https://www.npmjs.com/package/node-openvpn or OpenVPN with node, How it works?.

Nodejs - data transfer between server and client

I was given a task to send JSON string from client to server and from server to client, whenever there is a new record found to send.
I decided to build TCP connection(suggest me if there is any other better way in Node.js) between server and client to transfer data.
The problem is, I was supposed to use a delimiter to separate JSON strings one from another. I am afraid what if the json string contains the delimiter string inside the object. I am looking for a better way to separate two JSON strings.
Below is my code. Please help me.
Client
var net = require('net')
, client = new net.Socket();
var chunk = ''
, dlim_index = -1
, delimit = '~~';
client.connect(config.Port, config.IpAddress, function () {
console.log('Server Connected');
client.write('CLIENTID:' + process.argv[2]);
client.write(delimit);
});
client.on('data', function (data) {
var recvData = data.toString().trim();
chunk += recvData;
dlim_index = chunk.indexOf(recvData);
console.log(data);
while (dlim_index > -1) {
var useData = chunk.substring(0, dlim_index);
if (useData == 'SUCCESS') {
controller.listenOutQueue(function (dataToSend) {
var object = JSON.parse(dataToSend);
client.write(dataToSend);
client.write(delimit);
});
}
else {
var record = JSON.parse(useData);
controller.insertIntoQueue(record, function (status) {
});
}
chunk = chunk.substring(dlim_index + 2);
dlim_index = chunk.indexOf(delimit);
}
});
client.on('close', function () {
console.log('Connection closed');
});
client.setTimeout(50000, function () {
//client.destroy();
});
Server
var net = require('net')
, server = net.createServer()
, delimit = '~~'
, clients = [];
controller.listenOutQueue(function (dataToSend) {
client.write(dataToSend);
client.write(delimit);
});
server.on('connection', function (socket) {
var chunk = '';
var dlim_index = -1;
socket.on('data', function (data) {
var recvData = data.toString().trim();
chunk += recvData;
dlim_index = chunk.indexOf(delimit);
while (dlim_index > -1) {
var useData = chunk.substring(0, dlim_index);
if (useData.substring(0, 9) == 'CLIENTID:') {
socket.clientid = useData.replace('CLIENTID:', '');
console.log('Client Id: ' + socket.clientid);
clients.push(socket);
var successMessage = "SUCCESS";
socket.write(successMessage);
socket.write(delimit);
}
else {
controller.insertIntoQueue(JSON.parse(useData), function (status) {
});
}
chunk = chunk.substring(dlim_index + 2);
dlim_index = chunk.indexOf(delimit);
}
});
socket.on('end', function () {
console.log('Connection Closed (' + socket.clientid + ')');
});
socket.on('error', function (err) {
console.log('SOCKET ERROR:', err);
});
});
server.listen(config.Port, config.IpAddress);

NodeJS: Out of memory when sending messages to child_processes

My goal is to create a parent process that streams messages to the child processes indefinitely. To test this, i tried the below code for 150M messages to a child process that does nothing.
(Possible Answer Edited Below) Why would this code run out of memory?
I am using the ofe module but I do not know what to look for in the resulting heapdump, what method could I have used to search the heapdump for clues?
code:
server.js
// After 20M messages i get:
// FATAL ERROR: CALL_AND_RETRY_2 Allocation failed - process out of memory
var cp = require('child_process');
var xrange = require('xrange');
var maxChildren = require('os').cpus().length;
var util = require('util');
require('ofe').call();
var childError = function(err) {
console.log('Error: ' + err);
};
var childExit = function(code, signal) {
console.log('Exit Code: ' + code);
console.log('Exit Signal: ' + signal);
};
var childClose = function(code, signal) {
console.log('Close Code: ' + code);
console.log('Close Signal: ' + signal);
};
var childDisconnect = function() {
console.log('Disconnect');
};
var childMessage = function(msg, handle) {
console.log('Msg: ' + msg);
};
var createChild = function(){
var child = cp.fork("./child");
child.on('error', childError);
child.on('exit', childExit);
child.on('close', childClose);
child.on('disconnect', childDisconnect);
child.on('message', childMessage);
console.log("Child Created: " + child.pid);
return child;
}
var createChildren = function(){
var children = [];
xrange(maxChildren).each(function(i) {
children[i] = createChild();
});
return children;
}
var sendMessages = function(children) {
xrange(150000000).each(function(num) {
var idx = num % maxChildren;
if (num % 1000000 == 0) {
console.log(num);
}
children[idx].send(num);
});
};
child.js (contents)
process.on('message', function(msg) {});
Answer
Since this code is asynchronous , the parent process will send all the messages to the children without waiting for them to be processed, which seems to overload the clients. I believe the solution is to send a message back from the clients to 'pull' the next number after processing. Assuming this is the answer, I have a follow up question.
1) I'd like to write this but i'm not sure how to turn the xrange into a generator without the ability to yield (no-harmony nodejs), is there a callback solution? :
function getNextNumber(){
//pull the next available number from the 150M
}
child.on('message',function(msg) {
child.send(getNextNumber());
});
Followup
If I just wanted to iterate, this seems to be the way: https://stackoverflow.com/a/5784473/1578888 .
If I am reading this alternate answer correctly, it seems that implementing the xrange call as a true generator is not possible pre-harmony: https://stackoverflow.com/a/7442013/1578888
This is the code i ended up using (also renamed server.js to parent.js):
parent.js
var cp = require('child_process');
var xrange = require('xrange');
var maxChildren = require('os').cpus().length;
var util = require('util');
require('ofe').call();
var childError = function(err) {
console.log('Error: ' + err);
};
var childExit = function(code, signal) {
console.log('Exit Code: ' + code);
console.log('Exit Signal: ' + signal);
};
var childClose = function(code, signal) {
console.log('Close Code: ' + code);
console.log('Close Signal: ' + signal);
};
var childDisconnect = function() {
console.log('Disconnect');
};
var childMessage = function(msg, handle) {
//no output anymore!
//console.log('Msg: ' + msg);
};
var createChild = function(){
var child = cp.fork("./child.js");
child.on('error', childError);
child.on('exit', childExit);
child.on('close', childClose);
child.on('disconnect', childDisconnect);
child.on('message', childMessage);
console.log("Child Created: " + child.pid);
return child;
}
var getNextFn = (function () {
var i = 0
return function(cb) {
i = i + 1;
if (i < 150000000) {
return i;
} else {
return null;
}
}
})();
var createChildren = function(){
var children = [];
xrange(maxChildren).each(function(i) {
var child = createChild();
child.on('message', function(msg) {
var next = getNextFn();
if (next) {
if (next % 1000000 == 0) {
console.log(next + " " + new Date().toISOString());
}
child.send(next);
} else {
child.kill();
}
});
children[i] = child;
});
return children;
}
var c = createChildren();
child.js
process.on('message', function(msg) {
process.send({});
});
process.send({});

Resources